This closes #820
This commit is contained in:
commit
67f804054d
|
@ -21,7 +21,6 @@ import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException;
|
import org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException;
|
||||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
|
@ -37,6 +36,7 @@ import org.apache.activemq.artemis.core.server.ServerSession;
|
||||||
import org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl;
|
import org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl;
|
||||||
import org.apache.activemq.artemis.core.transaction.Transaction;
|
import org.apache.activemq.artemis.core.transaction.Transaction;
|
||||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnection;
|
import org.apache.activemq.artemis.jms.client.ActiveMQConnection;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.ProtonMessageConverter;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.EncodedMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.EncodedMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPException;
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPException;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPInternalErrorException;
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPInternalErrorException;
|
||||||
|
@ -59,9 +59,10 @@ import org.apache.qpid.proton.amqp.messaging.Accepted;
|
||||||
import org.apache.qpid.proton.amqp.messaging.Rejected;
|
import org.apache.qpid.proton.amqp.messaging.Rejected;
|
||||||
import org.apache.qpid.proton.amqp.transport.AmqpError;
|
import org.apache.qpid.proton.amqp.transport.AmqpError;
|
||||||
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
|
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
|
||||||
|
import org.apache.qpid.proton.codec.WritableBuffer;
|
||||||
import org.apache.qpid.proton.engine.Delivery;
|
import org.apache.qpid.proton.engine.Delivery;
|
||||||
import org.apache.qpid.proton.engine.Receiver;
|
import org.apache.qpid.proton.engine.Receiver;
|
||||||
import org.apache.qpid.proton.message.ProtonJMessage;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
public class AMQPSessionCallback implements SessionCallback {
|
public class AMQPSessionCallback implements SessionCallback {
|
||||||
|
@ -259,8 +260,11 @@ public class AMQPSessionCallback implements SessionCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtonJMessage encodeMessage(Object message, int deliveryCount) throws Exception {
|
public long encodeMessage(Object message, int deliveryCount, WritableBuffer buffer) throws Exception {
|
||||||
return (ProtonJMessage) manager.getConverter().outbound((ServerMessage) message, deliveryCount);
|
ProtonMessageConverter converter = (ProtonMessageConverter) manager.getConverter();
|
||||||
|
|
||||||
|
// The Proton variant accepts a WritableBuffer to allow for a faster more direct encode.
|
||||||
|
return (long) converter.outbound((ServerMessage) message, deliveryCount, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String tempQueueName() {
|
public String tempQueueName() {
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter;
|
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
|
||||||
import javax.jms.Destination;
|
|
||||||
import javax.jms.JMSException;
|
|
||||||
import javax.jms.MapMessage;
|
|
||||||
import javax.jms.Message;
|
|
||||||
import javax.jms.ObjectMessage;
|
|
||||||
import javax.jms.StreamMessage;
|
|
||||||
import javax.jms.TextMessage;
|
|
||||||
|
|
||||||
import org.apache.activemq.artemis.core.buffers.impl.ResetLimitWrappedActiveMQBuffer;
|
|
||||||
import org.apache.activemq.artemis.core.server.ServerMessage;
|
|
||||||
import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl;
|
|
||||||
import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerDestination;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMapMessage;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSObjectMessage;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSTextMessage;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.JMSVendor;
|
|
||||||
import org.apache.activemq.artemis.utils.IDGenerator;
|
|
||||||
|
|
||||||
public class ActiveMQJMSVendor implements JMSVendor {
|
|
||||||
|
|
||||||
private final IDGenerator serverGenerator;
|
|
||||||
|
|
||||||
ActiveMQJMSVendor(IDGenerator idGenerator) {
|
|
||||||
this.serverGenerator = idGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BytesMessage createBytesMessage() {
|
|
||||||
return new ServerJMSBytesMessage(newMessage(org.apache.activemq.artemis.api.core.Message.BYTES_TYPE), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StreamMessage createStreamMessage() {
|
|
||||||
return new ServerJMSStreamMessage(newMessage(org.apache.activemq.artemis.api.core.Message.STREAM_TYPE), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message createMessage() {
|
|
||||||
return new ServerJMSMessage(newMessage(org.apache.activemq.artemis.api.core.Message.DEFAULT_TYPE), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TextMessage createTextMessage() {
|
|
||||||
return new ServerJMSTextMessage(newMessage(org.apache.activemq.artemis.api.core.Message.TEXT_TYPE), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectMessage createObjectMessage() {
|
|
||||||
return new ServerJMSObjectMessage(newMessage(org.apache.activemq.artemis.api.core.Message.OBJECT_TYPE), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MapMessage createMapMessage() {
|
|
||||||
return new ServerJMSMapMessage(newMessage(org.apache.activemq.artemis.api.core.Message.MAP_TYPE), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setJMSXUserID(Message message, String s) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Destination createDestination(String name) {
|
|
||||||
return new ServerDestination(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setJMSXGroupID(Message message, String s) {
|
|
||||||
try {
|
|
||||||
message.setStringProperty("_AMQ_GROUP_ID", s);
|
|
||||||
} catch (JMSException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setJMSXGroupSequence(Message message, int i) {
|
|
||||||
try {
|
|
||||||
message.setIntProperty("JMSXGroupSeq", i);
|
|
||||||
} catch (JMSException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setJMSXDeliveryCount(Message message, long l) {
|
|
||||||
try {
|
|
||||||
message.setLongProperty("JMSXDeliveryCount", l);
|
|
||||||
} catch (JMSException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerJMSMessage wrapMessage(int messageType, ServerMessage wrapped, int deliveryCount) {
|
|
||||||
switch (messageType) {
|
|
||||||
case org.apache.activemq.artemis.api.core.Message.STREAM_TYPE:
|
|
||||||
return new ServerJMSStreamMessage(wrapped, deliveryCount);
|
|
||||||
case org.apache.activemq.artemis.api.core.Message.BYTES_TYPE:
|
|
||||||
return new ServerJMSBytesMessage(wrapped, deliveryCount);
|
|
||||||
case org.apache.activemq.artemis.api.core.Message.MAP_TYPE:
|
|
||||||
return new ServerJMSMapMessage(wrapped, deliveryCount);
|
|
||||||
case org.apache.activemq.artemis.api.core.Message.TEXT_TYPE:
|
|
||||||
return new ServerJMSTextMessage(wrapped, deliveryCount);
|
|
||||||
case org.apache.activemq.artemis.api.core.Message.OBJECT_TYPE:
|
|
||||||
return new ServerJMSObjectMessage(wrapped, deliveryCount);
|
|
||||||
default:
|
|
||||||
return new ServerJMSMessage(wrapped, deliveryCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toAddress(Destination destination) {
|
|
||||||
if (destination instanceof ActiveMQDestination) {
|
|
||||||
return ((ActiveMQDestination) destination).getAddress();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ServerMessageImpl newMessage(byte messageType) {
|
|
||||||
ServerMessageImpl message = new ServerMessageImpl(serverGenerator.generateID(), 512);
|
|
||||||
message.setType(messageType);
|
|
||||||
((ResetLimitWrappedActiveMQBuffer) message.getBodyBuffer()).setMessage(null);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,91 +16,86 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter;
|
package org.apache.activemq.artemis.protocol.amqp.converter;
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_NATIVE;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.jms.BytesMessage;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
||||||
import org.apache.activemq.artemis.core.server.ServerMessage;
|
import org.apache.activemq.artemis.core.server.ServerMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPNativeOutboundTransformer;
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPNativeOutboundTransformer;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.EncodedMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.EncodedMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.InboundTransformer;
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.InboundTransformer;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.JMSMappingInboundTransformer;
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.JMSMappingInboundTransformer;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.JMSMappingOutboundTransformer;
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.JMSMappingOutboundTransformer;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.OutboundTransformer;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.util.NettyWritable;
|
||||||
import org.apache.activemq.artemis.spi.core.protocol.MessageConverter;
|
import org.apache.activemq.artemis.spi.core.protocol.MessageConverter;
|
||||||
import org.apache.activemq.artemis.utils.IDGenerator;
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
import org.apache.qpid.proton.codec.WritableBuffer;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
public class ProtonMessageConverter implements MessageConverter {
|
public class ProtonMessageConverter implements MessageConverter {
|
||||||
|
|
||||||
ActiveMQJMSVendor activeMQJMSVendor;
|
|
||||||
|
|
||||||
private final String prefixVendor;
|
|
||||||
|
|
||||||
public ProtonMessageConverter(IDGenerator idGenerator) {
|
public ProtonMessageConverter(IDGenerator idGenerator) {
|
||||||
activeMQJMSVendor = new ActiveMQJMSVendor(idGenerator);
|
inboundTransformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
inboundTransformer = new JMSMappingInboundTransformer(activeMQJMSVendor);
|
outboundTransformer = new JMSMappingOutboundTransformer(idGenerator);
|
||||||
outboundTransformer = new JMSMappingOutboundTransformer(activeMQJMSVendor);
|
|
||||||
prefixVendor = outboundTransformer.getPrefixVendor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final InboundTransformer inboundTransformer;
|
private final InboundTransformer inboundTransformer;
|
||||||
private final JMSMappingOutboundTransformer outboundTransformer;
|
private final OutboundTransformer outboundTransformer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerMessage inbound(Object messageSource) throws Exception {
|
public ServerMessage inbound(Object messageSource) throws Exception {
|
||||||
ServerJMSMessage jmsMessage = inboundJMSType((EncodedMessage) messageSource);
|
EncodedMessage encodedMessageSource = (EncodedMessage) messageSource;
|
||||||
|
|
||||||
return (ServerMessage) jmsMessage.getInnerMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just create the JMS Part of the inbound (for testing)
|
|
||||||
*
|
|
||||||
* @param messageSource
|
|
||||||
* @return
|
|
||||||
* @throws Exception https://issues.jboss.org/browse/ENTMQ-1560
|
|
||||||
*/
|
|
||||||
public ServerJMSMessage inboundJMSType(EncodedMessage messageSource) throws Exception {
|
|
||||||
EncodedMessage encodedMessageSource = messageSource;
|
|
||||||
ServerJMSMessage transformedMessage = null;
|
ServerJMSMessage transformedMessage = null;
|
||||||
|
|
||||||
InboundTransformer transformer = inboundTransformer;
|
try {
|
||||||
|
transformedMessage = inboundTransformer.transform(encodedMessageSource);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActiveMQClientLogger.LOGGER.debug("Transform of message using [{}] transformer, failed" + inboundTransformer.getTransformerName());
|
||||||
|
ActiveMQClientLogger.LOGGER.trace("Transformation error:", e);
|
||||||
|
|
||||||
while (transformer != null) {
|
|
||||||
try {
|
|
||||||
transformedMessage = (ServerJMSMessage) transformer.transform(encodedMessageSource);
|
|
||||||
break;
|
|
||||||
} catch (Exception e) {
|
|
||||||
ActiveMQClientLogger.LOGGER.debug("Transform of message using [{}] transformer, failed" + inboundTransformer.getTransformerName());
|
|
||||||
ActiveMQClientLogger.LOGGER.trace("Transformation error:", e);
|
|
||||||
|
|
||||||
transformer = transformer.getFallbackTransformer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transformedMessage == null) {
|
|
||||||
throw new IOException("Failed to transform incoming delivery, skipping.");
|
throw new IOException("Failed to transform incoming delivery, skipping.");
|
||||||
}
|
}
|
||||||
|
|
||||||
transformedMessage.encode();
|
transformedMessage.encode();
|
||||||
|
|
||||||
return transformedMessage;
|
return (ServerMessage) transformedMessage.getInnerMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object outbound(ServerMessage messageOutbound, int deliveryCount) throws Exception {
|
public Object outbound(ServerMessage messageOutbound, int deliveryCount) throws Exception {
|
||||||
ServerJMSMessage jmsMessage = activeMQJMSVendor.wrapMessage(messageOutbound.getType(), messageOutbound, deliveryCount);
|
// Useful for testing but not recommended for real life use.
|
||||||
|
ByteBuf nettyBuffer = Unpooled.buffer(1024);
|
||||||
|
NettyWritable buffer = new NettyWritable(nettyBuffer);
|
||||||
|
long messageFormat = (long) outbound(messageOutbound, deliveryCount, buffer);
|
||||||
|
|
||||||
|
EncodedMessage encoded = new EncodedMessage(messageFormat, nettyBuffer.array(), nettyBuffer.arrayOffset() + nettyBuffer.readerIndex(),
|
||||||
|
nettyBuffer.readableBytes());
|
||||||
|
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object outbound(ServerMessage messageOutbound, int deliveryCount, WritableBuffer buffer) throws Exception {
|
||||||
|
ServerJMSMessage jmsMessage = AMQPMessageSupport.wrapMessage(messageOutbound.getType(), messageOutbound, deliveryCount);
|
||||||
|
|
||||||
jmsMessage.decode();
|
jmsMessage.decode();
|
||||||
|
|
||||||
if (jmsMessage.getBooleanProperty(prefixVendor + "NATIVE")) {
|
if (jmsMessage.getBooleanProperty(JMS_AMQP_NATIVE)) {
|
||||||
if (jmsMessage instanceof BytesMessage) {
|
if (jmsMessage instanceof BytesMessage) {
|
||||||
return AMQPNativeOutboundTransformer.transform(outboundTransformer, (BytesMessage) jmsMessage);
|
return AMQPNativeOutboundTransformer.transform(outboundTransformer, (ServerJMSBytesMessage) jmsMessage, buffer);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return outboundTransformer.convert(jmsMessage);
|
return outboundTransformer.transform(jmsMessage, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.jms;
|
package org.apache.activemq.artemis.protocol.amqp.converter.jms;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import javax.jms.DeliveryMode;
|
import javax.jms.DeliveryMode;
|
||||||
import javax.jms.Destination;
|
import javax.jms.Destination;
|
||||||
import javax.jms.JMSException;
|
import javax.jms.JMSException;
|
||||||
import javax.jms.Message;
|
import javax.jms.Message;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||||
|
@ -47,6 +48,10 @@ public class ServerJMSMessage implements Message {
|
||||||
this.deliveryCount = deliveryCount;
|
this.deliveryCount = deliveryCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDeliveryCount() {
|
||||||
|
return deliveryCount;
|
||||||
|
}
|
||||||
|
|
||||||
private ActiveMQBuffer readBodyBuffer;
|
private ActiveMQBuffer readBodyBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,31 +16,20 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.jms;
|
package org.apache.activemq.artemis.protocol.amqp.converter.jms;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import javax.jms.JMSException;
|
import javax.jms.JMSException;
|
||||||
import javax.jms.ObjectMessage;
|
import javax.jms.ObjectMessage;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import org.apache.activemq.artemis.api.core.Message;
|
import org.apache.activemq.artemis.api.core.Message;
|
||||||
import org.apache.activemq.artemis.core.message.impl.MessageInternal;
|
import org.apache.activemq.artemis.core.message.impl.MessageInternal;
|
||||||
import org.apache.activemq.artemis.utils.ObjectInputStreamWithClassLoader;
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
|
|
||||||
public class ServerJMSObjectMessage extends ServerJMSMessage implements ObjectMessage {
|
public class ServerJMSObjectMessage extends ServerJMSMessage implements ObjectMessage {
|
||||||
|
|
||||||
private static final String DEFAULT_WHITELIST;
|
public static final byte TYPE = Message.OBJECT_TYPE;
|
||||||
private static final String DEFAULT_BLACKLIST;
|
|
||||||
|
|
||||||
static {
|
private Binary payload;
|
||||||
DEFAULT_WHITELIST = System.getProperty(ObjectInputStreamWithClassLoader.WHITELIST_PROPERTY, "java.lang,java.math,javax.security,java.util,org.apache.activemq,org.apache.qpid.proton.amqp");
|
|
||||||
|
|
||||||
DEFAULT_BLACKLIST = System.getProperty(ObjectInputStreamWithClassLoader.BLACKLIST_PROPERTY, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final byte TYPE = Message.STREAM_TYPE;
|
|
||||||
|
|
||||||
private Serializable object;
|
|
||||||
|
|
||||||
public ServerJMSObjectMessage(MessageInternal message, int deliveryCount) {
|
public ServerJMSObjectMessage(MessageInternal message, int deliveryCount) {
|
||||||
super(message, deliveryCount);
|
super(message, deliveryCount);
|
||||||
|
@ -48,23 +37,27 @@ public class ServerJMSObjectMessage extends ServerJMSMessage implements ObjectMe
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setObject(Serializable object) throws JMSException {
|
public void setObject(Serializable object) throws JMSException {
|
||||||
this.object = object;
|
throw new UnsupportedOperationException("Cannot set Object on this internal message");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable getObject() throws JMSException {
|
public Serializable getObject() throws JMSException {
|
||||||
return object;
|
throw new UnsupportedOperationException("Cannot set Object on this internal message");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSerializedForm(Binary payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Binary getSerializedForm() {
|
||||||
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encode() throws Exception {
|
public void encode() throws Exception {
|
||||||
super.encode();
|
super.encode();
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
getInnerMessage().getBodyBuffer().writeInt(payload.getLength());
|
||||||
ObjectOutputStream ous = new ObjectOutputStream(out);
|
getInnerMessage().getBodyBuffer().writeBytes(payload.getArray(), payload.getArrayOffset(), payload.getLength());
|
||||||
ous.writeObject(object);
|
|
||||||
byte[] src = out.toByteArray();
|
|
||||||
getInnerMessage().getBodyBuffer().writeInt(src.length);
|
|
||||||
getInnerMessage().getBodyBuffer().writeBytes(src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,10 +66,6 @@ public class ServerJMSObjectMessage extends ServerJMSMessage implements ObjectMe
|
||||||
int size = getInnerMessage().getBodyBuffer().readInt();
|
int size = getInnerMessage().getBodyBuffer().readInt();
|
||||||
byte[] bytes = new byte[size];
|
byte[] bytes = new byte[size];
|
||||||
getInnerMessage().getBodyBuffer().readBytes(bytes);
|
getInnerMessage().getBodyBuffer().readBytes(bytes);
|
||||||
try (ObjectInputStreamWithClassLoader ois = new ObjectInputStreamWithClassLoader(new ByteArrayInputStream(bytes))) {
|
payload = new Binary(bytes);
|
||||||
ois.setWhiteList(DEFAULT_WHITELIST);
|
|
||||||
ois.setBlackList(DEFAULT_BLACKLIST);
|
|
||||||
object = (Serializable) ois.readObject();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.IllegalCharsetNameException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.charset.UnsupportedCharsetException;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPInvalidContentTypeException;
|
||||||
|
|
||||||
|
public final class AMQPContentTypeSupport {
|
||||||
|
|
||||||
|
private static final String UTF_8 = "UTF-8";
|
||||||
|
private static final String CHARSET = "charset";
|
||||||
|
private static final String TEXT = "text";
|
||||||
|
private static final String APPLICATION = "application";
|
||||||
|
private static final String JAVASCRIPT = "javascript";
|
||||||
|
private static final String XML = "xml";
|
||||||
|
private static final String XML_VARIANT = "+xml";
|
||||||
|
private static final String JSON = "json";
|
||||||
|
private static final String JSON_VARIANT = "+json";
|
||||||
|
private static final String XML_DTD = "xml-dtd";
|
||||||
|
private static final String ECMASCRIPT = "ecmascript";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param contentType
|
||||||
|
* the contentType of the received message
|
||||||
|
* @return the character set to use, or null if not to treat the message as text
|
||||||
|
* @throws ActiveMQAMQPInvalidContentTypeException
|
||||||
|
* if the content-type is invalid in some way.
|
||||||
|
*/
|
||||||
|
public static Charset parseContentTypeForTextualCharset(final String contentType) throws ActiveMQAMQPInvalidContentTypeException {
|
||||||
|
if (contentType == null || contentType.trim().isEmpty()) {
|
||||||
|
throw new ActiveMQAMQPInvalidContentTypeException("Content type can't be null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
int subTypeSeparator = contentType.indexOf("/");
|
||||||
|
if (subTypeSeparator == -1) {
|
||||||
|
throw new ActiveMQAMQPInvalidContentTypeException("Content type has no '/' separator: " + contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String type = contentType.substring(0, subTypeSeparator).toLowerCase().trim();
|
||||||
|
|
||||||
|
String subTypePart = contentType.substring(subTypeSeparator + 1).toLowerCase().trim();
|
||||||
|
|
||||||
|
String parameterPart = null;
|
||||||
|
int parameterSeparator = subTypePart.indexOf(";");
|
||||||
|
if (parameterSeparator != -1) {
|
||||||
|
if (parameterSeparator < subTypePart.length() - 1) {
|
||||||
|
parameterPart = contentType.substring(subTypeSeparator + 1).toLowerCase().trim();
|
||||||
|
}
|
||||||
|
subTypePart = subTypePart.substring(0, parameterSeparator).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subTypePart.isEmpty()) {
|
||||||
|
throw new ActiveMQAMQPInvalidContentTypeException("Content type has no subtype after '/'" + contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String subType = subTypePart;
|
||||||
|
|
||||||
|
if (isTextual(type, subType)) {
|
||||||
|
String charset = findCharset(parameterPart);
|
||||||
|
if (charset == null) {
|
||||||
|
charset = UTF_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UTF_8.equals(charset)) {
|
||||||
|
return StandardCharsets.UTF_8;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return Charset.forName(charset);
|
||||||
|
} catch (IllegalCharsetNameException icne) {
|
||||||
|
throw new ActiveMQAMQPInvalidContentTypeException("Illegal charset: " + charset);
|
||||||
|
} catch (UnsupportedCharsetException uce) {
|
||||||
|
throw new ActiveMQAMQPInvalidContentTypeException("Unsupported charset: " + charset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Internal Content Type utilities ----------------------------------//
|
||||||
|
|
||||||
|
private static boolean isTextual(String type, String subType) {
|
||||||
|
if (TEXT.equals(type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (APPLICATION.equals(type)) {
|
||||||
|
if (XML.equals(subType) || JSON.equals(subType) || JAVASCRIPT.equals(subType) || subType.endsWith(XML_VARIANT) || subType.endsWith(JSON_VARIANT)
|
||||||
|
|| XML_DTD.equals(subType) || ECMASCRIPT.equals(subType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String findCharset(String paramaterPart) {
|
||||||
|
String charset = null;
|
||||||
|
|
||||||
|
if (paramaterPart != null) {
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(paramaterPart, ";");
|
||||||
|
while (tokenizer.hasMoreTokens()) {
|
||||||
|
String parameter = tokenizer.nextToken().trim();
|
||||||
|
int eqIndex = parameter.indexOf('=');
|
||||||
|
if (eqIndex != -1) {
|
||||||
|
String name = parameter.substring(0, eqIndex);
|
||||||
|
if (CHARSET.equalsIgnoreCase(name.trim())) {
|
||||||
|
String value = unquote(parameter.substring(eqIndex + 1));
|
||||||
|
|
||||||
|
charset = value.toUpperCase();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String unquote(String s) {
|
||||||
|
if (s.length() > 1 && (s.startsWith("\"") && s.endsWith("\""))) {
|
||||||
|
return s.substring(1, s.length() - 1);
|
||||||
|
} else {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,24 +28,29 @@ import org.apache.qpid.proton.amqp.Binary;
|
||||||
import org.apache.qpid.proton.amqp.UnsignedLong;
|
import org.apache.qpid.proton.amqp.UnsignedLong;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for identifying and converting message-id and correlation-id values between
|
* Helper class for identifying and converting message-id and correlation-id values between the
|
||||||
* the AMQP types and the Strings values used by JMS.
|
* AMQP types and the Strings values used by JMS.
|
||||||
* <p>
|
* <p>
|
||||||
* <p>AMQP messages allow for 4 types of message-id/correlation-id: message-id-string, message-id-binary,
|
* <p>
|
||||||
* message-id-uuid, or message-id-ulong. In order to accept or return a string representation of these
|
* AMQP messages allow for 4 types of message-id/correlation-id: message-id-string,
|
||||||
* for interoperability with other AMQP clients, the following encoding can be used after removing or
|
* message-id-binary, message-id-uuid, or message-id-ulong. In order to accept or return a
|
||||||
* before adding the "ID:" prefix used for a JMSMessageID value:<br>
|
* string representation of these for interoperability with other AMQP clients, the following
|
||||||
|
* encoding can be used after removing or before adding the "ID:" prefix used for a JMSMessageID
|
||||||
|
* value:<br>
|
||||||
* <p>
|
* <p>
|
||||||
* {@literal "AMQP_BINARY:<hex representation of binary content>"}<br>
|
* {@literal "AMQP_BINARY:<hex representation of binary content>"}<br>
|
||||||
* {@literal "AMQP_UUID:<string representation of uuid>"}<br>
|
* {@literal "AMQP_UUID:<string representation of uuid>"}<br>
|
||||||
* {@literal "AMQP_ULONG:<string representation of ulong>"}<br>
|
* {@literal "AMQP_ULONG:<string representation of ulong>"}<br>
|
||||||
* {@literal "AMQP_STRING:<string>"}<br>
|
* {@literal "AMQP_STRING:<string>"}<br>
|
||||||
* <p>
|
* <p>
|
||||||
* <p>The AMQP_STRING encoding exists only for escaping message-id-string values that happen to begin
|
|
||||||
* with one of the encoding prefixes (including AMQP_STRING itself). It MUST NOT be used otherwise.
|
|
||||||
* <p>
|
* <p>
|
||||||
* <p>When provided a string for conversion which attempts to identify itself as an encoded binary, uuid, or
|
* The AMQP_STRING encoding exists only for escaping message-id-string values that happen to
|
||||||
* ulong but can't be converted into the indicated format, an exception will be thrown.
|
* begin with one of the encoding prefixes (including AMQP_STRING itself). It MUST NOT be used
|
||||||
|
* otherwise.
|
||||||
|
* <p>
|
||||||
|
* <p>
|
||||||
|
* When provided a string for conversion which attempts to identify itself as an encoded binary,
|
||||||
|
* uuid, or ulong but can't be converted into the indicated format, an exception will be thrown.
|
||||||
*/
|
*/
|
||||||
public class AMQPMessageIdHelper {
|
public class AMQPMessageIdHelper {
|
||||||
|
|
||||||
|
@ -63,11 +68,12 @@ public class AMQPMessageIdHelper {
|
||||||
private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
|
private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the provided AMQP messageId style object, and convert it to a base string.
|
* Takes the provided AMQP messageId style object, and convert it to a base string. Encodes
|
||||||
* Encodes type information as a prefix where necessary to convey or escape the type
|
* type information as a prefix where necessary to convey or escape the type of the provided
|
||||||
* of the provided object.
|
* object.
|
||||||
*
|
*
|
||||||
* @param messageId the raw messageId object to process
|
* @param messageId
|
||||||
|
* the raw messageId object to process
|
||||||
* @return the base string to be used in creating the actual id.
|
* @return the base string to be used in creating the actual id.
|
||||||
*/
|
*/
|
||||||
public String toBaseMessageIdString(Object messageId) {
|
public String toBaseMessageIdString(Object messageId) {
|
||||||
|
@ -106,9 +112,12 @@ public class AMQPMessageIdHelper {
|
||||||
* Takes the provided base id string and return the appropriate amqp messageId style object.
|
* Takes the provided base id string and return the appropriate amqp messageId style object.
|
||||||
* Converts the type based on any relevant encoding information found as a prefix.
|
* Converts the type based on any relevant encoding information found as a prefix.
|
||||||
*
|
*
|
||||||
* @param baseId the object to be converted to an AMQP MessageId value.
|
* @param baseId
|
||||||
|
* the object to be converted to an AMQP MessageId value.
|
||||||
* @return the AMQP messageId style object
|
* @return the AMQP messageId style object
|
||||||
* @throws ActiveMQAMQPIllegalStateException if the provided baseId String indicates an encoded type but can't be converted to that type.
|
* @throws ActiveMQAMQPIllegalStateException
|
||||||
|
* if the provided baseId String indicates an encoded type but can't be converted to
|
||||||
|
* that type.
|
||||||
*/
|
*/
|
||||||
public Object toIdObject(String baseId) throws ActiveMQAMQPIllegalStateException {
|
public Object toIdObject(String baseId) throws ActiveMQAMQPIllegalStateException {
|
||||||
if (baseId == null) {
|
if (baseId == null) {
|
||||||
|
@ -143,15 +152,17 @@ public class AMQPMessageIdHelper {
|
||||||
* <p>
|
* <p>
|
||||||
* The hex characters may be upper or lower case.
|
* The hex characters may be upper or lower case.
|
||||||
*
|
*
|
||||||
* @param hexString string to convert to a binary value.
|
* @param hexString
|
||||||
|
* string to convert to a binary value.
|
||||||
* @return a byte array containing the binary representation
|
* @return a byte array containing the binary representation
|
||||||
* @throws IllegalArgumentException if the provided String is a non-even length or contains
|
* @throws IllegalArgumentException
|
||||||
* non-hex characters
|
* if the provided String is a non-even length or contains non-hex characters
|
||||||
*/
|
*/
|
||||||
public byte[] convertHexStringToBinary(String hexString) throws IllegalArgumentException {
|
public byte[] convertHexStringToBinary(String hexString) throws IllegalArgumentException {
|
||||||
int length = hexString.length();
|
int length = hexString.length();
|
||||||
|
|
||||||
// As each byte needs two characters in the hex encoding, the string must be an even length.
|
// As each byte needs two characters in the hex encoding, the string must be an even
|
||||||
|
// length.
|
||||||
if (length % 2 != 0) {
|
if (length % 2 != 0) {
|
||||||
throw new IllegalArgumentException("The provided hex String must be an even length, but was of length " + length + ": " + hexString);
|
throw new IllegalArgumentException("The provided hex String must be an even length, but was of length " + length + ": " + hexString);
|
||||||
}
|
}
|
||||||
|
@ -177,7 +188,8 @@ public class AMQPMessageIdHelper {
|
||||||
* <p>
|
* <p>
|
||||||
* The returned hex characters are upper-case.
|
* The returned hex characters are upper-case.
|
||||||
*
|
*
|
||||||
* @param bytes the binary value to convert to a hex String instance.
|
* @param bytes
|
||||||
|
* the binary value to convert to a hex String instance.
|
||||||
* @return a String containing a hex representation of the bytes
|
* @return a String containing a hex representation of the bytes
|
||||||
*/
|
*/
|
||||||
public String convertBinaryToHexString(byte[] bytes) {
|
public String convertBinaryToHexString(byte[] bytes) {
|
||||||
|
@ -198,11 +210,10 @@ public class AMQPMessageIdHelper {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----- Internal implementation ------------------------------------------//
|
// ----- Internal implementation ------------------------------------------//
|
||||||
|
|
||||||
private boolean hasTypeEncodingPrefix(String stringId) {
|
private boolean hasTypeEncodingPrefix(String stringId) {
|
||||||
return hasAmqpBinaryPrefix(stringId) || hasAmqpUuidPrefix(stringId) ||
|
return hasAmqpBinaryPrefix(stringId) || hasAmqpUuidPrefix(stringId) || hasAmqpUlongPrefix(stringId) || hasAmqpStringPrefix(stringId);
|
||||||
hasAmqpUlongPrefix(stringId) || hasAmqpStringPrefix(stringId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAmqpStringPrefix(String stringId) {
|
private boolean hasAmqpStringPrefix(String stringId) {
|
||||||
|
|
|
@ -0,0 +1,272 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.BYTES_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.DEFAULT_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.MAP_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.OBJECT_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.STREAM_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.TEXT_TYPE;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.jms.Destination;
|
||||||
|
import javax.jms.JMSException;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.buffers.impl.ResetLimitWrappedActiveMQBuffer;
|
||||||
|
import org.apache.activemq.artemis.core.server.ServerMessage;
|
||||||
|
import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl;
|
||||||
|
import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMapMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSObjectMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSTextMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPInvalidContentTypeException;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
|
import org.apache.qpid.proton.amqp.Symbol;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.Data;
|
||||||
|
import org.apache.qpid.proton.message.Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support class containing constant values and static methods that are used to map to / from
|
||||||
|
* AMQP Message types being sent or received.
|
||||||
|
*/
|
||||||
|
public final class AMQPMessageSupport {
|
||||||
|
|
||||||
|
// Message Properties used to map AMQP to JMS and back
|
||||||
|
|
||||||
|
public static final String JMS_AMQP_PREFIX = "JMS_AMQP_";
|
||||||
|
public static final int JMS_AMQP_PREFIX_LENGTH = JMS_AMQP_PREFIX.length();
|
||||||
|
|
||||||
|
public static final String MESSAGE_FORMAT = "MESSAGE_FORMAT";
|
||||||
|
public static final String ORIGINAL_ENCODING = "ORIGINAL_ENCODING";
|
||||||
|
public static final String NATIVE = "NATIVE";
|
||||||
|
public static final String HEADER = "HEADER";
|
||||||
|
public static final String PROPERTIES = "PROPERTIES";
|
||||||
|
|
||||||
|
public static final String FIRST_ACQUIRER = "FirstAcquirer";
|
||||||
|
public static final String CONTENT_TYPE = "ContentType";
|
||||||
|
public static final String CONTENT_ENCODING = "ContentEncoding";
|
||||||
|
public static final String REPLYTO_GROUP_ID = "ReplyToGroupID";
|
||||||
|
|
||||||
|
public static final String DELIVERY_ANNOTATION_PREFIX = "DA_";
|
||||||
|
public static final String MESSAGE_ANNOTATION_PREFIX = "MA_";
|
||||||
|
public static final String FOOTER_PREFIX = "FT_";
|
||||||
|
|
||||||
|
public static final String JMS_AMQP_HEADER = JMS_AMQP_PREFIX + HEADER;
|
||||||
|
public static final String JMS_AMQP_PROPERTIES = JMS_AMQP_PREFIX + PROPERTIES;
|
||||||
|
public static final String JMS_AMQP_ORIGINAL_ENCODING = JMS_AMQP_PREFIX + ORIGINAL_ENCODING;
|
||||||
|
public static final String JMS_AMQP_MESSAGE_FORMAT = JMS_AMQP_PREFIX + MESSAGE_FORMAT;
|
||||||
|
public static final String JMS_AMQP_NATIVE = JMS_AMQP_PREFIX + NATIVE;
|
||||||
|
public static final String JMS_AMQP_FIRST_ACQUIRER = JMS_AMQP_PREFIX + FIRST_ACQUIRER;
|
||||||
|
public static final String JMS_AMQP_CONTENT_TYPE = JMS_AMQP_PREFIX + CONTENT_TYPE;
|
||||||
|
public static final String JMS_AMQP_CONTENT_ENCODING = JMS_AMQP_PREFIX + CONTENT_ENCODING;
|
||||||
|
public static final String JMS_AMQP_REPLYTO_GROUP_ID = JMS_AMQP_PREFIX + REPLYTO_GROUP_ID;
|
||||||
|
public static final String JMS_AMQP_DELIVERY_ANNOTATION_PREFIX = JMS_AMQP_PREFIX + DELIVERY_ANNOTATION_PREFIX;
|
||||||
|
public static final String JMS_AMQP_MESSAGE_ANNOTATION_PREFIX = JMS_AMQP_PREFIX + MESSAGE_ANNOTATION_PREFIX;
|
||||||
|
public static final String JMS_AMQP_FOOTER_PREFIX = JMS_AMQP_PREFIX + FOOTER_PREFIX;
|
||||||
|
|
||||||
|
// Message body type definitions
|
||||||
|
public static final Binary EMPTY_BINARY = new Binary(new byte[0]);
|
||||||
|
public static final Data EMPTY_BODY = new Data(EMPTY_BINARY);
|
||||||
|
|
||||||
|
public static final short AMQP_UNKNOWN = 0;
|
||||||
|
public static final short AMQP_NULL = 1;
|
||||||
|
public static final short AMQP_DATA = 2;
|
||||||
|
public static final short AMQP_SEQUENCE = 3;
|
||||||
|
public static final short AMQP_VALUE_NULL = 4;
|
||||||
|
public static final short AMQP_VALUE_STRING = 5;
|
||||||
|
public static final short AMQP_VALUE_BINARY = 6;
|
||||||
|
public static final short AMQP_VALUE_MAP = 7;
|
||||||
|
public static final short AMQP_VALUE_LIST = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content type used to mark Data sections as containing a serialized java object.
|
||||||
|
*/
|
||||||
|
public static final String SERIALIZED_JAVA_OBJECT_CONTENT_TYPE = "application/x-java-serialized-object";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content type used to mark Data sections as containing arbitrary bytes.
|
||||||
|
*/
|
||||||
|
public static final String OCTET_STREAM_CONTENT_TYPE = "application/octet-stream";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup and return the correct Proton Symbol instance based on the given key.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* the String value name of the Symbol to locate.
|
||||||
|
*
|
||||||
|
* @return the Symbol value that matches the given key.
|
||||||
|
*/
|
||||||
|
public static Symbol getSymbol(String key) {
|
||||||
|
return Symbol.valueOf(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safe way to access message annotations which will check internal structure and either
|
||||||
|
* return the annotation if it exists or null if the annotation or any annotations are
|
||||||
|
* present.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* the String key to use to lookup an annotation.
|
||||||
|
* @param message
|
||||||
|
* the AMQP message object that is being examined.
|
||||||
|
*
|
||||||
|
* @return the given annotation value or null if not present in the message.
|
||||||
|
*/
|
||||||
|
public static Object getMessageAnnotation(String key, Message message) {
|
||||||
|
if (message != null && message.getMessageAnnotations() != null) {
|
||||||
|
Map<Symbol, Object> annotations = message.getMessageAnnotations().getValue();
|
||||||
|
return annotations.get(AMQPMessageSupport.getSymbol(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the content-type field of the properties section (if present) in the given
|
||||||
|
* message matches the provided string (where null matches if there is no content type
|
||||||
|
* present.
|
||||||
|
*
|
||||||
|
* @param contentType
|
||||||
|
* content type string to compare against, or null if none
|
||||||
|
* @param message
|
||||||
|
* the AMQP message object that is being examined.
|
||||||
|
*
|
||||||
|
* @return true if content type matches
|
||||||
|
*/
|
||||||
|
public static boolean isContentType(String contentType, Message message) {
|
||||||
|
if (contentType == null) {
|
||||||
|
return message.getContentType() == null;
|
||||||
|
} else {
|
||||||
|
return contentType.equals(message.getContentType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param contentType
|
||||||
|
* the contentType of the received message
|
||||||
|
* @return the character set to use, or null if not to treat the message as text
|
||||||
|
*/
|
||||||
|
public static Charset getCharsetForTextualContent(String contentType) {
|
||||||
|
try {
|
||||||
|
return AMQPContentTypeSupport.parseContentTypeForTextualCharset(contentType);
|
||||||
|
} catch (ActiveMQAMQPInvalidContentTypeException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSMessage wrapMessage(int messageType, ServerMessage wrapped, int deliveryCount) {
|
||||||
|
switch (messageType) {
|
||||||
|
case STREAM_TYPE:
|
||||||
|
return new ServerJMSStreamMessage(wrapped, deliveryCount);
|
||||||
|
case BYTES_TYPE:
|
||||||
|
return new ServerJMSBytesMessage(wrapped, deliveryCount);
|
||||||
|
case MAP_TYPE:
|
||||||
|
return new ServerJMSMapMessage(wrapped, deliveryCount);
|
||||||
|
case TEXT_TYPE:
|
||||||
|
return new ServerJMSTextMessage(wrapped, deliveryCount);
|
||||||
|
case OBJECT_TYPE:
|
||||||
|
return new ServerJMSObjectMessage(wrapped, deliveryCount);
|
||||||
|
default:
|
||||||
|
return new ServerJMSMessage(wrapped, deliveryCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toAddress(Destination destination) {
|
||||||
|
if (destination instanceof ActiveMQDestination) {
|
||||||
|
return ((ActiveMQDestination) destination).getAddress();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSBytesMessage createBytesMessage(IDGenerator idGenerator) {
|
||||||
|
return new ServerJMSBytesMessage(newMessage(idGenerator, BYTES_TYPE), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSMessage createBytesMessage(IDGenerator idGenerator, byte[] array, int arrayOffset, int length) throws JMSException {
|
||||||
|
ServerJMSBytesMessage message = createBytesMessage(idGenerator);
|
||||||
|
message.writeBytes(array, arrayOffset, length);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSStreamMessage createStreamMessage(IDGenerator idGenerator) {
|
||||||
|
return new ServerJMSStreamMessage(newMessage(idGenerator, STREAM_TYPE), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSMessage createMessage(IDGenerator idGenerator) {
|
||||||
|
return new ServerJMSMessage(newMessage(idGenerator, DEFAULT_TYPE), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSTextMessage createTextMessage(IDGenerator idGenerator) {
|
||||||
|
return new ServerJMSTextMessage(newMessage(idGenerator, TEXT_TYPE), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSTextMessage createTextMessage(IDGenerator idGenerator, String text) throws JMSException {
|
||||||
|
ServerJMSTextMessage message = createTextMessage(idGenerator);
|
||||||
|
message.setText(text);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSObjectMessage createObjectMessage(IDGenerator idGenerator) {
|
||||||
|
return new ServerJMSObjectMessage(newMessage(idGenerator, OBJECT_TYPE), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSMessage createObjectMessage(IDGenerator idGenerator, Binary serializedForm) throws JMSException {
|
||||||
|
ServerJMSObjectMessage message = createObjectMessage(idGenerator);
|
||||||
|
message.setSerializedForm(serializedForm);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSMessage createObjectMessage(IDGenerator idGenerator, byte[] array, int offset, int length) throws JMSException {
|
||||||
|
ServerJMSObjectMessage message = createObjectMessage(idGenerator);
|
||||||
|
message.setSerializedForm(new Binary(array, offset, length));
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSMapMessage createMapMessage(IDGenerator idGenerator) {
|
||||||
|
return new ServerJMSMapMessage(newMessage(idGenerator, MAP_TYPE), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerJMSMapMessage createMapMessage(IDGenerator idGenerator, Map<String, Object> content) throws JMSException {
|
||||||
|
ServerJMSMapMessage message = createMapMessage(idGenerator);
|
||||||
|
final Set<Map.Entry<String, Object>> set = content.entrySet();
|
||||||
|
for (Map.Entry<String, Object> entry : set) {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof Binary) {
|
||||||
|
Binary binary = (Binary) value;
|
||||||
|
value = Arrays.copyOfRange(binary.getArray(), binary.getArrayOffset(), binary.getLength());
|
||||||
|
}
|
||||||
|
message.setObject(entry.getKey(), value);
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerMessageImpl newMessage(IDGenerator idGenerator, byte messageType) {
|
||||||
|
ServerMessageImpl message = new ServerMessageImpl(idGenerator.generateID(), 512);
|
||||||
|
message.setType(messageType);
|
||||||
|
((ResetLimitWrappedActiveMQBuffer) message.getBodyBuffer()).setMessage(null);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,8 +16,12 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public class AMQPMessageTypes {
|
public class AMQPMessageTypes {
|
||||||
|
|
||||||
|
// TODO - Remove in future release as these are no longer used by the
|
||||||
|
// inbound JMS Transformer.
|
||||||
|
|
||||||
public static final String AMQP_TYPE_KEY = "amqp:type";
|
public static final String AMQP_TYPE_KEY = "amqp:type";
|
||||||
|
|
||||||
public static final String AMQP_SEQUENCE = "amqp:sequence";
|
public static final String AMQP_SEQUENCE = "amqp:sequence";
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
* <p>
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* <p>
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,12 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
import javax.jms.Message;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
|
||||||
public class AMQPNativeInboundTransformer extends AMQPRawInboundTransformer {
|
public class AMQPNativeInboundTransformer extends AMQPRawInboundTransformer {
|
||||||
|
|
||||||
public AMQPNativeInboundTransformer(JMSVendor vendor) {
|
public AMQPNativeInboundTransformer(IDGenerator idGenerator) {
|
||||||
super(vendor);
|
super(idGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,16 +32,13 @@ public class AMQPNativeInboundTransformer extends AMQPRawInboundTransformer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InboundTransformer getFallbackTransformer() {
|
public InboundTransformer getFallbackTransformer() {
|
||||||
return new AMQPRawInboundTransformer(getVendor());
|
return new AMQPRawInboundTransformer(idGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message transform(EncodedMessage amqpMessage) throws Exception {
|
public ServerJMSMessage transform(EncodedMessage amqpMessage) throws Exception {
|
||||||
org.apache.qpid.proton.message.Message amqp = amqpMessage.decode();
|
org.apache.qpid.proton.message.Message amqp = amqpMessage.decode();
|
||||||
|
|
||||||
Message rc = super.transform(amqpMessage);
|
return populateMessage(super.transform(amqpMessage), amqp);
|
||||||
|
|
||||||
populateMessage(rc, amqp);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
* <p>
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* <p>
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,45 +16,65 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
import javax.jms.JMSException;
|
import javax.jms.JMSException;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
import org.apache.qpid.proton.amqp.UnsignedInteger;
|
import org.apache.qpid.proton.amqp.UnsignedInteger;
|
||||||
import org.apache.qpid.proton.amqp.messaging.Header;
|
import org.apache.qpid.proton.amqp.messaging.Header;
|
||||||
|
import org.apache.qpid.proton.codec.WritableBuffer;
|
||||||
import org.apache.qpid.proton.message.ProtonJMessage;
|
import org.apache.qpid.proton.message.ProtonJMessage;
|
||||||
|
|
||||||
public class AMQPNativeOutboundTransformer extends OutboundTransformer {
|
public class AMQPNativeOutboundTransformer extends OutboundTransformer {
|
||||||
|
|
||||||
public AMQPNativeOutboundTransformer(JMSVendor vendor) {
|
public AMQPNativeOutboundTransformer(IDGenerator idGenerator) {
|
||||||
super(vendor);
|
super(idGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProtonJMessage transform(OutboundTransformer options, BytesMessage msg) throws JMSException {
|
@Override
|
||||||
byte[] data = new byte[(int) msg.getBodyLength()];
|
public long transform(ServerJMSMessage message, WritableBuffer buffer) throws JMSException, UnsupportedEncodingException {
|
||||||
msg.readBytes(data);
|
if (message == null || !(message instanceof ServerJMSBytesMessage)) {
|
||||||
msg.reset();
|
return 0;
|
||||||
int count = msg.getIntProperty("JMSXDeliveryCount");
|
|
||||||
|
|
||||||
// decode...
|
|
||||||
ProtonJMessage amqp = (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create();
|
|
||||||
int offset = 0;
|
|
||||||
int len = data.length;
|
|
||||||
while (len > 0) {
|
|
||||||
final int decoded = amqp.decode(data, offset, len);
|
|
||||||
assert decoded > 0 : "Make progress decoding the message";
|
|
||||||
offset += decoded;
|
|
||||||
len -= decoded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the DeliveryCount header...
|
return transform(this, (ServerJMSBytesMessage) message, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long transform(OutboundTransformer options, ServerJMSBytesMessage message, WritableBuffer buffer) throws JMSException {
|
||||||
|
byte[] data = new byte[(int) message.getBodyLength()];
|
||||||
|
message.readBytes(data);
|
||||||
|
message.reset();
|
||||||
|
|
||||||
// The AMQP delivery-count field only includes prior failed delivery attempts,
|
// The AMQP delivery-count field only includes prior failed delivery attempts,
|
||||||
// whereas JMSXDeliveryCount includes the first/current delivery attempt. Subtract 1.
|
int amqpDeliveryCount = message.getDeliveryCount() - 1;
|
||||||
if (amqp.getHeader() == null) {
|
if (amqpDeliveryCount >= 1) {
|
||||||
amqp.setHeader(new Header());
|
|
||||||
|
// decode...
|
||||||
|
ProtonJMessage amqp = (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create();
|
||||||
|
int offset = 0;
|
||||||
|
int len = data.length;
|
||||||
|
while (len > 0) {
|
||||||
|
final int decoded = amqp.decode(data, offset, len);
|
||||||
|
assert decoded > 0 : "Make progress decoding the message";
|
||||||
|
offset += decoded;
|
||||||
|
len -= decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the DeliveryCount header which might require adding a Header
|
||||||
|
if (amqp.getHeader() == null && amqpDeliveryCount > 0) {
|
||||||
|
amqp.setHeader(new Header());
|
||||||
|
}
|
||||||
|
|
||||||
|
amqp.getHeader().setDeliveryCount(new UnsignedInteger(amqpDeliveryCount));
|
||||||
|
|
||||||
|
amqp.encode(buffer);
|
||||||
|
} else {
|
||||||
|
buffer.put(data, 0, data.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
amqp.getHeader().setDeliveryCount(new UnsignedInteger(count - 1));
|
return 0;
|
||||||
|
|
||||||
return amqp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
* <p>
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* <p>
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,14 +16,21 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_MESSAGE_FORMAT;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_NATIVE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.createBytesMessage;
|
||||||
|
|
||||||
import javax.jms.DeliveryMode;
|
import javax.jms.DeliveryMode;
|
||||||
import javax.jms.Message;
|
import javax.jms.Message;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
|
||||||
public class AMQPRawInboundTransformer extends InboundTransformer {
|
public class AMQPRawInboundTransformer extends InboundTransformer {
|
||||||
|
|
||||||
public AMQPRawInboundTransformer(JMSVendor vendor) {
|
public AMQPRawInboundTransformer(IDGenerator idGenerator) {
|
||||||
super(vendor);
|
super(idGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -37,24 +44,19 @@ public class AMQPRawInboundTransformer extends InboundTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message transform(EncodedMessage amqpMessage) throws Exception {
|
public ServerJMSMessage transform(EncodedMessage amqpMessage) throws Exception {
|
||||||
BytesMessage rc = vendor.createBytesMessage();
|
ServerJMSBytesMessage message = createBytesMessage(idGenerator);
|
||||||
rc.writeBytes(amqpMessage.getArray(), amqpMessage.getArrayOffset(), amqpMessage.getLength());
|
message.writeBytes(amqpMessage.getArray(), amqpMessage.getArrayOffset(), amqpMessage.getLength());
|
||||||
|
|
||||||
// We cannot decode the message headers to check so err on the side of caution
|
// We cannot decode the message headers to check so err on the side of caution
|
||||||
// and mark all messages as persistent.
|
// and mark all messages as persistent.
|
||||||
rc.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
|
message.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
|
||||||
rc.setJMSPriority(defaultPriority);
|
message.setJMSPriority(Message.DEFAULT_PRIORITY);
|
||||||
|
message.setJMSTimestamp(System.currentTimeMillis());
|
||||||
|
|
||||||
final long now = System.currentTimeMillis();
|
message.setLongProperty(JMS_AMQP_MESSAGE_FORMAT, amqpMessage.getMessageFormat());
|
||||||
rc.setJMSTimestamp(now);
|
message.setBooleanProperty(JMS_AMQP_NATIVE, true);
|
||||||
if (defaultTtl > 0) {
|
|
||||||
rc.setJMSExpiration(now + defaultTtl);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc.setLongProperty(prefixVendor + "MESSAGE_FORMAT", amqpMessage.getMessageFormat());
|
return message;
|
||||||
rc.setBooleanProperty(prefixVendor + "NATIVE", true);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
* <p>
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* <p>
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|
|
@ -16,13 +16,26 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
import javax.jms.DeliveryMode;
|
import static org.apache.activemq.artemis.api.core.Message.HDR_SCHEDULED_DELIVERY_TIME;
|
||||||
import javax.jms.JMSException;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_CONTENT_ENCODING;
|
||||||
import javax.jms.Message;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_CONTENT_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_FIRST_ACQUIRER;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_FOOTER_PREFIX;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_HEADER;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_MESSAGE_ANNOTATION_PREFIX;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_REPLYTO_GROUP_ID;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.jms.DeliveryMode;
|
||||||
|
import javax.jms.JMSException;
|
||||||
|
import javax.jms.Message;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerDestination;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
import org.apache.qpid.proton.amqp.Binary;
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
import org.apache.qpid.proton.amqp.Decimal128;
|
import org.apache.qpid.proton.amqp.Decimal128;
|
||||||
import org.apache.qpid.proton.amqp.Decimal32;
|
import org.apache.qpid.proton.amqp.Decimal32;
|
||||||
|
@ -38,109 +51,61 @@ import org.apache.qpid.proton.amqp.messaging.Header;
|
||||||
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
||||||
import org.apache.qpid.proton.amqp.messaging.Properties;
|
import org.apache.qpid.proton.amqp.messaging.Properties;
|
||||||
|
|
||||||
import static org.apache.activemq.artemis.api.core.Message.HDR_SCHEDULED_DELIVERY_TIME;
|
|
||||||
|
|
||||||
public abstract class InboundTransformer {
|
public abstract class InboundTransformer {
|
||||||
|
|
||||||
JMSVendor vendor;
|
protected IDGenerator idGenerator;
|
||||||
|
|
||||||
public static final String TRANSFORMER_NATIVE = "native";
|
public static final String TRANSFORMER_NATIVE = "native";
|
||||||
public static final String TRANSFORMER_RAW = "raw";
|
public static final String TRANSFORMER_RAW = "raw";
|
||||||
public static final String TRANSFORMER_JMS = "jms";
|
public static final String TRANSFORMER_JMS = "jms";
|
||||||
|
|
||||||
String prefixVendor = "JMS_AMQP_";
|
public InboundTransformer(IDGenerator idGenerator) {
|
||||||
String prefixDeliveryAnnotations = "DA_";
|
this.idGenerator = idGenerator;
|
||||||
String prefixMessageAnnotations = "MA_";
|
|
||||||
String prefixFooter = "FT_";
|
|
||||||
|
|
||||||
int defaultDeliveryMode = DeliveryMode.NON_PERSISTENT;
|
|
||||||
int defaultPriority = Message.DEFAULT_PRIORITY;
|
|
||||||
long defaultTtl = Message.DEFAULT_TIME_TO_LIVE;
|
|
||||||
|
|
||||||
public InboundTransformer(JMSVendor vendor) {
|
|
||||||
this.vendor = vendor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Message transform(EncodedMessage amqpMessage) throws Exception;
|
public abstract ServerJMSMessage transform(EncodedMessage amqpMessage) throws Exception;
|
||||||
|
|
||||||
public abstract String getTransformerName();
|
public abstract String getTransformerName();
|
||||||
|
|
||||||
public abstract InboundTransformer getFallbackTransformer();
|
public abstract InboundTransformer getFallbackTransformer();
|
||||||
|
|
||||||
public int getDefaultDeliveryMode() {
|
@SuppressWarnings("unchecked")
|
||||||
return defaultDeliveryMode;
|
protected ServerJMSMessage populateMessage(ServerJMSMessage jms, org.apache.qpid.proton.message.Message amqp) throws Exception {
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultDeliveryMode(int defaultDeliveryMode) {
|
|
||||||
this.defaultDeliveryMode = defaultDeliveryMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDefaultPriority() {
|
|
||||||
return defaultPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultPriority(int defaultPriority) {
|
|
||||||
this.defaultPriority = defaultPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getDefaultTtl() {
|
|
||||||
return defaultTtl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultTtl(long defaultTtl) {
|
|
||||||
this.defaultTtl = defaultTtl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPrefixVendor() {
|
|
||||||
return prefixVendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrefixVendor(String prefixVendor) {
|
|
||||||
this.prefixVendor = prefixVendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JMSVendor getVendor() {
|
|
||||||
return vendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVendor(JMSVendor vendor) {
|
|
||||||
this.vendor = vendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void populateMessage(Message jms, org.apache.qpid.proton.message.Message amqp) throws Exception {
|
|
||||||
Header header = amqp.getHeader();
|
Header header = amqp.getHeader();
|
||||||
if (header == null) {
|
if (header != null) {
|
||||||
header = new Header();
|
jms.setBooleanProperty(JMS_AMQP_HEADER, true);
|
||||||
}
|
|
||||||
|
|
||||||
if (header.getDurable() != null) {
|
if (header.getDurable() != null) {
|
||||||
jms.setJMSDeliveryMode(header.getDurable().booleanValue() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
|
jms.setJMSDeliveryMode(header.getDurable().booleanValue() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
|
||||||
|
} else {
|
||||||
|
jms.setJMSDeliveryMode(Message.DEFAULT_DELIVERY_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.getPriority() != null) {
|
||||||
|
jms.setJMSPriority(header.getPriority().intValue());
|
||||||
|
} else {
|
||||||
|
jms.setJMSPriority(Message.DEFAULT_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.getFirstAcquirer() != null) {
|
||||||
|
jms.setBooleanProperty(JMS_AMQP_FIRST_ACQUIRER, header.getFirstAcquirer());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.getDeliveryCount() != null) {
|
||||||
|
// AMQP Delivery Count counts only failed delivers where JMS
|
||||||
|
// Delivery Count should include the original delivery in the count.
|
||||||
|
jms.setLongProperty("JMSXDeliveryCount", header.getDeliveryCount().longValue() + 1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
jms.setJMSDeliveryMode(defaultDeliveryMode);
|
jms.setJMSPriority((byte) Message.DEFAULT_PRIORITY);
|
||||||
}
|
jms.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final MessageAnnotations ma = amqp.getMessageAnnotations();
|
final MessageAnnotations ma = amqp.getMessageAnnotations();
|
||||||
if (ma != null) {
|
if (ma != null) {
|
||||||
for (Map.Entry<?, ?> entry : ma.getValue().entrySet()) {
|
for (Map.Entry<?, ?> entry : ma.getValue().entrySet()) {
|
||||||
String key = entry.getKey().toString();
|
String key = entry.getKey().toString();
|
||||||
if ("x-opt-jms-type".equals(key) && entry.getValue() != null) {
|
if ("x-opt-delivery-time".equals(key) && entry.getValue() != null) {
|
||||||
// Legacy annotation, JMSType value will be replaced by Subject further down if also present.
|
|
||||||
jms.setJMSType(entry.getValue().toString());
|
|
||||||
} else if ("x-opt-delivery-time".equals(key) && entry.getValue() != null) {
|
|
||||||
long deliveryTime = ((Number) entry.getValue()).longValue();
|
long deliveryTime = ((Number) entry.getValue()).longValue();
|
||||||
jms.setLongProperty(HDR_SCHEDULED_DELIVERY_TIME.toString(), deliveryTime);
|
jms.setLongProperty(HDR_SCHEDULED_DELIVERY_TIME.toString(), deliveryTime);
|
||||||
} else if ("x-opt-delivery-delay".equals(key) && entry.getValue() != null) {
|
} else if ("x-opt-delivery-delay".equals(key) && entry.getValue() != null) {
|
||||||
|
@ -149,41 +114,15 @@ public abstract class InboundTransformer {
|
||||||
jms.setLongProperty(HDR_SCHEDULED_DELIVERY_TIME.toString(), System.currentTimeMillis() + delay);
|
jms.setLongProperty(HDR_SCHEDULED_DELIVERY_TIME.toString(), System.currentTimeMillis() + delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//todo
|
|
||||||
/*else if ("x-opt-delivery-repeat".equals(key) && entry.getValue() != null) {
|
|
||||||
int repeat = ((Number) entry.getValue()).intValue();
|
|
||||||
if (repeat > 0) {
|
|
||||||
jms.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, repeat);
|
|
||||||
}
|
|
||||||
} else if ("x-opt-delivery-period".equals(key) && entry.getValue() != null) {
|
|
||||||
long period = ((Number) entry.getValue()).longValue();
|
|
||||||
if (period > 0) {
|
|
||||||
jms.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, period);
|
|
||||||
}
|
|
||||||
} else if ("x-opt-delivery-cron".equals(key) && entry.getValue() != null) {
|
|
||||||
String cronEntry = (String) entry.getValue();
|
|
||||||
if (cronEntry != null) {
|
|
||||||
jms.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, cronEntry);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
setProperty(jms, prefixVendor + prefixMessageAnnotations + key, entry.getValue());
|
setProperty(jms, JMS_AMQP_MESSAGE_ANNOTATION_PREFIX + key, entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ApplicationProperties ap = amqp.getApplicationProperties();
|
final ApplicationProperties ap = amqp.getApplicationProperties();
|
||||||
if (ap != null) {
|
if (ap != null) {
|
||||||
for (Map.Entry<Object, Object> entry : (Set<Map.Entry<Object, Object>>) ap.getValue().entrySet()) {
|
for (Map.Entry<Object, Object> entry : (Set<Map.Entry<Object, Object>>) ap.getValue().entrySet()) {
|
||||||
String key = entry.getKey().toString();
|
setProperty(jms, entry.getKey().toString(), entry.getValue());
|
||||||
if ("JMSXGroupID".equals(key)) {
|
|
||||||
vendor.setJMSXGroupID(jms, entry.getValue().toString());
|
|
||||||
} else if ("JMSXGroupSequence".equals(key)) {
|
|
||||||
vendor.setJMSXGroupSequence(jms, ((Number) entry.getValue()).intValue());
|
|
||||||
} else if ("JMSXUserID".equals(key)) {
|
|
||||||
vendor.setJMSXUserID(jms, entry.getValue().toString());
|
|
||||||
} else {
|
|
||||||
setProperty(jms, key, entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,37 +133,38 @@ public abstract class InboundTransformer {
|
||||||
}
|
}
|
||||||
Binary userId = properties.getUserId();
|
Binary userId = properties.getUserId();
|
||||||
if (userId != null) {
|
if (userId != null) {
|
||||||
vendor.setJMSXUserID(jms, new String(userId.getArray(), userId.getArrayOffset(), userId.getLength(), StandardCharsets.UTF_8));
|
// TODO - Better Way to set this?
|
||||||
|
jms.setStringProperty("JMSXUserID", new String(userId.getArray(), userId.getArrayOffset(), userId.getLength(), StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
if (properties.getTo() != null) {
|
if (properties.getTo() != null) {
|
||||||
jms.setJMSDestination(vendor.createDestination(properties.getTo()));
|
jms.setJMSDestination(new ServerDestination(properties.getTo()));
|
||||||
}
|
}
|
||||||
if (properties.getSubject() != null) {
|
if (properties.getSubject() != null) {
|
||||||
jms.setJMSType(properties.getSubject());
|
jms.setJMSType(properties.getSubject());
|
||||||
}
|
}
|
||||||
if (properties.getReplyTo() != null) {
|
if (properties.getReplyTo() != null) {
|
||||||
jms.setJMSReplyTo(vendor.createDestination(properties.getReplyTo()));
|
jms.setJMSReplyTo(new ServerDestination(properties.getReplyTo()));
|
||||||
}
|
}
|
||||||
if (properties.getCorrelationId() != null) {
|
if (properties.getCorrelationId() != null) {
|
||||||
jms.setJMSCorrelationID(AMQPMessageIdHelper.INSTANCE.toBaseMessageIdString(properties.getCorrelationId()));
|
jms.setJMSCorrelationID(AMQPMessageIdHelper.INSTANCE.toBaseMessageIdString(properties.getCorrelationId()));
|
||||||
}
|
}
|
||||||
if (properties.getContentType() != null) {
|
if (properties.getContentType() != null) {
|
||||||
jms.setStringProperty(prefixVendor + "ContentType", properties.getContentType().toString());
|
jms.setStringProperty(JMS_AMQP_CONTENT_TYPE, properties.getContentType().toString());
|
||||||
}
|
}
|
||||||
if (properties.getContentEncoding() != null) {
|
if (properties.getContentEncoding() != null) {
|
||||||
jms.setStringProperty(prefixVendor + "ContentEncoding", properties.getContentEncoding().toString());
|
jms.setStringProperty(JMS_AMQP_CONTENT_ENCODING, properties.getContentEncoding().toString());
|
||||||
}
|
}
|
||||||
if (properties.getCreationTime() != null) {
|
if (properties.getCreationTime() != null) {
|
||||||
jms.setJMSTimestamp(properties.getCreationTime().getTime());
|
jms.setJMSTimestamp(properties.getCreationTime().getTime());
|
||||||
}
|
}
|
||||||
if (properties.getGroupId() != null) {
|
if (properties.getGroupId() != null) {
|
||||||
vendor.setJMSXGroupID(jms, properties.getGroupId());
|
jms.setStringProperty("_AMQ_GROUP_ID", properties.getGroupId());
|
||||||
}
|
}
|
||||||
if (properties.getGroupSequence() != null) {
|
if (properties.getGroupSequence() != null) {
|
||||||
vendor.setJMSXGroupSequence(jms, properties.getGroupSequence().intValue());
|
jms.setIntProperty("JMSXGroupSeq", properties.getGroupSequence().intValue());
|
||||||
}
|
}
|
||||||
if (properties.getReplyToGroupId() != null) {
|
if (properties.getReplyToGroupId() != null) {
|
||||||
jms.setStringProperty(prefixVendor + "ReplyToGroupID", properties.getReplyToGroupId());
|
jms.setStringProperty(JMS_AMQP_REPLYTO_GROUP_ID, properties.getReplyToGroupId());
|
||||||
}
|
}
|
||||||
if (properties.getAbsoluteExpiryTime() != null) {
|
if (properties.getAbsoluteExpiryTime() != null) {
|
||||||
jms.setJMSExpiration(properties.getAbsoluteExpiryTime().getTime());
|
jms.setJMSExpiration(properties.getAbsoluteExpiryTime().getTime());
|
||||||
|
@ -232,9 +172,9 @@ public abstract class InboundTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the jms expiration has not yet been set...
|
// If the jms expiration has not yet been set...
|
||||||
if (jms.getJMSExpiration() == 0) {
|
if (header != null && jms.getJMSExpiration() == 0) {
|
||||||
// Then lets try to set it based on the message ttl.
|
// Then lets try to set it based on the message ttl.
|
||||||
long ttl = defaultTtl;
|
long ttl = Message.DEFAULT_TIME_TO_LIVE;
|
||||||
if (header.getTtl() != null) {
|
if (header.getTtl() != null) {
|
||||||
ttl = header.getTtl().longValue();
|
ttl = header.getTtl().longValue();
|
||||||
}
|
}
|
||||||
|
@ -250,9 +190,11 @@ public abstract class InboundTransformer {
|
||||||
if (fp != null) {
|
if (fp != null) {
|
||||||
for (Map.Entry<Object, Object> entry : (Set<Map.Entry<Object, Object>>) fp.getValue().entrySet()) {
|
for (Map.Entry<Object, Object> entry : (Set<Map.Entry<Object, Object>>) fp.getValue().entrySet()) {
|
||||||
String key = entry.getKey().toString();
|
String key = entry.getKey().toString();
|
||||||
setProperty(jms, prefixVendor + prefixFooter + key, entry.getValue());
|
setProperty(jms, JMS_AMQP_FOOTER_PREFIX + key, entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return jms;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setProperty(Message msg, String key, Object value) throws JMSException {
|
private void setProperty(Message msg, String key, Object value) throws JMSException {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
* <p>
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* <p>
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,27 +16,50 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_DATA;
|
||||||
import javax.jms.MapMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_NULL;
|
||||||
import javax.jms.Message;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_SEQUENCE;
|
||||||
import javax.jms.ObjectMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_BINARY;
|
||||||
import javax.jms.StreamMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_LIST;
|
||||||
import javax.jms.TextMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_MAP;
|
||||||
import java.io.Serializable;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_NULL;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_STRING;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_MESSAGE_FORMAT;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_ORIGINAL_ENCODING;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.OCTET_STREAM_CONTENT_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.createBytesMessage;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.createMapMessage;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.createMessage;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.createObjectMessage;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.createStreamMessage;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.createTextMessage;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.getCharsetForTextualContent;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.isContentType;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.nio.charset.CharacterCodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPInternalErrorException;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
import org.apache.qpid.proton.amqp.Binary;
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
import org.apache.qpid.proton.amqp.messaging.AmqpSequence;
|
import org.apache.qpid.proton.amqp.messaging.AmqpSequence;
|
||||||
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
||||||
import org.apache.qpid.proton.amqp.messaging.Data;
|
import org.apache.qpid.proton.amqp.messaging.Data;
|
||||||
import org.apache.qpid.proton.amqp.messaging.Section;
|
import org.apache.qpid.proton.amqp.messaging.Section;
|
||||||
|
import org.apache.qpid.proton.message.Message;
|
||||||
|
|
||||||
public class JMSMappingInboundTransformer extends InboundTransformer {
|
public class JMSMappingInboundTransformer extends InboundTransformer {
|
||||||
|
|
||||||
public JMSMappingInboundTransformer(JMSVendor vendor) {
|
public JMSMappingInboundTransformer(IDGenerator idGenerator) {
|
||||||
super(vendor);
|
super(idGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,75 +69,128 @@ public class JMSMappingInboundTransformer extends InboundTransformer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InboundTransformer getFallbackTransformer() {
|
public InboundTransformer getFallbackTransformer() {
|
||||||
return new AMQPNativeInboundTransformer(getVendor());
|
return new AMQPNativeInboundTransformer(idGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
|
||||||
@Override
|
@Override
|
||||||
public Message transform(EncodedMessage amqpMessage) throws Exception {
|
public ServerJMSMessage transform(EncodedMessage encodedMessage) throws Exception {
|
||||||
org.apache.qpid.proton.message.Message amqp = amqpMessage.decode();
|
ServerJMSMessage transformedMessage = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Message amqpMessage = encodedMessage.decode();
|
||||||
|
transformedMessage = createServerMessage(amqpMessage);
|
||||||
|
populateMessage(transformedMessage, amqpMessage);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
InboundTransformer transformer = this.getFallbackTransformer();
|
||||||
|
|
||||||
|
while (transformer != null) {
|
||||||
|
try {
|
||||||
|
transformedMessage = transformer.transform(encodedMessage);
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
transformer = transformer.getFallbackTransformer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regardless of the transformer that finally decoded the message we need to ensure that
|
||||||
|
// the AMQP Message Format value is preserved for application on retransmit.
|
||||||
|
if (transformedMessage != null && encodedMessage.getMessageFormat() != 0) {
|
||||||
|
transformedMessage.setLongProperty(JMS_AMQP_MESSAGE_FORMAT, encodedMessage.getMessageFormat());
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private ServerJMSMessage createServerMessage(Message message) throws Exception {
|
||||||
|
|
||||||
|
Section body = message.getBody();
|
||||||
|
ServerJMSMessage result;
|
||||||
|
|
||||||
Message rc;
|
|
||||||
final Section body = amqp.getBody();
|
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
rc = vendor.createMessage();
|
if (isContentType(SERIALIZED_JAVA_OBJECT_CONTENT_TYPE, message)) {
|
||||||
|
result = createObjectMessage(idGenerator);
|
||||||
|
} else if (isContentType(OCTET_STREAM_CONTENT_TYPE, message) || isContentType(null, message)) {
|
||||||
|
result = createBytesMessage(idGenerator);
|
||||||
|
} else {
|
||||||
|
Charset charset = getCharsetForTextualContent(message.getContentType());
|
||||||
|
if (charset != null) {
|
||||||
|
result = createTextMessage(idGenerator);
|
||||||
|
} else {
|
||||||
|
result = createMessage(idGenerator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_NULL);
|
||||||
} else if (body instanceof Data) {
|
} else if (body instanceof Data) {
|
||||||
Binary d = ((Data) body).getValue();
|
Binary payload = ((Data) body).getValue();
|
||||||
BytesMessage m = vendor.createBytesMessage();
|
|
||||||
m.writeBytes(d.getArray(), d.getArrayOffset(), d.getLength());
|
if (isContentType(SERIALIZED_JAVA_OBJECT_CONTENT_TYPE, message)) {
|
||||||
rc = m;
|
result = createObjectMessage(idGenerator, payload.getArray(), payload.getArrayOffset(), payload.getLength());
|
||||||
|
} else if (isContentType(OCTET_STREAM_CONTENT_TYPE, message)) {
|
||||||
|
result = createBytesMessage(idGenerator, payload.getArray(), payload.getArrayOffset(), payload.getLength());
|
||||||
|
} else {
|
||||||
|
Charset charset = getCharsetForTextualContent(message.getContentType());
|
||||||
|
if (StandardCharsets.UTF_8.equals(charset)) {
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(payload.getArray(), payload.getArrayOffset(), payload.getLength());
|
||||||
|
|
||||||
|
try {
|
||||||
|
CharBuffer chars = charset.newDecoder().decode(buf);
|
||||||
|
result = createTextMessage(idGenerator, String.valueOf(chars));
|
||||||
|
} catch (CharacterCodingException e) {
|
||||||
|
result = createBytesMessage(idGenerator, payload.getArray(), payload.getArrayOffset(), payload.getLength());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = createBytesMessage(idGenerator, payload.getArray(), payload.getArrayOffset(), payload.getLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_DATA);
|
||||||
} else if (body instanceof AmqpSequence) {
|
} else if (body instanceof AmqpSequence) {
|
||||||
AmqpSequence sequence = (AmqpSequence) body;
|
AmqpSequence sequence = (AmqpSequence) body;
|
||||||
StreamMessage m = vendor.createStreamMessage();
|
ServerJMSStreamMessage m = createStreamMessage(idGenerator);
|
||||||
for (Object item : sequence.getValue()) {
|
for (Object item : sequence.getValue()) {
|
||||||
m.writeObject(item);
|
m.writeObject(item);
|
||||||
}
|
}
|
||||||
rc = m;
|
|
||||||
m.setStringProperty(AMQPMessageTypes.AMQP_TYPE_KEY, AMQPMessageTypes.AMQP_SEQUENCE);
|
result = m;
|
||||||
|
result.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_SEQUENCE);
|
||||||
} else if (body instanceof AmqpValue) {
|
} else if (body instanceof AmqpValue) {
|
||||||
Object value = ((AmqpValue) body).getValue();
|
Object value = ((AmqpValue) body).getValue();
|
||||||
if (value == null) {
|
if (value == null || value instanceof String) {
|
||||||
rc = vendor.createObjectMessage();
|
result = createTextMessage(idGenerator, (String) value);
|
||||||
}
|
|
||||||
if (value instanceof String) {
|
result.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, value == null ? AMQP_VALUE_NULL : AMQP_VALUE_STRING);
|
||||||
TextMessage m = vendor.createTextMessage();
|
|
||||||
m.setText((String) value);
|
|
||||||
rc = m;
|
|
||||||
} else if (value instanceof Binary) {
|
} else if (value instanceof Binary) {
|
||||||
Binary d = (Binary) value;
|
Binary payload = (Binary) value;
|
||||||
BytesMessage m = vendor.createBytesMessage();
|
|
||||||
m.writeBytes(d.getArray(), d.getArrayOffset(), d.getLength());
|
if (isContentType(SERIALIZED_JAVA_OBJECT_CONTENT_TYPE, message)) {
|
||||||
rc = m;
|
result = createObjectMessage(idGenerator, payload);
|
||||||
|
} else {
|
||||||
|
result = createBytesMessage(idGenerator, payload.getArray(), payload.getArrayOffset(), payload.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_BINARY);
|
||||||
} else if (value instanceof List) {
|
} else if (value instanceof List) {
|
||||||
StreamMessage m = vendor.createStreamMessage();
|
ServerJMSStreamMessage m = createStreamMessage(idGenerator);
|
||||||
for (Object item : (List<Object>) value) {
|
for (Object item : (List<Object>) value) {
|
||||||
m.writeObject(item);
|
m.writeObject(item);
|
||||||
}
|
}
|
||||||
rc = m;
|
result = m;
|
||||||
m.setStringProperty(AMQPMessageTypes.AMQP_TYPE_KEY, AMQPMessageTypes.AMQP_LIST);
|
result.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_LIST);
|
||||||
} else if (value instanceof Map) {
|
} else if (value instanceof Map) {
|
||||||
MapMessage m = vendor.createMapMessage();
|
result = createMapMessage(idGenerator, (Map<String, Object>) value);
|
||||||
final Set<Map.Entry<String, Object>> set = ((Map<String, Object>) value).entrySet();
|
result.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_MAP);
|
||||||
for (Map.Entry<String, Object> entry : set) {
|
|
||||||
m.setObject(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
rc = m;
|
|
||||||
} else {
|
} else {
|
||||||
ObjectMessage m = vendor.createObjectMessage();
|
// Trigger fall-back to native encoder which generates BytesMessage with the
|
||||||
m.setObject((Serializable) value);
|
// original message stored in the message body.
|
||||||
rc = m;
|
throw new ActiveMQAMQPInternalErrorException("Unable to encode to ActiveMQ JMS Message");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Unexpected body type: " + body.getClass());
|
throw new RuntimeException("Unexpected body type: " + body.getClass());
|
||||||
}
|
}
|
||||||
rc.setJMSDeliveryMode(defaultDeliveryMode);
|
|
||||||
rc.setJMSPriority(defaultPriority);
|
|
||||||
rc.setJMSExpiration(defaultTtl);
|
|
||||||
|
|
||||||
populateMessage(rc, amqp);
|
return result;
|
||||||
|
|
||||||
rc.setLongProperty(prefixVendor + "MESSAGE_FORMAT", amqpMessage.getMessageFormat());
|
|
||||||
rc.setBooleanProperty(prefixVendor + "NATIVE", false);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
* <p>
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* <p>
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,30 +16,61 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
import static org.apache.activemq.artemis.api.core.Message.HDR_SCHEDULED_DELIVERY_TIME;
|
||||||
import javax.jms.DeliveryMode;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_DATA;
|
||||||
import javax.jms.Destination;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_NULL;
|
||||||
import javax.jms.JMSException;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_SEQUENCE;
|
||||||
import javax.jms.MapMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_UNKNOWN;
|
||||||
import javax.jms.Message;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_BINARY;
|
||||||
import javax.jms.MessageEOFException;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_LIST;
|
||||||
import javax.jms.ObjectMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_STRING;
|
||||||
import javax.jms.Queue;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.EMPTY_BINARY;
|
||||||
import javax.jms.StreamMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_CONTENT_ENCODING;
|
||||||
import javax.jms.TemporaryQueue;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_CONTENT_TYPE;
|
||||||
import javax.jms.TemporaryTopic;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_DELIVERY_ANNOTATION_PREFIX;
|
||||||
import javax.jms.TextMessage;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_FIRST_ACQUIRER;
|
||||||
import javax.jms.Topic;
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_FOOTER_PREFIX;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_HEADER;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_MESSAGE_ANNOTATION_PREFIX;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_MESSAGE_FORMAT;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_NATIVE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_ORIGINAL_ENCODING;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_PREFIX;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_PROPERTIES;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_REPLYTO_GROUP_ID;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.toAddress;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.jms.Destination;
|
||||||
|
import javax.jms.JMSException;
|
||||||
|
import javax.jms.Message;
|
||||||
|
import javax.jms.MessageEOFException;
|
||||||
|
import javax.jms.Queue;
|
||||||
|
import javax.jms.TemporaryQueue;
|
||||||
|
import javax.jms.TemporaryTopic;
|
||||||
|
import javax.jms.TextMessage;
|
||||||
|
import javax.jms.Topic;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.core.message.impl.MessageInternal;
|
import org.apache.activemq.artemis.core.message.impl.MessageInternal;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMapMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSObjectMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSTextMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPIllegalStateException;
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPIllegalStateException;
|
||||||
|
import org.apache.activemq.artemis.reader.MessageUtil;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
import org.apache.qpid.proton.amqp.Binary;
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
import org.apache.qpid.proton.amqp.Symbol;
|
import org.apache.qpid.proton.amqp.Symbol;
|
||||||
import org.apache.qpid.proton.amqp.UnsignedByte;
|
import org.apache.qpid.proton.amqp.UnsignedByte;
|
||||||
|
@ -54,12 +85,16 @@ import org.apache.qpid.proton.amqp.messaging.Header;
|
||||||
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
||||||
import org.apache.qpid.proton.amqp.messaging.Properties;
|
import org.apache.qpid.proton.amqp.messaging.Properties;
|
||||||
import org.apache.qpid.proton.amqp.messaging.Section;
|
import org.apache.qpid.proton.amqp.messaging.Section;
|
||||||
import org.apache.qpid.proton.message.ProtonJMessage;
|
import org.apache.qpid.proton.codec.AMQPDefinedTypes;
|
||||||
|
import org.apache.qpid.proton.codec.DecoderImpl;
|
||||||
|
import org.apache.qpid.proton.codec.EncoderImpl;
|
||||||
|
import org.apache.qpid.proton.codec.WritableBuffer;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
public class JMSMappingOutboundTransformer extends OutboundTransformer {
|
public class JMSMappingOutboundTransformer extends OutboundTransformer {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(JMSMappingOutboundTransformer.class);
|
private static final Logger logger = Logger.getLogger(JMSMappingOutboundTransformer.class);
|
||||||
|
|
||||||
public static final Symbol JMS_DEST_TYPE_MSG_ANNOTATION = Symbol.valueOf("x-opt-jms-dest");
|
public static final Symbol JMS_DEST_TYPE_MSG_ANNOTATION = Symbol.valueOf("x-opt-jms-dest");
|
||||||
public static final Symbol JMS_REPLY_TO_TYPE_MSG_ANNOTATION = Symbol.valueOf("x-opt-jms-reply-to");
|
public static final Symbol JMS_REPLY_TO_TYPE_MSG_ANNOTATION = Symbol.valueOf("x-opt-jms-reply-to");
|
||||||
|
|
||||||
|
@ -68,51 +103,340 @@ public class JMSMappingOutboundTransformer extends OutboundTransformer {
|
||||||
public static final byte TEMP_QUEUE_TYPE = 0x02;
|
public static final byte TEMP_QUEUE_TYPE = 0x02;
|
||||||
public static final byte TEMP_TOPIC_TYPE = 0x03;
|
public static final byte TEMP_TOPIC_TYPE = 0x03;
|
||||||
|
|
||||||
public JMSMappingOutboundTransformer(JMSVendor vendor) {
|
// For now Proton requires that we create a decoder to create an encoder
|
||||||
super(vendor);
|
private static class EncoderDecoderPair {
|
||||||
|
DecoderImpl decoder = new DecoderImpl();
|
||||||
|
EncoderImpl encoder = new EncoderImpl(decoder);
|
||||||
|
{
|
||||||
|
AMQPDefinedTypes.registerAllTypes(decoder, encoder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static final ThreadLocal<EncoderDecoderPair> tlsCodec = new ThreadLocal<EncoderDecoderPair>() {
|
||||||
* Perform the conversion between JMS Message and Proton Message without
|
@Override
|
||||||
* re-encoding it to array. This is needed because some frameworks may elect
|
protected EncoderDecoderPair initialValue() {
|
||||||
* to do this on their own way (Netty for instance using Nettybuffers)
|
return new EncoderDecoderPair();
|
||||||
*
|
|
||||||
* @param msg
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public ProtonJMessage convert(Message msg) throws JMSException, UnsupportedEncodingException {
|
|
||||||
Header header = new Header();
|
|
||||||
Properties props = new Properties();
|
|
||||||
HashMap<Symbol, Object> daMap = null;
|
|
||||||
HashMap<Symbol, Object> maMap = null;
|
|
||||||
HashMap apMap = null;
|
|
||||||
Section body = null;
|
|
||||||
HashMap footerMap = null;
|
|
||||||
if (msg instanceof BytesMessage) {
|
|
||||||
BytesMessage m = (BytesMessage) msg;
|
|
||||||
byte[] data = new byte[(int) m.getBodyLength()];
|
|
||||||
m.readBytes(data);
|
|
||||||
m.reset(); // Need to reset after readBytes or future readBytes
|
|
||||||
// calls (ex: redeliveries) will fail and return -1
|
|
||||||
body = new Data(new Binary(data));
|
|
||||||
}
|
}
|
||||||
if (msg instanceof TextMessage) {
|
};
|
||||||
body = new AmqpValue(((TextMessage) msg).getText());
|
|
||||||
|
public JMSMappingOutboundTransformer(IDGenerator idGenerator) {
|
||||||
|
super(idGenerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long transform(ServerJMSMessage message, WritableBuffer buffer) throws JMSException, UnsupportedEncodingException {
|
||||||
|
if (message == null) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (msg instanceof MapMessage) {
|
|
||||||
final HashMap<String, Object> map = new HashMap<>();
|
long messageFormat = 0;
|
||||||
final MapMessage m = (MapMessage) msg;
|
Header header = null;
|
||||||
final Enumeration<String> names = m.getMapNames();
|
Properties properties = null;
|
||||||
while (names.hasMoreElements()) {
|
Map<Symbol, Object> daMap = null;
|
||||||
String key = names.nextElement();
|
Map<Symbol, Object> maMap = null;
|
||||||
map.put(key, m.getObject(key));
|
Map<String, Object> apMap = null;
|
||||||
|
Map<Object, Object> footerMap = null;
|
||||||
|
|
||||||
|
Section body = convertBody(message);
|
||||||
|
|
||||||
|
if (message.getInnerMessage().isDurable()) {
|
||||||
|
if (header == null) {
|
||||||
|
header = new Header();
|
||||||
}
|
}
|
||||||
body = new AmqpValue(map);
|
header.setDurable(true);
|
||||||
}
|
}
|
||||||
if (msg instanceof StreamMessage) {
|
byte priority = (byte) message.getJMSPriority();
|
||||||
|
if (priority != Message.DEFAULT_PRIORITY) {
|
||||||
|
if (header == null) {
|
||||||
|
header = new Header();
|
||||||
|
}
|
||||||
|
header.setPriority(UnsignedByte.valueOf(priority));
|
||||||
|
}
|
||||||
|
String type = message.getJMSType();
|
||||||
|
if (type != null) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setSubject(type);
|
||||||
|
}
|
||||||
|
String messageId = message.getJMSMessageID();
|
||||||
|
if (messageId != null) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
properties.setMessageId(AMQPMessageIdHelper.INSTANCE.toIdObject(messageId));
|
||||||
|
} catch (ActiveMQAMQPIllegalStateException e) {
|
||||||
|
properties.setMessageId(messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Destination destination = message.getJMSDestination();
|
||||||
|
if (destination != null) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setTo(toAddress(destination));
|
||||||
|
if (maMap == null) {
|
||||||
|
maMap = new HashMap<Symbol, Object>();
|
||||||
|
}
|
||||||
|
maMap.put(JMS_DEST_TYPE_MSG_ANNOTATION, destinationType(destination));
|
||||||
|
}
|
||||||
|
Destination replyTo = message.getJMSReplyTo();
|
||||||
|
if (replyTo != null) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setReplyTo(toAddress(replyTo));
|
||||||
|
if (maMap == null) {
|
||||||
|
maMap = new HashMap<Symbol, Object>();
|
||||||
|
}
|
||||||
|
maMap.put(JMS_REPLY_TO_TYPE_MSG_ANNOTATION, destinationType(replyTo));
|
||||||
|
}
|
||||||
|
String correlationId = message.getJMSCorrelationID();
|
||||||
|
if (correlationId != null) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
properties.setCorrelationId(AMQPMessageIdHelper.INSTANCE.toIdObject(correlationId));
|
||||||
|
} catch (ActiveMQAMQPIllegalStateException e) {
|
||||||
|
properties.setCorrelationId(correlationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long expiration = message.getJMSExpiration();
|
||||||
|
if (expiration != 0) {
|
||||||
|
long ttl = expiration - System.currentTimeMillis();
|
||||||
|
if (ttl < 0) {
|
||||||
|
ttl = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header == null) {
|
||||||
|
header = new Header();
|
||||||
|
}
|
||||||
|
header.setTtl(new UnsignedInteger((int) ttl));
|
||||||
|
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setAbsoluteExpiryTime(new Date(expiration));
|
||||||
|
}
|
||||||
|
long timeStamp = message.getJMSTimestamp();
|
||||||
|
if (timeStamp != 0) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setCreationTime(new Date(timeStamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<String> keySet = MessageUtil.getPropertyNames(message.getInnerMessage());
|
||||||
|
for (String key : keySet) {
|
||||||
|
if (key.startsWith("JMSX")) {
|
||||||
|
if (key.equals("JMSXDeliveryCount")) {
|
||||||
|
// The AMQP delivery-count field only includes prior failed delivery attempts,
|
||||||
|
// whereas JMSXDeliveryCount includes the first/current delivery attempt.
|
||||||
|
int amqpDeliveryCount = message.getDeliveryCount() - 1;
|
||||||
|
if (amqpDeliveryCount > 0) {
|
||||||
|
if (header == null) {
|
||||||
|
header = new Header();
|
||||||
|
}
|
||||||
|
header.setDeliveryCount(new UnsignedInteger(amqpDeliveryCount));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (key.equals("JMSXUserID")) {
|
||||||
|
String value = message.getStringProperty(key);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setUserId(new Binary(value.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
continue;
|
||||||
|
} else if (key.equals("JMSXGroupID")) {
|
||||||
|
String value = message.getStringProperty(key);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setGroupId(value);
|
||||||
|
continue;
|
||||||
|
} else if (key.equals("JMSXGroupSeq")) {
|
||||||
|
UnsignedInteger value = new UnsignedInteger(message.getIntProperty(key));
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setGroupSequence(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (key.startsWith(JMS_AMQP_PREFIX)) {
|
||||||
|
// AMQP Message Information stored from a conversion to the Core Message
|
||||||
|
if (key.equals(JMS_AMQP_MESSAGE_FORMAT)) {
|
||||||
|
messageFormat = message.getLongProperty(JMS_AMQP_MESSAGE_FORMAT);
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(JMS_AMQP_NATIVE)) {
|
||||||
|
// skip..internal use only
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(JMS_AMQP_ORIGINAL_ENCODING)) {
|
||||||
|
// skip..internal use only
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(JMS_AMQP_FIRST_ACQUIRER)) {
|
||||||
|
if (header == null) {
|
||||||
|
header = new Header();
|
||||||
|
}
|
||||||
|
header.setFirstAcquirer(message.getBooleanProperty(key));
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(JMS_AMQP_HEADER)) {
|
||||||
|
if (header == null) {
|
||||||
|
header = new Header();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (key.startsWith(JMS_AMQP_PROPERTIES)) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (key.startsWith(JMS_AMQP_DELIVERY_ANNOTATION_PREFIX)) {
|
||||||
|
if (daMap == null) {
|
||||||
|
daMap = new HashMap<Symbol, Object>();
|
||||||
|
}
|
||||||
|
String name = key.substring(JMS_AMQP_DELIVERY_ANNOTATION_PREFIX.length());
|
||||||
|
daMap.put(Symbol.valueOf(name), message.getObjectProperty(key));
|
||||||
|
continue;
|
||||||
|
} else if (key.startsWith(JMS_AMQP_MESSAGE_ANNOTATION_PREFIX)) {
|
||||||
|
if (maMap == null) {
|
||||||
|
maMap = new HashMap<Symbol, Object>();
|
||||||
|
}
|
||||||
|
String name = key.substring(JMS_AMQP_MESSAGE_ANNOTATION_PREFIX.length());
|
||||||
|
maMap.put(Symbol.valueOf(name), message.getObjectProperty(key));
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(JMS_AMQP_CONTENT_TYPE)) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setContentType(Symbol.getSymbol(message.getStringProperty(key)));
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(JMS_AMQP_CONTENT_ENCODING)) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setContentEncoding(Symbol.getSymbol(message.getStringProperty(key)));
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(JMS_AMQP_REPLYTO_GROUP_ID)) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setReplyToGroupId(message.getStringProperty(key));
|
||||||
|
continue;
|
||||||
|
} else if (key.startsWith(JMS_AMQP_FOOTER_PREFIX)) {
|
||||||
|
if (footerMap == null) {
|
||||||
|
footerMap = new HashMap<Object, Object>();
|
||||||
|
}
|
||||||
|
String name = key.substring(JMS_AMQP_FOOTER_PREFIX.length());
|
||||||
|
footerMap.put(name, message.getObjectProperty(key));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (key.equals("_AMQ_GROUP_ID")) {
|
||||||
|
String value = message.getStringProperty(key);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new Properties();
|
||||||
|
}
|
||||||
|
properties.setGroupId(value);
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(ServerJMSMessage.NATIVE_MESSAGE_ID)) {
|
||||||
|
// skip..internal use only
|
||||||
|
continue;
|
||||||
|
} else if (key.endsWith(HDR_SCHEDULED_DELIVERY_TIME.toString())) {
|
||||||
|
// skip..remove annotation from previous inbound transformation
|
||||||
|
continue;
|
||||||
|
} else if (key.equals(AMQPMessageTypes.AMQP_TYPE_KEY)) {
|
||||||
|
// skip..internal use only - TODO - Remove this deprecated value in future release.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apMap == null) {
|
||||||
|
apMap = new HashMap<String, Object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object objectProperty = message.getObjectProperty(key);
|
||||||
|
if (objectProperty instanceof byte[]) {
|
||||||
|
objectProperty = new Binary((byte[]) objectProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
apMap.put(key, objectProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
EncoderImpl encoder = tlsCodec.get().encoder;
|
||||||
|
encoder.setByteBuffer(buffer);
|
||||||
|
|
||||||
|
if (header != null) {
|
||||||
|
encoder.writeObject(header);
|
||||||
|
}
|
||||||
|
if (daMap != null) {
|
||||||
|
encoder.writeObject(new DeliveryAnnotations(daMap));
|
||||||
|
}
|
||||||
|
if (maMap != null) {
|
||||||
|
encoder.writeObject(new MessageAnnotations(maMap));
|
||||||
|
}
|
||||||
|
if (properties != null) {
|
||||||
|
encoder.writeObject(properties);
|
||||||
|
}
|
||||||
|
if (apMap != null) {
|
||||||
|
encoder.writeObject(new ApplicationProperties(apMap));
|
||||||
|
}
|
||||||
|
if (body != null) {
|
||||||
|
encoder.writeObject(body);
|
||||||
|
}
|
||||||
|
if (footerMap != null) {
|
||||||
|
encoder.writeObject(new Footer(footerMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Section convertBody(ServerJMSMessage message) throws JMSException {
|
||||||
|
|
||||||
|
Section body = null;
|
||||||
|
short orignalEncoding = AMQP_UNKNOWN;
|
||||||
|
|
||||||
|
try {
|
||||||
|
orignalEncoding = message.getShortProperty(JMS_AMQP_ORIGINAL_ENCODING);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// Ignore and stick with UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message instanceof ServerJMSBytesMessage) {
|
||||||
|
Binary payload = getBinaryFromMessageBody((ServerJMSBytesMessage) message);
|
||||||
|
|
||||||
|
if (payload == null) {
|
||||||
|
payload = EMPTY_BINARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (orignalEncoding) {
|
||||||
|
case AMQP_NULL:
|
||||||
|
break;
|
||||||
|
case AMQP_VALUE_BINARY:
|
||||||
|
body = new AmqpValue(payload);
|
||||||
|
break;
|
||||||
|
case AMQP_DATA:
|
||||||
|
case AMQP_UNKNOWN:
|
||||||
|
default:
|
||||||
|
body = new Data(payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (message instanceof ServerJMSTextMessage) {
|
||||||
|
switch (orignalEncoding) {
|
||||||
|
case AMQP_NULL:
|
||||||
|
break;
|
||||||
|
case AMQP_DATA:
|
||||||
|
body = new Data(getBinaryFromMessageBody((ServerJMSTextMessage) message));
|
||||||
|
break;
|
||||||
|
case AMQP_VALUE_STRING:
|
||||||
|
case AMQP_UNKNOWN:
|
||||||
|
default:
|
||||||
|
body = new AmqpValue(((TextMessage) message).getText());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (message instanceof ServerJMSMapMessage) {
|
||||||
|
body = new AmqpValue(getMapFromMessageBody((ServerJMSMapMessage) message));
|
||||||
|
} else if (message instanceof ServerJMSStreamMessage) {
|
||||||
ArrayList<Object> list = new ArrayList<>();
|
ArrayList<Object> list = new ArrayList<>();
|
||||||
final StreamMessage m = (StreamMessage) msg;
|
final ServerJMSStreamMessage m = (ServerJMSStreamMessage) message;
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
list.add(m.readObject());
|
list.add(m.readObject());
|
||||||
|
@ -120,21 +444,58 @@ public class JMSMappingOutboundTransformer extends OutboundTransformer {
|
||||||
} catch (MessageEOFException e) {
|
} catch (MessageEOFException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
String amqpType = msg.getStringProperty(AMQPMessageTypes.AMQP_TYPE_KEY);
|
// Deprecated encoding markers - TODO - Remove on future release
|
||||||
if (amqpType.equals(AMQPMessageTypes.AMQP_LIST)) {
|
if (orignalEncoding == AMQP_UNKNOWN) {
|
||||||
body = new AmqpValue(list);
|
String amqpType = message.getStringProperty(AMQPMessageTypes.AMQP_TYPE_KEY);
|
||||||
} else {
|
if (amqpType != null) {
|
||||||
body = new AmqpSequence(list);
|
if (amqpType.equals(AMQPMessageTypes.AMQP_LIST)) {
|
||||||
|
orignalEncoding = AMQP_VALUE_LIST;
|
||||||
|
} else {
|
||||||
|
orignalEncoding = AMQP_SEQUENCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (msg instanceof ObjectMessage) {
|
|
||||||
body = new AmqpValue(((ObjectMessage) msg).getObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body == null && msg instanceof ServerJMSMessage) {
|
switch (orignalEncoding) {
|
||||||
|
case AMQP_SEQUENCE:
|
||||||
|
body = new AmqpSequence(list);
|
||||||
|
break;
|
||||||
|
case AMQP_VALUE_LIST:
|
||||||
|
case AMQP_UNKNOWN:
|
||||||
|
default:
|
||||||
|
body = new AmqpValue(list);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (message instanceof ServerJMSObjectMessage) {
|
||||||
|
Binary payload = getBinaryFromMessageBody((ServerJMSObjectMessage) message);
|
||||||
|
|
||||||
MessageInternal internalMessage = ((ServerJMSMessage) msg).getInnerMessage();
|
if (payload == null) {
|
||||||
if (!internalMessage.containsProperty("AMQP_MESSAGE_FORMAT")) {
|
payload = EMPTY_BINARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (orignalEncoding) {
|
||||||
|
case AMQP_VALUE_BINARY:
|
||||||
|
body = new AmqpValue(payload);
|
||||||
|
break;
|
||||||
|
case AMQP_DATA:
|
||||||
|
case AMQP_UNKNOWN:
|
||||||
|
default:
|
||||||
|
body = new Data(payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For a non-AMQP message we tag the outbound content type as containing
|
||||||
|
// a serialized Java object so that an AMQP client has a hint as to what
|
||||||
|
// we are sending it.
|
||||||
|
if (!message.propertyExists(JMS_AMQP_CONTENT_TYPE)) {
|
||||||
|
message.setStringProperty(JMS_AMQP_CONTENT_TYPE, SERIALIZED_JAVA_OBJECT_CONTENT_TYPE);
|
||||||
|
}
|
||||||
|
} else if (message instanceof ServerJMSMessage) {
|
||||||
|
// If this is not an AMQP message that was converted then the original encoding
|
||||||
|
// will be unknown so we check for special cases of messages with special data
|
||||||
|
// encoded into the server message body.
|
||||||
|
if (orignalEncoding == AMQP_UNKNOWN) {
|
||||||
|
MessageInternal internalMessage = message.getInnerMessage();
|
||||||
int readerIndex = internalMessage.getBodyBuffer().readerIndex();
|
int readerIndex = internalMessage.getBodyBuffer().readerIndex();
|
||||||
try {
|
try {
|
||||||
Object s = internalMessage.getBodyBuffer().readNullableSimpleString();
|
Object s = internalMessage.getBodyBuffer().readNullableSimpleString();
|
||||||
|
@ -149,146 +510,51 @@ public class JMSMappingOutboundTransformer extends OutboundTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header.setDurable(msg.getJMSDeliveryMode() == DeliveryMode.PERSISTENT ? true : false);
|
return body;
|
||||||
header.setPriority(new UnsignedByte((byte) msg.getJMSPriority()));
|
}
|
||||||
if (msg.getJMSType() != null) {
|
|
||||||
props.setSubject(msg.getJMSType());
|
private Binary getBinaryFromMessageBody(ServerJMSBytesMessage message) throws JMSException {
|
||||||
|
byte[] data = new byte[(int) message.getBodyLength()];
|
||||||
|
message.readBytes(data);
|
||||||
|
message.reset(); // Need to reset after readBytes or future readBytes
|
||||||
|
|
||||||
|
return new Binary(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Binary getBinaryFromMessageBody(ServerJMSTextMessage message) throws JMSException {
|
||||||
|
Binary result = null;
|
||||||
|
String text = message.getText();
|
||||||
|
if (text != null) {
|
||||||
|
result = new Binary(text.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
if (msg.getJMSMessageID() != null) {
|
|
||||||
|
|
||||||
String msgId = msg.getJMSMessageID();
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private Binary getBinaryFromMessageBody(ServerJMSObjectMessage message) throws JMSException {
|
||||||
props.setMessageId(AMQPMessageIdHelper.INSTANCE.toIdObject(msgId));
|
message.getInnerMessage().getBodyBuffer().resetReaderIndex();
|
||||||
} catch (ActiveMQAMQPIllegalStateException e) {
|
int size = message.getInnerMessage().getBodyBuffer().readInt();
|
||||||
props.setMessageId(msgId);
|
byte[] bytes = new byte[size];
|
||||||
|
message.getInnerMessage().getBodyBuffer().readBytes(bytes);
|
||||||
|
|
||||||
|
return new Binary(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getMapFromMessageBody(ServerJMSMapMessage message) throws JMSException {
|
||||||
|
final HashMap<String, Object> map = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final Enumeration<String> names = message.getMapNames();
|
||||||
|
while (names.hasMoreElements()) {
|
||||||
|
String key = names.nextElement();
|
||||||
|
Object value = message.getObject(key);
|
||||||
|
if (value instanceof byte[]) {
|
||||||
|
value = new Binary((byte[]) value);
|
||||||
}
|
}
|
||||||
}
|
map.put(key, value);
|
||||||
if (msg.getJMSDestination() != null) {
|
|
||||||
props.setTo(vendor.toAddress(msg.getJMSDestination()));
|
|
||||||
if (maMap == null) {
|
|
||||||
maMap = new HashMap<>();
|
|
||||||
}
|
|
||||||
maMap.put(JMS_DEST_TYPE_MSG_ANNOTATION, destinationType(msg.getJMSDestination()));
|
|
||||||
}
|
|
||||||
if (msg.getJMSReplyTo() != null) {
|
|
||||||
props.setReplyTo(vendor.toAddress(msg.getJMSReplyTo()));
|
|
||||||
if (maMap == null) {
|
|
||||||
maMap = new HashMap<>();
|
|
||||||
}
|
|
||||||
maMap.put(JMS_REPLY_TO_TYPE_MSG_ANNOTATION, destinationType(msg.getJMSReplyTo()));
|
|
||||||
}
|
|
||||||
if (msg.getJMSCorrelationID() != null) {
|
|
||||||
String correlationId = msg.getJMSCorrelationID();
|
|
||||||
|
|
||||||
try {
|
|
||||||
props.setCorrelationId(AMQPMessageIdHelper.INSTANCE.toIdObject(correlationId));
|
|
||||||
} catch (ActiveMQAMQPIllegalStateException e) {
|
|
||||||
props.setCorrelationId(correlationId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (msg.getJMSExpiration() != 0) {
|
|
||||||
long ttl = msg.getJMSExpiration() - System.currentTimeMillis();
|
|
||||||
if (ttl < 0) {
|
|
||||||
ttl = 1;
|
|
||||||
}
|
|
||||||
header.setTtl(new UnsignedInteger((int) ttl));
|
|
||||||
|
|
||||||
props.setAbsoluteExpiryTime(new Date(msg.getJMSExpiration()));
|
|
||||||
}
|
|
||||||
if (msg.getJMSTimestamp() != 0) {
|
|
||||||
props.setCreationTime(new Date(msg.getJMSTimestamp()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final Enumeration<String> keys = msg.getPropertyNames();
|
return map;
|
||||||
while (keys.hasMoreElements()) {
|
|
||||||
String key = keys.nextElement();
|
|
||||||
if (key.equals(messageFormatKey) || key.equals(nativeKey) || key.equals(ServerJMSMessage.NATIVE_MESSAGE_ID)) {
|
|
||||||
// skip..
|
|
||||||
} else if (key.equals(firstAcquirerKey)) {
|
|
||||||
header.setFirstAcquirer(msg.getBooleanProperty(key));
|
|
||||||
} else if (key.startsWith("JMSXDeliveryCount")) {
|
|
||||||
// The AMQP delivery-count field only includes prior failed delivery attempts,
|
|
||||||
// whereas JMSXDeliveryCount includes the first/current delivery attempt.
|
|
||||||
int amqpDeliveryCount = msg.getIntProperty(key) - 1;
|
|
||||||
if (amqpDeliveryCount > 0) {
|
|
||||||
header.setDeliveryCount(new UnsignedInteger(amqpDeliveryCount));
|
|
||||||
}
|
|
||||||
} else if (key.startsWith("JMSXUserID")) {
|
|
||||||
String value = msg.getStringProperty(key);
|
|
||||||
props.setUserId(new Binary(value.getBytes(StandardCharsets.UTF_8)));
|
|
||||||
} else if (key.startsWith("JMSXGroupID") || key.startsWith("_AMQ_GROUP_ID")) {
|
|
||||||
String value = msg.getStringProperty(key);
|
|
||||||
props.setGroupId(value);
|
|
||||||
if (apMap == null) {
|
|
||||||
apMap = new HashMap();
|
|
||||||
}
|
|
||||||
apMap.put(key, value);
|
|
||||||
} else if (key.startsWith("JMSXGroupSeq")) {
|
|
||||||
UnsignedInteger value = new UnsignedInteger(msg.getIntProperty(key));
|
|
||||||
props.setGroupSequence(value);
|
|
||||||
if (apMap == null) {
|
|
||||||
apMap = new HashMap();
|
|
||||||
}
|
|
||||||
apMap.put(key, value);
|
|
||||||
} else if (key.startsWith(prefixDeliveryAnnotationsKey)) {
|
|
||||||
if (daMap == null) {
|
|
||||||
daMap = new HashMap<>();
|
|
||||||
}
|
|
||||||
String name = key.substring(prefixDeliveryAnnotationsKey.length());
|
|
||||||
daMap.put(Symbol.valueOf(name), msg.getObjectProperty(key));
|
|
||||||
} else if (key.startsWith(prefixMessageAnnotationsKey)) {
|
|
||||||
if (maMap == null) {
|
|
||||||
maMap = new HashMap<>();
|
|
||||||
}
|
|
||||||
String name = key.substring(prefixMessageAnnotationsKey.length());
|
|
||||||
maMap.put(Symbol.valueOf(name), msg.getObjectProperty(key));
|
|
||||||
} else if (key.equals(contentTypeKey)) {
|
|
||||||
props.setContentType(Symbol.getSymbol(msg.getStringProperty(key)));
|
|
||||||
} else if (key.equals(contentEncodingKey)) {
|
|
||||||
props.setContentEncoding(Symbol.getSymbol(msg.getStringProperty(key)));
|
|
||||||
} else if (key.equals(replyToGroupIDKey)) {
|
|
||||||
props.setReplyToGroupId(msg.getStringProperty(key));
|
|
||||||
} else if (key.startsWith(prefixFooterKey)) {
|
|
||||||
if (footerMap == null) {
|
|
||||||
footerMap = new HashMap();
|
|
||||||
}
|
|
||||||
String name = key.substring(prefixFooterKey.length());
|
|
||||||
footerMap.put(name, msg.getObjectProperty(key));
|
|
||||||
} else if (key.equals(AMQPMessageTypes.AMQP_TYPE_KEY)) {
|
|
||||||
// skip
|
|
||||||
} else {
|
|
||||||
if (apMap == null) {
|
|
||||||
apMap = new HashMap();
|
|
||||||
}
|
|
||||||
Object objectProperty = msg.getObjectProperty(key);
|
|
||||||
if (objectProperty instanceof byte[]) {
|
|
||||||
Binary binary = new Binary((byte[]) objectProperty);
|
|
||||||
apMap.put(key, binary);
|
|
||||||
} else {
|
|
||||||
apMap.put(key, objectProperty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageAnnotations ma = null;
|
|
||||||
if (maMap != null) {
|
|
||||||
ma = new MessageAnnotations(maMap);
|
|
||||||
}
|
|
||||||
DeliveryAnnotations da = null;
|
|
||||||
if (daMap != null) {
|
|
||||||
da = new DeliveryAnnotations(daMap);
|
|
||||||
}
|
|
||||||
ApplicationProperties ap = null;
|
|
||||||
if (apMap != null) {
|
|
||||||
ap = new ApplicationProperties(apMap);
|
|
||||||
}
|
|
||||||
Footer footer = null;
|
|
||||||
if (footerMap != null) {
|
|
||||||
footer = new Footer(footerMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create(header, da, ma, props, ap, body, footer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte destinationType(Destination destination) {
|
private static byte destinationType(Destination destination) {
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
/**
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
* <p>
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* <p>
|
|
||||||
* 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.protocol.amqp.converter.message;
|
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
|
||||||
import javax.jms.Destination;
|
|
||||||
import javax.jms.MapMessage;
|
|
||||||
import javax.jms.Message;
|
|
||||||
import javax.jms.ObjectMessage;
|
|
||||||
import javax.jms.StreamMessage;
|
|
||||||
import javax.jms.TextMessage;
|
|
||||||
|
|
||||||
public interface JMSVendor {
|
|
||||||
|
|
||||||
BytesMessage createBytesMessage();
|
|
||||||
|
|
||||||
StreamMessage createStreamMessage();
|
|
||||||
|
|
||||||
Message createMessage();
|
|
||||||
|
|
||||||
TextMessage createTextMessage();
|
|
||||||
|
|
||||||
ObjectMessage createObjectMessage();
|
|
||||||
|
|
||||||
MapMessage createMapMessage();
|
|
||||||
|
|
||||||
void setJMSXUserID(Message message, String value);
|
|
||||||
|
|
||||||
Destination createDestination(String name);
|
|
||||||
|
|
||||||
void setJMSXGroupID(Message message, String groupId);
|
|
||||||
|
|
||||||
void setJMSXGroupSequence(Message message, int value);
|
|
||||||
|
|
||||||
void setJMSXDeliveryCount(Message message, long value);
|
|
||||||
|
|
||||||
String toAddress(Destination destination);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,13 +1,13 @@
|
||||||
/**
|
/*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
* this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
* 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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
* the License. You may obtain a copy of the License at
|
||||||
* <p>
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* <p>
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,54 +16,36 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
package org.apache.activemq.artemis.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
import javax.jms.JMSException;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
import org.apache.qpid.proton.codec.WritableBuffer;
|
||||||
|
|
||||||
public abstract class OutboundTransformer {
|
public abstract class OutboundTransformer {
|
||||||
|
|
||||||
JMSVendor vendor;
|
protected IDGenerator idGenerator;
|
||||||
String prefixVendor;
|
|
||||||
|
|
||||||
String prefixDeliveryAnnotations = "DA_";
|
public OutboundTransformer(IDGenerator idGenerator) {
|
||||||
String prefixMessageAnnotations = "MA_";
|
this.idGenerator = idGenerator;
|
||||||
String prefixFooter = "FT_";
|
|
||||||
|
|
||||||
String messageFormatKey;
|
|
||||||
String nativeKey;
|
|
||||||
String firstAcquirerKey;
|
|
||||||
String prefixDeliveryAnnotationsKey;
|
|
||||||
String prefixMessageAnnotationsKey;
|
|
||||||
String contentTypeKey;
|
|
||||||
String contentEncodingKey;
|
|
||||||
String replyToGroupIDKey;
|
|
||||||
String prefixFooterKey;
|
|
||||||
|
|
||||||
public OutboundTransformer(JMSVendor vendor) {
|
|
||||||
this.vendor = vendor;
|
|
||||||
this.setPrefixVendor("JMS_AMQP_");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPrefixVendor() {
|
/**
|
||||||
return prefixVendor;
|
* Given an JMS Message perform a conversion to an AMQP Message and encode into a form that
|
||||||
}
|
* is ready for transmission.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message to transform
|
||||||
|
* @param buffer
|
||||||
|
* the buffer where encoding should write to
|
||||||
|
*
|
||||||
|
* @return the message format key of the encoded message.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during message transformation
|
||||||
|
*/
|
||||||
|
public abstract long transform(ServerJMSMessage message, WritableBuffer buffer) throws JMSException, UnsupportedEncodingException;
|
||||||
|
|
||||||
public void setPrefixVendor(String prefixVendor) {
|
|
||||||
this.prefixVendor = prefixVendor;
|
|
||||||
|
|
||||||
messageFormatKey = prefixVendor + "MESSAGE_FORMAT";
|
|
||||||
nativeKey = prefixVendor + "NATIVE";
|
|
||||||
firstAcquirerKey = prefixVendor + "FirstAcquirer";
|
|
||||||
prefixDeliveryAnnotationsKey = prefixVendor + prefixDeliveryAnnotations;
|
|
||||||
prefixMessageAnnotationsKey = prefixVendor + prefixMessageAnnotations;
|
|
||||||
contentTypeKey = prefixVendor + "ContentType";
|
|
||||||
contentEncodingKey = prefixVendor + "ContentEncoding";
|
|
||||||
replyToGroupIDKey = prefixVendor + "ReplyToGroupID";
|
|
||||||
prefixFooterKey = prefixVendor + prefixFooter;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public JMSVendor getVendor() {
|
|
||||||
return vendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVendor(JMSVendor vendor) {
|
|
||||||
this.vendor = vendor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.exceptions;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
|
||||||
|
import org.apache.qpid.proton.amqp.transport.AmqpError;
|
||||||
|
|
||||||
|
public class ActiveMQAMQPInvalidContentTypeException extends ActiveMQAMQPException {
|
||||||
|
|
||||||
|
public ActiveMQAMQPInvalidContentTypeException(String message) {
|
||||||
|
super(AmqpError.INTERNAL_ERROR, message, ActiveMQExceptionType.INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,8 +19,6 @@ package org.apache.activemq.artemis.protocol.amqp.proton;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.buffer.PooledByteBufAllocator;
|
|
||||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
import org.apache.activemq.artemis.core.server.QueueQueryResult;
|
import org.apache.activemq.artemis.core.server.QueueQueryResult;
|
||||||
import org.apache.activemq.artemis.core.transaction.Transaction;
|
import org.apache.activemq.artemis.core.transaction.Transaction;
|
||||||
|
@ -52,9 +50,11 @@ import org.apache.qpid.proton.amqp.transport.ErrorCondition;
|
||||||
import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
|
import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
|
||||||
import org.apache.qpid.proton.engine.Delivery;
|
import org.apache.qpid.proton.engine.Delivery;
|
||||||
import org.apache.qpid.proton.engine.Sender;
|
import org.apache.qpid.proton.engine.Sender;
|
||||||
import org.apache.qpid.proton.message.ProtonJMessage;
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
|
||||||
public class ProtonServerSenderContext extends ProtonInitializable implements ProtonDeliveryHandler {
|
public class ProtonServerSenderContext extends ProtonInitializable implements ProtonDeliveryHandler {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(ProtonServerSenderContext.class);
|
private static final Logger log = Logger.getLogger(ProtonServerSenderContext.class);
|
||||||
|
@ -407,33 +407,6 @@ public class ProtonServerSenderContext extends ProtonInitializable implements Pr
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//encode the message
|
|
||||||
ProtonJMessage serverMessage;
|
|
||||||
try {
|
|
||||||
// This can be done a lot better here
|
|
||||||
serverMessage = sessionSPI.encodeMessage(message, deliveryCount);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
log.warn(e.getMessage(), e);
|
|
||||||
throw new ActiveMQAMQPInternalErrorException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return performSend(serverMessage, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasCapabilities(Symbol symbol, Source source) {
|
|
||||||
if (source != null) {
|
|
||||||
if (source.getCapabilities() != null) {
|
|
||||||
for (Symbol cap : source.getCapabilities()) {
|
|
||||||
if (symbol.equals(cap)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int performSend(ProtonJMessage serverMessage, Object context) {
|
|
||||||
if (!creditsSemaphore.tryAcquire()) {
|
if (!creditsSemaphore.tryAcquire()) {
|
||||||
try {
|
try {
|
||||||
creditsSemaphore.acquire();
|
creditsSemaphore.acquire();
|
||||||
|
@ -444,22 +417,32 @@ public class ProtonServerSenderContext extends ProtonInitializable implements Pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//presettle means we can ack the message on the dealer side before we send it, i.e. for browsers
|
// presettle means we can settle the message on the dealer side before we send it, i.e. for browsers
|
||||||
boolean preSettle = sender.getRemoteSenderSettleMode() == SenderSettleMode.SETTLED;
|
boolean preSettle = sender.getRemoteSenderSettleMode() == SenderSettleMode.SETTLED;
|
||||||
|
|
||||||
//we only need a tag if we are going to ack later
|
// we only need a tag if we are going to settle later
|
||||||
byte[] tag = preSettle ? new byte[0] : protonSession.getTag();
|
byte[] tag = preSettle ? new byte[0] : protonSession.getTag();
|
||||||
|
|
||||||
ByteBuf nettyBuffer = PooledByteBufAllocator.DEFAULT.heapBuffer(1024);
|
ByteBuf nettyBuffer = PooledByteBufAllocator.DEFAULT.heapBuffer(1024);
|
||||||
try {
|
try {
|
||||||
serverMessage.encode(new NettyWritable(nettyBuffer));
|
long messageFormat = 0;
|
||||||
|
|
||||||
|
// Encode the Server Message into the given Netty Buffer as an AMQP
|
||||||
|
// Message transformed from the internal message model.
|
||||||
|
try {
|
||||||
|
messageFormat = sessionSPI.encodeMessage(message, deliveryCount, new NettyWritable(nettyBuffer));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.warn(e.getMessage(), e);
|
||||||
|
throw new ActiveMQAMQPInternalErrorException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
int size = nettyBuffer.writerIndex();
|
int size = nettyBuffer.writerIndex();
|
||||||
|
|
||||||
synchronized (connection.getLock()) {
|
synchronized (connection.getLock()) {
|
||||||
final Delivery delivery;
|
final Delivery delivery;
|
||||||
delivery = sender.delivery(tag, 0, tag.length);
|
delivery = sender.delivery(tag, 0, tag.length);
|
||||||
delivery.setContext(context);
|
delivery.setMessageFormat((int) messageFormat);
|
||||||
|
delivery.setContext(message);
|
||||||
|
|
||||||
// this will avoid a copy.. patch provided by Norman using buffer.array()
|
// this will avoid a copy.. patch provided by Norman using buffer.array()
|
||||||
sender.send(nettyBuffer.array(), nettyBuffer.arrayOffset() + nettyBuffer.readerIndex(), nettyBuffer.readableBytes());
|
sender.send(nettyBuffer.array(), nettyBuffer.arrayOffset() + nettyBuffer.readerIndex(), nettyBuffer.readableBytes());
|
||||||
|
@ -479,6 +462,19 @@ public class ProtonServerSenderContext extends ProtonInitializable implements Pr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean hasCapabilities(Symbol symbol, Source source) {
|
||||||
|
if (source != null) {
|
||||||
|
if (source.getCapabilities() != null) {
|
||||||
|
for (Symbol cap : source.getCapabilities()) {
|
||||||
|
if (symbol.equals(cap)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static String createQueueName(String clientId, String pubId) {
|
private static String createQueueName(String clientId, String pubId) {
|
||||||
return clientId + "." + pubId;
|
return clientId + "." + pubId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,32 +16,31 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.converter;
|
package org.apache.activemq.artemis.protocol.amqp.converter;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import static org.apache.activemq.artemis.api.core.Message.BYTES_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.MAP_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.STREAM_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.api.core.Message.TEXT_TYPE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.wrapMessage;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.buffer.PooledByteBufAllocator;
|
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
import org.apache.activemq.artemis.core.journal.EncodingSupport;
|
import org.apache.activemq.artemis.core.journal.EncodingSupport;
|
||||||
import org.apache.activemq.artemis.core.server.ServerMessage;
|
import org.apache.activemq.artemis.core.server.ServerMessage;
|
||||||
import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMapMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMapMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSObjectMessage;
|
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSTextMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSTextMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.converter.message.EncodedMessage;
|
import org.apache.activemq.artemis.protocol.amqp.converter.message.EncodedMessage;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.util.NettyWritable;
|
import org.apache.activemq.artemis.protocol.amqp.util.NettyWritable;
|
||||||
import org.apache.activemq.artemis.utils.SimpleIDGenerator;
|
import org.apache.activemq.artemis.utils.SimpleIDGenerator;
|
||||||
import org.apache.blacklist.ABadClass;
|
|
||||||
import org.apache.qpid.proton.amqp.Binary;
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
import org.apache.qpid.proton.amqp.messaging.AmqpSequence;
|
import org.apache.qpid.proton.amqp.messaging.AmqpSequence;
|
||||||
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
||||||
|
@ -53,10 +52,13 @@ import org.apache.qpid.proton.message.impl.MessageImpl;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
|
||||||
public class TestConversions extends Assert {
|
public class TestConversions extends Assert {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testObjectMessageWhiteList() throws Exception {
|
public void testAmqpValueOfBooleanIsPassedThrough() throws Exception {
|
||||||
Map<String, Object> mapprop = createPropertiesMap();
|
Map<String, Object> mapprop = createPropertiesMap();
|
||||||
ApplicationProperties properties = new ApplicationProperties(mapprop);
|
ApplicationProperties properties = new ApplicationProperties(mapprop);
|
||||||
MessageImpl message = (MessageImpl) Message.Factory.create();
|
MessageImpl message = (MessageImpl) Message.Factory.create();
|
||||||
|
@ -73,39 +75,15 @@ public class TestConversions extends Assert {
|
||||||
EncodedMessage encodedMessage = encodeMessage(message);
|
EncodedMessage encodedMessage = encodeMessage(message);
|
||||||
|
|
||||||
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
||||||
ServerJMSObjectMessage serverMessage = (ServerJMSObjectMessage) converter.inboundJMSType(encodedMessage);
|
ServerMessage serverMessage = converter.inbound(encodedMessage);
|
||||||
|
|
||||||
verifyProperties(serverMessage);
|
verifyProperties(new ServerJMSMessage(serverMessage, 0));
|
||||||
|
|
||||||
assertEquals(true, serverMessage.getObject());
|
EncodedMessage encoded = (EncodedMessage) converter.outbound(serverMessage, 0);
|
||||||
|
Message amqpMessage = encoded.decode();
|
||||||
|
|
||||||
Object obj = converter.outbound((ServerMessage) serverMessage.getInnerMessage(), 0);
|
AmqpValue value = (AmqpValue) amqpMessage.getBody();
|
||||||
|
|
||||||
AmqpValue value = (AmqpValue) ((Message) obj).getBody();
|
|
||||||
assertEquals(value.getValue(), true);
|
assertEquals(value.getValue(), true);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testObjectMessageNotOnWhiteList() throws Exception {
|
|
||||||
|
|
||||||
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
|
||||||
ServerMessageImpl message = new ServerMessageImpl(1, 1024);
|
|
||||||
message.setType((byte) 2);
|
|
||||||
ServerJMSObjectMessage serverMessage = new ServerJMSObjectMessage(message, 1024);
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
ObjectOutputStream ois = new ObjectOutputStream(out);
|
|
||||||
ois.writeObject(new ABadClass());
|
|
||||||
byte[] src = out.toByteArray();
|
|
||||||
serverMessage.getInnerMessage().getBodyBuffer().writeInt(src.length);
|
|
||||||
serverMessage.getInnerMessage().getBodyBuffer().writeBytes(src);
|
|
||||||
|
|
||||||
try {
|
|
||||||
converter.outbound((ServerMessage) serverMessage.getInnerMessage(), 0);
|
|
||||||
fail("should throw ClassNotFoundException");
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -126,22 +104,23 @@ public class TestConversions extends Assert {
|
||||||
EncodedMessage encodedMessage = encodeMessage(message);
|
EncodedMessage encodedMessage = encodeMessage(message);
|
||||||
|
|
||||||
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
||||||
ServerJMSBytesMessage serverMessage = (ServerJMSBytesMessage) converter.inboundJMSType(encodedMessage);
|
ServerMessage serverMessage = converter.inbound(encodedMessage);
|
||||||
|
|
||||||
verifyProperties(serverMessage);
|
ServerJMSBytesMessage bytesMessage = (ServerJMSBytesMessage) wrapMessage(BYTES_TYPE, serverMessage, 0);
|
||||||
|
|
||||||
assertEquals(bodyBytes.length, serverMessage.getBodyLength());
|
verifyProperties(bytesMessage);
|
||||||
|
|
||||||
|
assertEquals(bodyBytes.length, bytesMessage.getBodyLength());
|
||||||
|
|
||||||
byte[] newBodyBytes = new byte[4];
|
byte[] newBodyBytes = new byte[4];
|
||||||
|
|
||||||
serverMessage.readBytes(newBodyBytes);
|
bytesMessage.readBytes(newBodyBytes);
|
||||||
|
|
||||||
Assert.assertArrayEquals(bodyBytes, newBodyBytes);
|
Assert.assertArrayEquals(bodyBytes, newBodyBytes);
|
||||||
|
|
||||||
Object obj = converter.outbound((ServerMessage) serverMessage.getInnerMessage(), 0);
|
Object obj = converter.outbound(serverMessage, 0);
|
||||||
|
|
||||||
System.out.println("output = " + obj);
|
System.out.println("output = " + obj);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyProperties(javax.jms.Message message) throws Exception {
|
private void verifyProperties(javax.jms.Message message) throws Exception {
|
||||||
|
@ -175,25 +154,25 @@ public class TestConversions extends Assert {
|
||||||
EncodedMessage encodedMessage = encodeMessage(message);
|
EncodedMessage encodedMessage = encodeMessage(message);
|
||||||
|
|
||||||
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
||||||
ServerJMSMapMessage serverMessage = (ServerJMSMapMessage) converter.inboundJMSType(encodedMessage);
|
ServerMessage serverMessage = converter.inbound(encodedMessage);
|
||||||
|
|
||||||
verifyProperties(serverMessage);
|
ServerJMSMapMessage mapMessage = (ServerJMSMapMessage) wrapMessage(MAP_TYPE, serverMessage, 0);
|
||||||
|
mapMessage.decode();
|
||||||
|
|
||||||
Assert.assertEquals(1, serverMessage.getInt("someint"));
|
verifyProperties(mapMessage);
|
||||||
Assert.assertEquals("value", serverMessage.getString("somestr"));
|
|
||||||
|
|
||||||
Object obj = converter.outbound((ServerMessage) serverMessage.getInnerMessage(), 0);
|
Assert.assertEquals(1, mapMessage.getInt("someint"));
|
||||||
|
Assert.assertEquals("value", mapMessage.getString("somestr"));
|
||||||
|
|
||||||
reEncodeMsg(obj);
|
EncodedMessage encoded = (EncodedMessage) converter.outbound(serverMessage, 0);
|
||||||
|
Message amqpMessage = encoded.decode();
|
||||||
|
|
||||||
MessageImpl outMessage = (MessageImpl) obj;
|
AmqpValue value = (AmqpValue) amqpMessage.getBody();
|
||||||
AmqpValue value = (AmqpValue) outMessage.getBody();
|
Map<?, ?> mapoutput = (Map<?, ?>) value.getValue();
|
||||||
Map mapoutput = (Map) value.getValue();
|
|
||||||
|
|
||||||
assertEquals(Integer.valueOf(1), mapoutput.get("someint"));
|
assertEquals(Integer.valueOf(1), mapoutput.get("someint"));
|
||||||
|
|
||||||
System.out.println("output = " + obj);
|
System.out.println("output = " + amqpMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -212,26 +191,25 @@ public class TestConversions extends Assert {
|
||||||
EncodedMessage encodedMessage = encodeMessage(message);
|
EncodedMessage encodedMessage = encodeMessage(message);
|
||||||
|
|
||||||
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
||||||
ServerJMSStreamMessage serverMessage = (ServerJMSStreamMessage) converter.inboundJMSType(encodedMessage);
|
ServerMessage serverMessage = converter.inbound(encodedMessage);
|
||||||
|
|
||||||
simulatePersistence(serverMessage);
|
simulatePersistence(serverMessage);
|
||||||
|
|
||||||
verifyProperties(serverMessage);
|
ServerJMSStreamMessage streamMessage = (ServerJMSStreamMessage) wrapMessage(STREAM_TYPE, serverMessage, 0);
|
||||||
|
|
||||||
serverMessage.reset();
|
verifyProperties(streamMessage);
|
||||||
|
|
||||||
assertEquals(10, serverMessage.readInt());
|
streamMessage.reset();
|
||||||
assertEquals("10", serverMessage.readString());
|
|
||||||
|
|
||||||
Object obj = converter.outbound((ServerMessage) serverMessage.getInnerMessage(), 0);
|
assertEquals(10, streamMessage.readInt());
|
||||||
|
assertEquals("10", streamMessage.readString());
|
||||||
|
|
||||||
reEncodeMsg(obj);
|
EncodedMessage encoded = (EncodedMessage) converter.outbound(serverMessage, 0);
|
||||||
|
Message amqpMessage = encoded.decode();
|
||||||
|
|
||||||
MessageImpl outMessage = (MessageImpl) obj;
|
List<?> list = ((AmqpSequence) amqpMessage.getBody()).getValue();
|
||||||
List list = ((AmqpSequence) outMessage.getBody()).getValue();
|
|
||||||
Assert.assertEquals(Integer.valueOf(10), list.get(0));
|
Assert.assertEquals(Integer.valueOf(10), list.get(0));
|
||||||
Assert.assertEquals("10", list.get(1));
|
Assert.assertEquals("10", list.get(1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -247,33 +225,33 @@ public class TestConversions extends Assert {
|
||||||
EncodedMessage encodedMessage = encodeMessage(message);
|
EncodedMessage encodedMessage = encodeMessage(message);
|
||||||
|
|
||||||
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
ProtonMessageConverter converter = new ProtonMessageConverter(new SimpleIDGenerator(0));
|
||||||
ServerJMSTextMessage serverMessage = (ServerJMSTextMessage) converter.inboundJMSType(encodedMessage);
|
ServerMessage serverMessage = converter.inbound(encodedMessage);
|
||||||
|
|
||||||
simulatePersistence(serverMessage);
|
simulatePersistence(serverMessage);
|
||||||
|
|
||||||
verifyProperties(serverMessage);
|
ServerJMSTextMessage textMessage = (ServerJMSTextMessage) wrapMessage(TEXT_TYPE, serverMessage, 0);
|
||||||
|
textMessage.decode();
|
||||||
|
|
||||||
Assert.assertEquals(text, serverMessage.getText());
|
verifyProperties(textMessage);
|
||||||
|
|
||||||
Object obj = converter.outbound((ServerMessage) serverMessage.getInnerMessage(), 0);
|
Assert.assertEquals(text, textMessage.getText());
|
||||||
|
|
||||||
reEncodeMsg(obj);
|
EncodedMessage encoded = (EncodedMessage) converter.outbound(serverMessage, 0);
|
||||||
|
Message amqpMessage = encoded.decode();
|
||||||
|
|
||||||
MessageImpl outMessage = (MessageImpl) obj;
|
AmqpValue value = (AmqpValue) amqpMessage.getBody();
|
||||||
AmqpValue value = (AmqpValue) outMessage.getBody();
|
|
||||||
String textValue = (String) value.getValue();
|
String textValue = (String) value.getValue();
|
||||||
|
|
||||||
Assert.assertEquals(text, textValue);
|
Assert.assertEquals(text, textValue);
|
||||||
|
|
||||||
System.out.println("output = " + obj);
|
System.out.println("output = " + amqpMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void simulatePersistence(ServerJMSMessage serverMessage) {
|
private void simulatePersistence(ServerMessage serverMessage) {
|
||||||
serverMessage.getInnerMessage().setAddress(new SimpleString("jms.queue.SomeAddress"));
|
serverMessage.setAddress(new SimpleString("jms.queue.SomeAddress"));
|
||||||
// This is just to simulate what would happen during the persistence of the message
|
// This is just to simulate what would happen during the persistence of the message
|
||||||
// We need to still be able to recover the message when we read it back
|
// We need to still be able to recover the message when we read it back
|
||||||
((EncodingSupport) serverMessage.getInnerMessage()).encode(new EmptyBuffer());
|
((EncodingSupport) serverMessage).encode(new EmptyBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProtonJMessage reEncodeMsg(Object obj) {
|
private ProtonJMessage reEncodeMsg(Object obj) {
|
||||||
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPInvalidContentTypeException;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class AMQPContentTypeSupportTest {
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeWithOnlyType() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("type", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeEndsWithSlash() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("type/", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeMissingSubtype() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("type/;", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeEmptyString() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeNullString() throws Exception {
|
||||||
|
doParseContentTypeTestImpl(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeNoParamsAfterSeparatorNonTextual() throws Exception {
|
||||||
|
// Expect null as this is not a textual type
|
||||||
|
doParseContentTypeTestImpl("type/subtype;", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeNoParamsAfterSeparatorTextualType() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeEmptyParamsAfterSeparator() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;;", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeNoParams() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithCharsetUtf8() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithCharsetAscii() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithMultipleParams() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain; param=value; charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithCharsetQuoted() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=\"us-ascii\"", StandardCharsets.US_ASCII);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeWithCharsetQuotedEmpty() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=\"\"", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeWithCharsetQuoteNotClosed() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=\"unclosed", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeWithCharsetQuoteNotClosedEmpty() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=\"", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ActiveMQAMQPInvalidContentTypeException.class)
|
||||||
|
public void testParseContentTypeWithNoCharsetValue() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithTextPlain() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("text/plain;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("text/plain", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithTextJson() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/json;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("text/json;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("text/json;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("text/json", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithTextHtml() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/html;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("text/html;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("text/html;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("text/html", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithTextFoo() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("text/foo;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("text/foo;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("text/foo;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("text/foo", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationJson() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("application/json;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("application/json;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("application/json;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("application/json", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationJsonVariant() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("application/something+json;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("application/something+json;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("application/something+json;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("application/something+json", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationJavascript() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("application/javascript;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("application/javascript;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("application/javascript;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("application/javascript", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationEcmascript() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("application/ecmascript;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("application/ecmascript;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("application/ecmascript;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("application/ecmascript", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationXml() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("application/xml;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("application/xml;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("application/xml;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("application/xml", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationXmlVariant() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("application/something+xml;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("application/something+xml;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("application/something+xml;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("application/something+xml", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationXmlDtd() throws Exception {
|
||||||
|
doParseContentTypeTestImpl("application/xml-dtd;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doParseContentTypeTestImpl("application/xml-dtd;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doParseContentTypeTestImpl("application/xml-dtd;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doParseContentTypeTestImpl("application/xml-dtd", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationOtherNotTextual() throws Exception {
|
||||||
|
// Expect null as this is not a textual type
|
||||||
|
doParseContentTypeTestImpl("application/other", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationOctetStream() throws Exception {
|
||||||
|
// Expect null as this is not a textual type
|
||||||
|
doParseContentTypeTestImpl(AMQPMessageSupport.OCTET_STREAM_CONTENT_TYPE, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseContentTypeWithApplicationJavaSerialized() throws Exception {
|
||||||
|
// Expect null as this is not a textual type
|
||||||
|
doParseContentTypeTestImpl(AMQPMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doParseContentTypeTestImpl(String contentType, Charset expected) throws ActiveMQAMQPInvalidContentTypeException {
|
||||||
|
Charset charset = AMQPContentTypeSupport.parseContentTypeForTextualCharset(contentType);
|
||||||
|
if (expected == null) {
|
||||||
|
assertNull("Expected no charset, but got:" + charset, charset);
|
||||||
|
} else {
|
||||||
|
assertEquals("Charset not as expected", expected, charset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,391 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPException;
|
||||||
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
|
import org.apache.qpid.proton.amqp.UnsignedLong;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class AMQPMessageIdHelperTest {
|
||||||
|
|
||||||
|
private AMQPMessageIdHelper messageIdHelper;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
messageIdHelper = new AMQPMessageIdHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns null if given
|
||||||
|
* null
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithNull() {
|
||||||
|
String nullString = null;
|
||||||
|
assertNull("null string should have been returned", messageIdHelper.toBaseMessageIdString(nullString));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} throws an IAE if given
|
||||||
|
* an unexpected object type.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringThrowsIAEWithUnexpectedType() {
|
||||||
|
try {
|
||||||
|
messageIdHelper.toBaseMessageIdString(new Object());
|
||||||
|
fail("expected exception not thrown");
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns the given
|
||||||
|
* basic string unchanged
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithString() {
|
||||||
|
String stringMessageId = "myIdString";
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(stringMessageId);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", stringMessageId, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns a string
|
||||||
|
* indicating an AMQP encoded string, when the given string happens to already begin with the
|
||||||
|
* {@link AMQPMessageIdHelper#AMQP_UUID_PREFIX}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForUUID() {
|
||||||
|
String uuidStringMessageId = AMQPMessageIdHelper.AMQP_UUID_PREFIX + UUID.randomUUID();
|
||||||
|
String expected = AMQPMessageIdHelper.AMQP_STRING_PREFIX + uuidStringMessageId;
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(uuidStringMessageId);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", expected, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns a string
|
||||||
|
* indicating an AMQP encoded string, when the given string happens to already begin with the
|
||||||
|
* {@link AMQPMessageIdHelper#AMQP_ULONG_PREFIX}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForLong() {
|
||||||
|
String longStringMessageId = AMQPMessageIdHelper.AMQP_ULONG_PREFIX + Long.valueOf(123456789L);
|
||||||
|
String expected = AMQPMessageIdHelper.AMQP_STRING_PREFIX + longStringMessageId;
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(longStringMessageId);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", expected, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns a string
|
||||||
|
* indicating an AMQP encoded string, when the given string happens to already begin with the
|
||||||
|
* {@link AMQPMessageIdHelper#AMQP_BINARY_PREFIX}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForBinary() {
|
||||||
|
String binaryStringMessageId = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + "0123456789ABCDEF";
|
||||||
|
String expected = AMQPMessageIdHelper.AMQP_STRING_PREFIX + binaryStringMessageId;
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(binaryStringMessageId);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", expected, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns a string
|
||||||
|
* indicating an AMQP encoded string (effectively twice), when the given string happens to
|
||||||
|
* already begin with the {@link AMQPMessageIdHelper#AMQP_STRING_PREFIX}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForString() {
|
||||||
|
String stringMessageId = AMQPMessageIdHelper.AMQP_STRING_PREFIX + "myStringId";
|
||||||
|
String expected = AMQPMessageIdHelper.AMQP_STRING_PREFIX + stringMessageId;
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(stringMessageId);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", expected, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns a string
|
||||||
|
* indicating an AMQP encoded UUID when given a UUID object.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithUUID() {
|
||||||
|
UUID uuidMessageId = UUID.randomUUID();
|
||||||
|
String expected = AMQPMessageIdHelper.AMQP_UUID_PREFIX + uuidMessageId.toString();
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(uuidMessageId);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", expected, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns a string
|
||||||
|
* indicating an AMQP encoded ulong when given a UnsignedLong object.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithUnsignedLong() {
|
||||||
|
UnsignedLong uLongMessageId = UnsignedLong.valueOf(123456789L);
|
||||||
|
String expected = AMQPMessageIdHelper.AMQP_ULONG_PREFIX + uLongMessageId.toString();
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(uLongMessageId);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", expected, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toBaseMessageIdString(Object)} returns a string
|
||||||
|
* indicating an AMQP encoded binary when given a Binary object.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToBaseMessageIdStringWithBinary() {
|
||||||
|
byte[] bytes = new byte[] {(byte) 0x00, (byte) 0xAB, (byte) 0x09, (byte) 0xFF};
|
||||||
|
Binary binary = new Binary(bytes);
|
||||||
|
|
||||||
|
String expected = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + "00AB09FF";
|
||||||
|
|
||||||
|
String baseMessageIdString = messageIdHelper.toBaseMessageIdString(binary);
|
||||||
|
assertNotNull("null string should not have been returned", baseMessageIdString);
|
||||||
|
assertEquals("expected base id string was not returned", expected, baseMessageIdString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} returns an UnsignedLong when
|
||||||
|
* given a string indicating an encoded AMQP ulong id.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithEncodedUlong() throws Exception {
|
||||||
|
UnsignedLong longId = UnsignedLong.valueOf(123456789L);
|
||||||
|
String provided = AMQPMessageIdHelper.AMQP_ULONG_PREFIX + "123456789";
|
||||||
|
|
||||||
|
Object idObject = messageIdHelper.toIdObject(provided);
|
||||||
|
assertNotNull("null object should not have been returned", idObject);
|
||||||
|
assertEquals("expected id object was not returned", longId, idObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} returns a Binary when given a
|
||||||
|
* string indicating an encoded AMQP binary id, using upper case hex characters
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithEncodedBinaryUppercaseHexString() throws Exception {
|
||||||
|
byte[] bytes = new byte[] {(byte) 0x00, (byte) 0xAB, (byte) 0x09, (byte) 0xFF};
|
||||||
|
Binary binaryId = new Binary(bytes);
|
||||||
|
|
||||||
|
String provided = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + "00AB09FF";
|
||||||
|
|
||||||
|
Object idObject = messageIdHelper.toIdObject(provided);
|
||||||
|
assertNotNull("null object should not have been returned", idObject);
|
||||||
|
assertEquals("expected id object was not returned", binaryId, idObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} returns null when given null.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithNull() throws Exception {
|
||||||
|
assertNull("null object should have been returned", messageIdHelper.toIdObject(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} returns a Binary when given a
|
||||||
|
* string indicating an encoded AMQP binary id, using lower case hex characters.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithEncodedBinaryLowercaseHexString() throws Exception {
|
||||||
|
byte[] bytes = new byte[] {(byte) 0x00, (byte) 0xAB, (byte) 0x09, (byte) 0xFF};
|
||||||
|
Binary binaryId = new Binary(bytes);
|
||||||
|
|
||||||
|
String provided = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + "00ab09ff";
|
||||||
|
|
||||||
|
Object idObject = messageIdHelper.toIdObject(provided);
|
||||||
|
assertNotNull("null object should not have been returned", idObject);
|
||||||
|
assertEquals("expected id object was not returned", binaryId, idObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} returns a UUID when given a
|
||||||
|
* string indicating an encoded AMQP uuid id.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithEncodedUuid() throws Exception {
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
String provided = AMQPMessageIdHelper.AMQP_UUID_PREFIX + uuid.toString();
|
||||||
|
|
||||||
|
Object idObject = messageIdHelper.toIdObject(provided);
|
||||||
|
assertNotNull("null object should not have been returned", idObject);
|
||||||
|
assertEquals("expected id object was not returned", uuid, idObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} returns a string when given a
|
||||||
|
* string without any type encoding prefix.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithStringContainingNoEncodingPrefix() throws Exception {
|
||||||
|
String stringId = "myStringId";
|
||||||
|
|
||||||
|
Object idObject = messageIdHelper.toIdObject(stringId);
|
||||||
|
assertNotNull("null object should not have been returned", idObject);
|
||||||
|
assertEquals("expected id object was not returned", stringId, idObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} returns the remainder of the
|
||||||
|
* provided string after removing the {@link AMQPMessageIdHelper#AMQP_STRING_PREFIX} prefix.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithStringContainingStringEncodingPrefix() throws Exception {
|
||||||
|
String suffix = "myStringSuffix";
|
||||||
|
String stringId = AMQPMessageIdHelper.AMQP_STRING_PREFIX + suffix;
|
||||||
|
|
||||||
|
Object idObject = messageIdHelper.toIdObject(stringId);
|
||||||
|
assertNotNull("null object should not have been returned", idObject);
|
||||||
|
assertEquals("expected id object was not returned", suffix, idObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that when given a string with with the {@link AMQPMessageIdHelper#AMQP_STRING_PREFIX}
|
||||||
|
* prefix and then additionally the {@link AMQPMessageIdHelper#AMQP_UUID_PREFIX}, the
|
||||||
|
* {@link AMQPMessageIdHelper#toIdObject(String)} method returns the remainder of the
|
||||||
|
* provided string after removing the {@link AMQPMessageIdHelper#AMQP_STRING_PREFIX} prefix.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithStringContainingStringEncodingPrefixAndThenUuidPrefix() throws Exception {
|
||||||
|
String encodedUuidString = AMQPMessageIdHelper.AMQP_UUID_PREFIX + UUID.randomUUID().toString();
|
||||||
|
String stringId = AMQPMessageIdHelper.AMQP_STRING_PREFIX + encodedUuidString;
|
||||||
|
|
||||||
|
Object idObject = messageIdHelper.toIdObject(stringId);
|
||||||
|
assertNotNull("null object should not have been returned", idObject);
|
||||||
|
assertEquals("expected id object was not returned", encodedUuidString, idObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} throws an
|
||||||
|
* {@link IdConversionException} when presented with an encoded binary hex string of uneven
|
||||||
|
* length (after the prefix) that thus can't be converted due to each byte using 2 characters
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithStringContainingBinaryHexThrowsWithUnevenLengthString() {
|
||||||
|
String unevenHead = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + "123";
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageIdHelper.toIdObject(unevenHead);
|
||||||
|
fail("expected exception was not thrown");
|
||||||
|
} catch (ActiveMQAMQPException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that {@link AMQPMessageIdHelper#toIdObject(String)} throws an
|
||||||
|
* {@link IdConversionException} when presented with an encoded binary hex string (after the
|
||||||
|
* prefix) that contains characters other than 0-9 and A-F and a-f, and thus can't be
|
||||||
|
* converted
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testToIdObjectWithStringContainingBinaryHexThrowsWithNonHexCharacters() {
|
||||||
|
|
||||||
|
// char before '0'
|
||||||
|
char nonHexChar = '/';
|
||||||
|
String nonHexString = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageIdHelper.toIdObject(nonHexString);
|
||||||
|
fail("expected exception was not thrown");
|
||||||
|
} catch (ActiveMQAMQPException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// char after '9', before 'A'
|
||||||
|
nonHexChar = ':';
|
||||||
|
nonHexString = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageIdHelper.toIdObject(nonHexString);
|
||||||
|
fail("expected exception was not thrown");
|
||||||
|
} catch (ActiveMQAMQPException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// char after 'F', before 'a'
|
||||||
|
nonHexChar = 'G';
|
||||||
|
nonHexString = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageIdHelper.toIdObject(nonHexString);
|
||||||
|
fail("expected exception was not thrown");
|
||||||
|
} catch (ActiveMQAMQPException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// char after 'f'
|
||||||
|
nonHexChar = 'g';
|
||||||
|
nonHexString = AMQPMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageIdHelper.toIdObject(nonHexString);
|
||||||
|
fail("expected exception was not thrown");
|
||||||
|
} catch (ActiveMQAMQPException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.qpid.proton.Proton;
|
||||||
|
import org.apache.qpid.proton.amqp.Symbol;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
||||||
|
import org.apache.qpid.proton.message.Message;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class AMQPMessageSupportTest {
|
||||||
|
|
||||||
|
// ---------- getSymbol ---------------------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSymbol() {
|
||||||
|
assertNotNull(AMQPMessageSupport.getSymbol("x-opt-something-or-other"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- getMessageAnnotation ----------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetMessageAnnotationWhenMessageHasAnnotationsMap() {
|
||||||
|
Map<Symbol, Object> messageAnnotationsMap = new HashMap<>();
|
||||||
|
messageAnnotationsMap.put(Symbol.valueOf("x-opt-test"), Boolean.TRUE);
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setMessageAnnotations(new MessageAnnotations(messageAnnotationsMap));
|
||||||
|
|
||||||
|
assertNotNull(AMQPMessageSupport.getMessageAnnotation("x-opt-test", message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetMessageAnnotationWhenMessageHasEmptyAnnotationsMap() {
|
||||||
|
Map<Symbol, Object> messageAnnotationsMap = new HashMap<>();
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setMessageAnnotations(new MessageAnnotations(messageAnnotationsMap));
|
||||||
|
|
||||||
|
assertNull(AMQPMessageSupport.getMessageAnnotation("x-opt-test", message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetMessageAnnotationWhenMessageHasNoAnnotationsMap() {
|
||||||
|
Message message = Proton.message();
|
||||||
|
assertNull(AMQPMessageSupport.getMessageAnnotation("x-opt-test", message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetMessageAnnotationWhenMessageIsNull() {
|
||||||
|
assertNull(AMQPMessageSupport.getMessageAnnotation("x-opt-test", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- isContentType -----------------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsContentTypeWithNullStringValueAndNullMessageContentType() {
|
||||||
|
Message message = Proton.message();
|
||||||
|
assertTrue(AMQPMessageSupport.isContentType(null, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsContentTypeWithNonNullStringValueAndNullMessageContentType() {
|
||||||
|
Message message = Proton.message();
|
||||||
|
assertFalse(AMQPMessageSupport.isContentType("test", message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsContentTypeWithNonNullStringValueAndNonNullMessageContentTypeNotEqual() {
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setContentType("fails");
|
||||||
|
assertFalse(AMQPMessageSupport.isContentType("test", message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsContentTypeWithNonNullStringValueAndNonNullMessageContentTypeEqual() {
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setContentType("test");
|
||||||
|
assertTrue(AMQPMessageSupport.isContentType("test", message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsContentTypeWithNullStringValueAndNonNullMessageContentType() {
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setContentType("test");
|
||||||
|
assertFalse(AMQPMessageSupport.isContentType(null, message));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,718 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.jms.Destination;
|
||||||
|
import javax.jms.MapMessage;
|
||||||
|
import javax.jms.Queue;
|
||||||
|
import javax.jms.TemporaryQueue;
|
||||||
|
import javax.jms.TemporaryTopic;
|
||||||
|
import javax.jms.TextMessage;
|
||||||
|
import javax.jms.Topic;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.jms.client.ActiveMQMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMapMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSObjectMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSTextMessage;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
import org.apache.activemq.artemis.utils.SimpleIDGenerator;
|
||||||
|
import org.apache.qpid.proton.Proton;
|
||||||
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
|
import org.apache.qpid.proton.amqp.Symbol;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.AmqpSequence;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.Data;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
||||||
|
import org.apache.qpid.proton.message.Message;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class JMSMappingInboundTransformerTest {
|
||||||
|
|
||||||
|
private IDGenerator idGenerator;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
this.idGenerator = new SimpleIDGenerator(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Null Body Section ------------------------------------------------//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a message with no body section, but with the content type set to
|
||||||
|
* {@value AMQPMessageSupport#OCTET_STREAM_CONTENT_TYPE} results in a BytesMessage
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateBytesMessageFromNoBodySectionAndContentType() throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
Message message = Message.Factory.create();
|
||||||
|
message.setContentType(AMQPMessageSupport.OCTET_STREAM_CONTENT_TYPE);
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a message with no body section, and no content-type results in a BytesMessage
|
||||||
|
* when not otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateBytesMessageFromNoBodySectionAndNoContentType() throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
Message message = Message.Factory.create();
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a message with no body section, but with the content type set to
|
||||||
|
* {@value AMQPMessageSupport#SERIALIZED_JAVA_OBJECT_CONTENT_TYPE} results in an
|
||||||
|
* ObjectMessage when not otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateObjectMessageFromNoBodySectionAndContentType() throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
Message message = Message.Factory.create();
|
||||||
|
message.setContentType(AMQPMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE);
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSObjectMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromNoBodySectionAndContentType() throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
Message message = Message.Factory.create();
|
||||||
|
message.setContentType("text/plain");
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSTextMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a message with no body section, and with the content type set to an unknown
|
||||||
|
* value results in a plain Message when not otherwise annotated to indicate the type of JMS
|
||||||
|
* message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
public void testCreateGenericMessageFromNoBodySectionAndUnknownContentType() throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
Message message = Message.Factory.create();
|
||||||
|
message.setContentType("unknown-content-type");
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ActiveMQMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Data Body Section ------------------------------------------------//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a data body containing nothing, but with the content type set to
|
||||||
|
* {@value AMQPMessageSupport#OCTET_STREAM_CONTENT_TYPE} results in a BytesMessage when not
|
||||||
|
* otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateBytesMessageFromDataWithEmptyBinaryAndContentType() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
Binary binary = new Binary(new byte[0]);
|
||||||
|
message.setBody(new Data(binary));
|
||||||
|
message.setContentType(AMQPMessageSupport.OCTET_STREAM_CONTENT_TYPE);
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a message with an empty data body section, and with the content type set to an
|
||||||
|
* unknown value results in a BytesMessage when not otherwise annotated to indicate the type
|
||||||
|
* of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
public void testCreateBytesMessageFromDataWithUnknownContentType() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
Binary binary = new Binary(new byte[0]);
|
||||||
|
message.setBody(new Data(binary));
|
||||||
|
message.setContentType("unknown-content-type");
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a receiving a data body containing nothing and no content type being set results
|
||||||
|
* in a BytesMessage when not otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateBytesMessageFromDataWithEmptyBinaryAndNoContentType() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
Binary binary = new Binary(new byte[0]);
|
||||||
|
message.setBody(new Data(binary));
|
||||||
|
|
||||||
|
assertNull(message.getContentType());
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that receiving a data body containing nothing, but with the content type set to
|
||||||
|
* {@value AMQPMessageSupport#SERIALIZED_JAVA_OBJECT_CONTENT_TYPE} results in an
|
||||||
|
* ObjectMessage when not otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateObjectMessageFromDataWithContentTypeAndEmptyBinary() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
Binary binary = new Binary(new byte[0]);
|
||||||
|
message.setBody(new Data(binary));
|
||||||
|
message.setContentType(AMQPMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE);
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSObjectMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeTextPlain() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/plain;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/plain;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/plain;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/plain", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeTextJson() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/json;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/json;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/json;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/json", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeTextHtml() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/html;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/html;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/html;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/html", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeTextFoo() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/foo;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/foo;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/foo;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("text/foo", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeApplicationJson() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/json;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/json;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/json;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/json", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeApplicationJsonVariant() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+json;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+json;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+json;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+json", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeApplicationJavascript() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/javascript;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/javascript;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/javascript;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/javascript", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeApplicationEcmascript() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/ecmascript;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/ecmascript;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/ecmascript;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/ecmascript", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeApplicationXml() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeApplicationXmlVariant() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+xml;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+xml;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+xml;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/something+xml", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromDataWithContentTypeApplicationXmlDtd() throws Exception {
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml-dtd;charset=iso-8859-1", StandardCharsets.ISO_8859_1);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml-dtd;charset=us-ascii", StandardCharsets.US_ASCII);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml-dtd;charset=utf-8", StandardCharsets.UTF_8);
|
||||||
|
doCreateTextMessageFromDataWithContentTypeTestImpl("application/xml-dtd", StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doCreateTextMessageFromDataWithContentTypeTestImpl(String contentType, Charset expectedCharset) throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
Binary binary = new Binary(new byte[0]);
|
||||||
|
message.setBody(new Data(binary));
|
||||||
|
message.setContentType(contentType);
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
if (StandardCharsets.UTF_8.equals(expectedCharset)) {
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSTextMessage.class, jmsMessage.getClass());
|
||||||
|
} else {
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- AmqpValue transformations ----------------------------------------//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-value body containing a string results in a TextMessage when not
|
||||||
|
* otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromAmqpValueWithString() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setBody(new AmqpValue("content"));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSTextMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-value body containing a null results in an TextMessage when not
|
||||||
|
* otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateTextMessageFromAmqpValueWithNull() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setBody(new AmqpValue(null));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSTextMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a message with an AmqpValue section containing a Binary, but with the content
|
||||||
|
* type set to {@value AMQPMessageSupport#SERIALIZED_JAVA_OBJECT_CONTENT_TYPE} results in an
|
||||||
|
* ObjectMessage when not otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateObjectMessageFromAmqpValueWithBinaryAndContentType() throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
Message message = Message.Factory.create();
|
||||||
|
message.setBody(new AmqpValue(new Binary(new byte[0])));
|
||||||
|
message.setContentType(AMQPMessageSupport.SERIALIZED_JAVA_OBJECT_CONTENT_TYPE);
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSObjectMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-value body containing a map results in an MapMessage when not otherwise
|
||||||
|
* annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateAmqpMapMessageFromAmqpValueWithMap() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
message.setBody(new AmqpValue(map));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSMapMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-value body containing a map that has an AMQP Binary as one of the
|
||||||
|
* entries encoded into the Map results in an MapMessage where a byte array can be read from
|
||||||
|
* the entry.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateAmqpMapMessageFromAmqpValueWithMapContainingBinaryEntry() throws Exception {
|
||||||
|
final String ENTRY_NAME = "bytesEntry";
|
||||||
|
|
||||||
|
Message message = Proton.message();
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
byte[] inputBytes = new byte[] {1, 2, 3, 4, 5};
|
||||||
|
map.put(ENTRY_NAME, new Binary(inputBytes));
|
||||||
|
|
||||||
|
message.setBody(new AmqpValue(map));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSMapMessage.class, jmsMessage.getClass());
|
||||||
|
|
||||||
|
MapMessage mapMessage = (MapMessage) jmsMessage;
|
||||||
|
byte[] outputBytes = mapMessage.getBytes(ENTRY_NAME);
|
||||||
|
assertNotNull(outputBytes);
|
||||||
|
assertTrue(Arrays.equals(inputBytes, outputBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-value body containing a list results in an StreamMessage when not
|
||||||
|
* otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateAmqpStreamMessageFromAmqpValueWithList() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
message.setBody(new AmqpValue(list));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSStreamMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-sequence body containing a list results in an StreamMessage when not
|
||||||
|
* otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateAmqpStreamMessageFromAmqpSequence() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
message.setBody(new AmqpSequence(list));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSStreamMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-value body containing a binary value results in BytesMessage when not
|
||||||
|
* otherwise annotated to indicate the type of JMS message it is.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateAmqpBytesMessageFromAmqpValueWithBinary() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
Binary binary = new Binary(new byte[0]);
|
||||||
|
message.setBody(new AmqpValue(binary));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that an amqp-value body containing a value which can't be categorized results in an
|
||||||
|
* exception from the transformer and then try the transformer's own fallback transformer to
|
||||||
|
* result in an BytesMessage.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* if an error occurs during the test.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateBytesMessageFromAmqpValueWithUncategorisedContent() throws Exception {
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setBody(new AmqpValue(UUID.randomUUID()));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertNotNull("Message should not be null", jmsMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSBytesMessage.class, jmsMessage.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformMessageWithAmqpValueStringCreatesTextMessage() throws Exception {
|
||||||
|
String contentString = "myTextMessageContent";
|
||||||
|
Message message = Message.Factory.create();
|
||||||
|
message.setBody(new AmqpValue(contentString));
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(message);
|
||||||
|
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
|
||||||
|
assertTrue("Expected TextMessage", jmsMessage instanceof TextMessage);
|
||||||
|
assertEquals("Unexpected message class type", ServerJMSTextMessage.class, jmsMessage.getClass());
|
||||||
|
|
||||||
|
TextMessage textMessage = (TextMessage) jmsMessage;
|
||||||
|
|
||||||
|
assertNotNull(textMessage.getText());
|
||||||
|
assertEquals(contentString, textMessage.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Destination Conversions ------------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithNoToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithToTypeDestinationTypeAnnotationTestImpl(null, Destination.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithQueueStringToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithToTypeDestinationTypeAnnotationTestImpl("queue", Queue.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithTemporaryQueueStringToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithToTypeDestinationTypeAnnotationTestImpl("queue,temporary", TemporaryQueue.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithTopicStringToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithToTypeDestinationTypeAnnotationTestImpl("topic", Topic.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithTemporaryTopicStringToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithToTypeDestinationTypeAnnotationTestImpl("topic,temporary", TemporaryTopic.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTransformWithToTypeDestinationTypeAnnotationTestImpl(Object toTypeAnnotationValue, Class<? extends Destination> expectedClass)
|
||||||
|
throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
String toAddress = "toAddress";
|
||||||
|
Message amqp = Message.Factory.create();
|
||||||
|
amqp.setBody(new AmqpValue("myTextMessageContent"));
|
||||||
|
amqp.setAddress(toAddress);
|
||||||
|
if (toTypeAnnotationValue != null) {
|
||||||
|
Map<Symbol, Object> map = new HashMap<>();
|
||||||
|
map.put(Symbol.valueOf("x-opt-to-type"), toTypeAnnotationValue);
|
||||||
|
MessageAnnotations ma = new MessageAnnotations(map);
|
||||||
|
amqp.setMessageAnnotations(ma);
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(amqp);
|
||||||
|
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
assertTrue("Expected TextMessage", jmsMessage instanceof TextMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- ReplyTo Conversions ----------------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithNoReplyToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithReplyToTypeDestinationTypeAnnotationTestImpl(null, Destination.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithQueueStringReplyToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithReplyToTypeDestinationTypeAnnotationTestImpl("queue", Queue.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithTemporaryQueueStringReplyToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithReplyToTypeDestinationTypeAnnotationTestImpl("queue,temporary", TemporaryQueue.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithTopicStringReplyToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithReplyToTypeDestinationTypeAnnotationTestImpl("topic", Topic.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransformWithTemporaryTopicStringReplyToTypeDestinationTypeAnnotation() throws Exception {
|
||||||
|
doTransformWithReplyToTypeDestinationTypeAnnotationTestImpl("topic,temporary", TemporaryTopic.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTransformWithReplyToTypeDestinationTypeAnnotationTestImpl(Object replyToTypeAnnotationValue, Class<? extends Destination> expectedClass)
|
||||||
|
throws Exception {
|
||||||
|
JMSMappingInboundTransformer transformer = new JMSMappingInboundTransformer(idGenerator);
|
||||||
|
|
||||||
|
String replyToAddress = "replyToAddress";
|
||||||
|
Message amqp = Message.Factory.create();
|
||||||
|
amqp.setBody(new AmqpValue("myTextMessageContent"));
|
||||||
|
amqp.setReplyTo(replyToAddress);
|
||||||
|
if (replyToTypeAnnotationValue != null) {
|
||||||
|
Map<Symbol, Object> map = new HashMap<>();
|
||||||
|
map.put(Symbol.valueOf("x-opt-reply-type"), replyToTypeAnnotationValue);
|
||||||
|
MessageAnnotations ma = new MessageAnnotations(map);
|
||||||
|
amqp.setMessageAnnotations(ma);
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedMessage em = encodeMessage(amqp);
|
||||||
|
|
||||||
|
javax.jms.Message jmsMessage = transformer.transform(em);
|
||||||
|
assertTrue("Expected TextMessage", jmsMessage instanceof TextMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Utility Methods --------------------------------------------------//
|
||||||
|
|
||||||
|
private EncodedMessage encodeMessage(Message message) {
|
||||||
|
byte[] encodeBuffer = new byte[1024 * 8];
|
||||||
|
int encodedSize;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
encodedSize = message.encode(encodeBuffer, 0, encodeBuffer.length);
|
||||||
|
break;
|
||||||
|
} catch (java.nio.BufferOverflowException e) {
|
||||||
|
encodeBuffer = new byte[encodeBuffer.length * 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long messageFormat = 0;
|
||||||
|
return new EncodedMessage(messageFormat, encodeBuffer, 0, encodedSize);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,952 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_DATA;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_NULL;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_SEQUENCE;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_UNKNOWN;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.AMQP_VALUE_BINARY;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.converter.message.AMQPMessageSupport.JMS_AMQP_ORIGINAL_ENCODING;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.jms.JMSException;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.buffers.impl.ResetLimitWrappedActiveMQBuffer;
|
||||||
|
import org.apache.activemq.artemis.core.server.impl.ServerMessageImpl;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerDestination;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSBytesMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMapMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSObjectMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSStreamMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.jms.ServerJMSTextMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.util.NettyWritable;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
import org.apache.activemq.artemis.utils.SimpleIDGenerator;
|
||||||
|
import org.apache.qpid.proton.amqp.Binary;
|
||||||
|
import org.apache.qpid.proton.amqp.Symbol;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.AmqpSequence;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.Data;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
||||||
|
import org.apache.qpid.proton.message.Message;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
public class JMSMappingOutboundTransformerTest {
|
||||||
|
|
||||||
|
private final UUID TEST_OBJECT_VALUE = UUID.fromString("fee14b62-09e0-4ac6-a4c3-4206c630d844");
|
||||||
|
private final String TEST_ADDRESS = "queue://testAddress";
|
||||||
|
|
||||||
|
private IDGenerator idGenerator;
|
||||||
|
private JMSMappingOutboundTransformer transformer;
|
||||||
|
|
||||||
|
public static final byte QUEUE_TYPE = 0x00;
|
||||||
|
public static final byte TOPIC_TYPE = 0x01;
|
||||||
|
public static final byte TEMP_QUEUE_TYPE = 0x02;
|
||||||
|
public static final byte TEMP_TOPIC_TYPE = 0x03;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
idGenerator = new SimpleIDGenerator(0);
|
||||||
|
transformer = new JMSMappingOutboundTransformer(idGenerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- no-body Message type tests ---------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageToAmqpMessageWithNoBody() throws Exception {
|
||||||
|
ServerJMSMessage outbound = createMessage();
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNull(amqp.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertTextMessageToAmqpMessageWithNoBodyOriginalEncodingWasNull() throws Exception {
|
||||||
|
ServerJMSTextMessage outbound = createTextMessage();
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_NULL);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNull(amqp.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- BytesMessage type tests ---------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertEmptyBytesMessageToAmqpMessageWithDataBody() throws Exception {
|
||||||
|
ServerJMSBytesMessage outbound = createBytesMessage();
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertTrue(((Data) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertEquals(0, ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertUncompressedBytesMessageToAmqpMessageWithDataBody() throws Exception {
|
||||||
|
byte[] expectedPayload = new byte[] {8, 16, 24, 32};
|
||||||
|
ServerJMSBytesMessage outbound = createBytesMessage();
|
||||||
|
outbound.writeBytes(expectedPayload);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertTrue(((Data) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertEquals(4, ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
|
||||||
|
Binary amqpData = ((Data) amqp.getBody()).getValue();
|
||||||
|
Binary inputData = new Binary(expectedPayload);
|
||||||
|
|
||||||
|
assertTrue(inputData.equals(amqpData));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Compressed message body support not yet implemented.")
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedBytesMessageToAmqpMessageWithDataBody() throws Exception {
|
||||||
|
byte[] expectedPayload = new byte[] {8, 16, 24, 32};
|
||||||
|
ServerJMSBytesMessage outbound = createBytesMessage(true);
|
||||||
|
outbound.writeBytes(expectedPayload);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertTrue(((Data) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertEquals(4, ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
|
||||||
|
Binary amqpData = ((Data) amqp.getBody()).getValue();
|
||||||
|
Binary inputData = new Binary(expectedPayload);
|
||||||
|
|
||||||
|
assertTrue(inputData.equals(amqpData));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertEmptyBytesMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
ServerJMSBytesMessage outbound = createBytesMessage();
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_BINARY);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertEquals(0, ((Binary) ((AmqpValue) amqp.getBody()).getValue()).getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertUncompressedBytesMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
byte[] expectedPayload = new byte[] {8, 16, 24, 32};
|
||||||
|
ServerJMSBytesMessage outbound = createBytesMessage();
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_BINARY);
|
||||||
|
outbound.writeBytes(expectedPayload);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertEquals(4, ((Binary) ((AmqpValue) amqp.getBody()).getValue()).getLength());
|
||||||
|
|
||||||
|
Binary amqpData = (Binary) ((AmqpValue) amqp.getBody()).getValue();
|
||||||
|
Binary inputData = new Binary(expectedPayload);
|
||||||
|
|
||||||
|
assertTrue(inputData.equals(amqpData));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Compressed message body support not yet implemented.")
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedBytesMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
byte[] expectedPayload = new byte[] {8, 16, 24, 32};
|
||||||
|
ServerJMSBytesMessage outbound = createBytesMessage(true);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_BINARY);
|
||||||
|
outbound.writeBytes(expectedPayload);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertEquals(4, ((Binary) ((AmqpValue) amqp.getBody()).getValue()).getLength());
|
||||||
|
|
||||||
|
Binary amqpData = (Binary) ((AmqpValue) amqp.getBody()).getValue();
|
||||||
|
Binary inputData = new Binary(expectedPayload);
|
||||||
|
|
||||||
|
assertTrue(inputData.equals(amqpData));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- MapMessage type tests --------------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMapMessageToAmqpMessageWithNoBody() throws Exception {
|
||||||
|
ServerJMSMapMessage outbound = createMapMessage();
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMapMessageToAmqpMessageWithByteArrayValueInBody() throws Exception {
|
||||||
|
final byte[] byteArray = new byte[] {1, 2, 3, 4, 5};
|
||||||
|
|
||||||
|
ServerJMSMapMessage outbound = createMapMessage();
|
||||||
|
outbound.setBytes("bytes", byteArray);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Map);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<Object, Object> amqpMap = (Map<Object, Object>) ((AmqpValue) amqp.getBody()).getValue();
|
||||||
|
|
||||||
|
assertEquals(1, amqpMap.size());
|
||||||
|
Binary readByteArray = (Binary) amqpMap.get("bytes");
|
||||||
|
assertNotNull(readByteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMapMessageToAmqpMessage() throws Exception {
|
||||||
|
ServerJMSMapMessage outbound = createMapMessage();
|
||||||
|
outbound.setString("property-1", "string");
|
||||||
|
outbound.setInt("property-2", 1);
|
||||||
|
outbound.setBoolean("property-3", true);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Map);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<Object, Object> amqpMap = (Map<Object, Object>) ((AmqpValue) amqp.getBody()).getValue();
|
||||||
|
|
||||||
|
assertEquals(3, amqpMap.size());
|
||||||
|
assertTrue("string".equals(amqpMap.get("property-1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedMapMessageToAmqpMessage() throws Exception {
|
||||||
|
ServerJMSMapMessage outbound = createMapMessage(true);
|
||||||
|
outbound.setString("property-1", "string");
|
||||||
|
outbound.setInt("property-2", 1);
|
||||||
|
outbound.setBoolean("property-3", true);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Map);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<Object, Object> amqpMap = (Map<Object, Object>) ((AmqpValue) amqp.getBody()).getValue();
|
||||||
|
|
||||||
|
assertEquals(3, amqpMap.size());
|
||||||
|
assertTrue("string".equals(amqpMap.get("property-1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- StreamMessage type tests -----------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertStreamMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
ServerJMSStreamMessage outbound = createStreamMessage();
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof List);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertStreamMessageToAmqpMessageWithAmqpSequencey() throws Exception {
|
||||||
|
ServerJMSStreamMessage outbound = createStreamMessage();
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_SEQUENCE);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpSequence);
|
||||||
|
assertTrue(((AmqpSequence) amqp.getBody()).getValue() instanceof List);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedStreamMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
ServerJMSStreamMessage outbound = createStreamMessage(true);
|
||||||
|
outbound.writeBoolean(false);
|
||||||
|
outbound.writeString("test");
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof List);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Object> amqpList = (List<Object>) ((AmqpValue) amqp.getBody()).getValue();
|
||||||
|
|
||||||
|
assertEquals(2, amqpList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedStreamMessageToAmqpMessageWithAmqpSequencey() throws Exception {
|
||||||
|
ServerJMSStreamMessage outbound = createStreamMessage(true);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_SEQUENCE);
|
||||||
|
outbound.writeBoolean(false);
|
||||||
|
outbound.writeString("test");
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpSequence);
|
||||||
|
assertTrue(((AmqpSequence) amqp.getBody()).getValue() instanceof List);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Object> amqpList = ((AmqpSequence) amqp.getBody()).getValue();
|
||||||
|
|
||||||
|
assertEquals(2, amqpList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- ObjectMessage type tests -----------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertEmptyObjectMessageToAmqpMessageWithDataBody() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage();
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertEquals(5, ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertEmptyObjectMessageToAmqpMessageUnknownEncodingGetsDataSection() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage();
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_UNKNOWN);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertEquals(5, ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertEmptyObjectMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage();
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_BINARY);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertEquals(5, ((Binary) ((AmqpValue) amqp.getBody()).getValue()).getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertObjectMessageToAmqpMessageWithDataBody() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage(TEST_OBJECT_VALUE);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertFalse(0 == ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
|
||||||
|
Object value = deserialize(((Data) amqp.getBody()).getValue().getArray());
|
||||||
|
assertNotNull(value);
|
||||||
|
assertTrue(value instanceof UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertObjectMessageToAmqpMessageUnknownEncodingGetsDataSection() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage(TEST_OBJECT_VALUE);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_UNKNOWN);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertFalse(0 == ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
|
||||||
|
Object value = deserialize(((Data) amqp.getBody()).getValue().getArray());
|
||||||
|
assertNotNull(value);
|
||||||
|
assertTrue(value instanceof UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertObjectMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage(TEST_OBJECT_VALUE);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_BINARY);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertFalse(0 == ((Binary) ((AmqpValue) amqp.getBody()).getValue()).getLength());
|
||||||
|
|
||||||
|
Object value = deserialize(((Binary) ((AmqpValue) amqp.getBody()).getValue()).getArray());
|
||||||
|
assertNotNull(value);
|
||||||
|
assertTrue(value instanceof UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedObjectMessageToAmqpMessageWithDataBody() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage(TEST_OBJECT_VALUE, true);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertFalse(0 == ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
|
||||||
|
Object value = deserialize(((Data) amqp.getBody()).getValue().getArray());
|
||||||
|
assertNotNull(value);
|
||||||
|
assertTrue(value instanceof UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedObjectMessageToAmqpMessageUnknownEncodingGetsDataSection() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage(TEST_OBJECT_VALUE, true);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_UNKNOWN);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertFalse(0 == ((Data) amqp.getBody()).getValue().getLength());
|
||||||
|
|
||||||
|
Object value = deserialize(((Data) amqp.getBody()).getValue().getArray());
|
||||||
|
assertNotNull(value);
|
||||||
|
assertTrue(value instanceof UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedObjectMessageToAmqpMessageWithAmqpValueBody() throws Exception {
|
||||||
|
ServerJMSObjectMessage outbound = createObjectMessage(TEST_OBJECT_VALUE, true);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_VALUE_BINARY);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(((AmqpValue) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
assertFalse(0 == ((Binary) ((AmqpValue) amqp.getBody()).getValue()).getLength());
|
||||||
|
|
||||||
|
Object value = deserialize(((Binary) ((AmqpValue) amqp.getBody()).getValue()).getArray());
|
||||||
|
assertNotNull(value);
|
||||||
|
assertTrue(value instanceof UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- TextMessage type tests -------------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertTextMessageToAmqpMessageWithNoBody() throws Exception {
|
||||||
|
ServerJMSTextMessage outbound = createTextMessage();
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertNull(((AmqpValue) amqp.getBody()).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertTextMessageCreatesBodyUsingOriginalEncodingWithDataSection() throws Exception {
|
||||||
|
String contentString = "myTextMessageContent";
|
||||||
|
ServerJMSTextMessage outbound = createTextMessage(contentString);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_DATA);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertTrue(((Data) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
|
||||||
|
Binary data = ((Data) amqp.getBody()).getValue();
|
||||||
|
String contents = new String(data.getArray(), data.getArrayOffset(), data.getLength(), StandardCharsets.UTF_8);
|
||||||
|
assertEquals(contentString, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertTextMessageContentNotStoredCreatesBodyUsingOriginalEncodingWithDataSection() throws Exception {
|
||||||
|
String contentString = "myTextMessageContent";
|
||||||
|
ServerJMSTextMessage outbound = createTextMessage(contentString);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_DATA);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertTrue(((Data) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
|
||||||
|
Binary data = ((Data) amqp.getBody()).getValue();
|
||||||
|
String contents = new String(data.getArray(), data.getArrayOffset(), data.getLength(), StandardCharsets.UTF_8);
|
||||||
|
assertEquals(contentString, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertTextMessageCreatesAmqpValueStringBody() throws Exception {
|
||||||
|
String contentString = "myTextMessageContent";
|
||||||
|
ServerJMSTextMessage outbound = createTextMessage(contentString);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertEquals(contentString, ((AmqpValue) amqp.getBody()).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertTextMessageContentNotStoredCreatesAmqpValueStringBody() throws Exception {
|
||||||
|
String contentString = "myTextMessageContent";
|
||||||
|
ServerJMSTextMessage outbound = createTextMessage(contentString);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof AmqpValue);
|
||||||
|
assertEquals(contentString, ((AmqpValue) amqp.getBody()).getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertCompressedTextMessageCreatesDataSectionBody() throws Exception {
|
||||||
|
String contentString = "myTextMessageContent";
|
||||||
|
ServerJMSTextMessage outbound = createTextMessage(contentString, true);
|
||||||
|
outbound.setShortProperty(JMS_AMQP_ORIGINAL_ENCODING, AMQP_DATA);
|
||||||
|
outbound.encode();
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(outbound);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
assertNotNull(amqp.getBody());
|
||||||
|
assertTrue(amqp.getBody() instanceof Data);
|
||||||
|
assertTrue(((Data) amqp.getBody()).getValue() instanceof Binary);
|
||||||
|
|
||||||
|
Binary data = ((Data) amqp.getBody()).getValue();
|
||||||
|
String contents = new String(data.getArray(), data.getArrayOffset(), data.getLength(), StandardCharsets.UTF_8);
|
||||||
|
assertEquals(contentString, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Test JMSDestination Handling -------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSDestinationNull() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSDestination(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSDestinationQueue() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSDestination(createDestination(QUEUE_TYPE), QUEUE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Artemis code doesn't provide a means of supplying a typed destination to AMQP")
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSDestinationTemporaryQueue() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSDestination(createDestination(TEMP_QUEUE_TYPE), TEMP_QUEUE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Artemis code doesn't provide a means of supplying a typed destination to AMQP")
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSDestinationTopic() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSDestination(createDestination(TOPIC_TYPE), TOPIC_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Artemis code doesn't provide a means of supplying a typed destination to AMQP")
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSDestinationTemporaryTopic() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSDestination(createDestination(TEMP_TOPIC_TYPE), TEMP_TOPIC_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestConvertMessageWithJMSDestination(ServerDestination jmsDestination, Object expectedAnnotationValue) throws Exception {
|
||||||
|
ServerJMSTextMessage textMessage = createTextMessage();
|
||||||
|
textMessage.setText("myTextMessageContent");
|
||||||
|
textMessage.setJMSDestination(jmsDestination);
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(textMessage);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
MessageAnnotations ma = amqp.getMessageAnnotations();
|
||||||
|
Map<Symbol, Object> maMap = ma == null ? null : ma.getValue();
|
||||||
|
if (maMap != null) {
|
||||||
|
Object actualValue = maMap.get(JMSMappingOutboundTransformer.JMS_DEST_TYPE_MSG_ANNOTATION);
|
||||||
|
assertEquals("Unexpected annotation value", expectedAnnotationValue, actualValue);
|
||||||
|
} else if (expectedAnnotationValue != null) {
|
||||||
|
fail("Expected annotation value, but there were no annotations");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jmsDestination != null) {
|
||||||
|
assertEquals("Unexpected 'to' address", jmsDestination.getAddress(), amqp.getAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Test JMSReplyTo Handling -----------------------------------------//
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSReplyToNull() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSReplyTo(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSReplyToQueue() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSReplyTo(createDestination(QUEUE_TYPE), QUEUE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Artemis code doesn't provide a means of supplying a typed destination to AMQP")
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSReplyToTemporaryQueue() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSReplyTo(createDestination(TEMP_QUEUE_TYPE), TEMP_QUEUE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Artemis code doesn't provide a means of supplying a typed destination to AMQP")
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSReplyToTopic() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSReplyTo(createDestination(TOPIC_TYPE), TOPIC_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Artemis code doesn't provide a means of supplying a typed destination to AMQP")
|
||||||
|
@Test
|
||||||
|
public void testConvertMessageWithJMSReplyToTemporaryTopic() throws Exception {
|
||||||
|
doTestConvertMessageWithJMSReplyTo(createDestination(TEMP_TOPIC_TYPE), TEMP_TOPIC_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestConvertMessageWithJMSReplyTo(ServerDestination jmsReplyTo, Object expectedAnnotationValue) throws Exception {
|
||||||
|
ServerJMSTextMessage textMessage = createTextMessage();
|
||||||
|
textMessage.setText("myTextMessageContent");
|
||||||
|
textMessage.setJMSReplyTo(jmsReplyTo);
|
||||||
|
|
||||||
|
EncodedMessage encoded = transform(textMessage);
|
||||||
|
assertNotNull(encoded);
|
||||||
|
|
||||||
|
Message amqp = encoded.decode();
|
||||||
|
|
||||||
|
MessageAnnotations ma = amqp.getMessageAnnotations();
|
||||||
|
Map<Symbol, Object> maMap = ma == null ? null : ma.getValue();
|
||||||
|
if (maMap != null) {
|
||||||
|
Object actualValue = maMap.get(JMSMappingOutboundTransformer.JMS_REPLY_TO_TYPE_MSG_ANNOTATION);
|
||||||
|
assertEquals("Unexpected annotation value", expectedAnnotationValue, actualValue);
|
||||||
|
} else if (expectedAnnotationValue != null) {
|
||||||
|
fail("Expected annotation value, but there were no annotations");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jmsReplyTo != null) {
|
||||||
|
assertEquals("Unexpected 'reply-to' address", jmsReplyTo.getAddress(), amqp.getReplyTo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Utility Methods used for this Test -------------------------------//
|
||||||
|
|
||||||
|
public EncodedMessage transform(ServerJMSMessage message) throws Exception {
|
||||||
|
// Useful for testing but not recommended for real life use.
|
||||||
|
ByteBuf nettyBuffer = Unpooled.buffer(1024);
|
||||||
|
NettyWritable buffer = new NettyWritable(nettyBuffer);
|
||||||
|
|
||||||
|
long messageFormat = transformer.transform(message, buffer);
|
||||||
|
|
||||||
|
EncodedMessage encoded = new EncodedMessage(messageFormat, nettyBuffer.array(), nettyBuffer.arrayOffset() + nettyBuffer.readerIndex(), nettyBuffer.readableBytes());
|
||||||
|
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerDestination createDestination(byte destType) {
|
||||||
|
ServerDestination destination = null;
|
||||||
|
switch (destType) {
|
||||||
|
case QUEUE_TYPE:
|
||||||
|
destination = new ServerDestination(TEST_ADDRESS);
|
||||||
|
break;
|
||||||
|
case TOPIC_TYPE:
|
||||||
|
destination = new ServerDestination(TEST_ADDRESS);
|
||||||
|
break;
|
||||||
|
case TEMP_QUEUE_TYPE:
|
||||||
|
destination = new ServerDestination(TEST_ADDRESS);
|
||||||
|
break;
|
||||||
|
case TEMP_TOPIC_TYPE:
|
||||||
|
destination = new ServerDestination(TEST_ADDRESS);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invliad Destination Type given/");
|
||||||
|
}
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSMessage createMessage() {
|
||||||
|
return new ServerJMSMessage(newMessage(org.apache.activemq.artemis.api.core.Message.DEFAULT_TYPE), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSBytesMessage createBytesMessage() {
|
||||||
|
return createBytesMessage(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSBytesMessage createBytesMessage(boolean compression) {
|
||||||
|
ServerJMSBytesMessage message = new ServerJMSBytesMessage(newMessage(org.apache.activemq.artemis.api.core.Message.BYTES_TYPE), 0);
|
||||||
|
|
||||||
|
if (compression) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSMapMessage createMapMessage() {
|
||||||
|
return createMapMessage(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSMapMessage createMapMessage(boolean compression) {
|
||||||
|
ServerJMSMapMessage message = new ServerJMSMapMessage(newMessage(org.apache.activemq.artemis.api.core.Message.MAP_TYPE), 0);
|
||||||
|
|
||||||
|
if (compression) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSStreamMessage createStreamMessage() {
|
||||||
|
return createStreamMessage(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSStreamMessage createStreamMessage(boolean compression) {
|
||||||
|
ServerJMSStreamMessage message = new ServerJMSStreamMessage(newMessage(org.apache.activemq.artemis.api.core.Message.STREAM_TYPE), 0);
|
||||||
|
|
||||||
|
if (compression) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSObjectMessage createObjectMessage() {
|
||||||
|
return createObjectMessage(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSObjectMessage createObjectMessage(Serializable payload) {
|
||||||
|
return createObjectMessage(payload, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSObjectMessage createObjectMessage(Serializable payload, boolean compression) {
|
||||||
|
ServerJMSObjectMessage result = AMQPMessageSupport.createObjectMessage(idGenerator);
|
||||||
|
|
||||||
|
if (compression) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos);) {
|
||||||
|
|
||||||
|
oos.writeObject(payload);
|
||||||
|
byte[] data = baos.toByteArray();
|
||||||
|
result.setSerializedForm(new Binary(data));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new AssertionError("Should not fail to setObject in this test");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSTextMessage createTextMessage() {
|
||||||
|
return createTextMessage(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSTextMessage createTextMessage(String text) {
|
||||||
|
return createTextMessage(text, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerJMSTextMessage createTextMessage(String text, boolean compression) {
|
||||||
|
ServerJMSTextMessage result = AMQPMessageSupport.createTextMessage(idGenerator);
|
||||||
|
|
||||||
|
if (compression) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
result.setText(text);
|
||||||
|
} catch (JMSException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object deserialize(byte[] payload) throws Exception {
|
||||||
|
try (ByteArrayInputStream bis = new ByteArrayInputStream(payload); ObjectInputStream ois = new ObjectInputStream(bis);) {
|
||||||
|
|
||||||
|
return ois.readObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerMessageImpl newMessage(byte messageType) {
|
||||||
|
ServerMessageImpl message = new ServerMessageImpl(idGenerator.generateID(), 512);
|
||||||
|
message.setType(messageType);
|
||||||
|
((ResetLimitWrappedActiveMQBuffer) message.getBodyBuffer()).setMessage(null);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,300 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.server.ServerMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.ProtonMessageConverter;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.util.NettyWritable;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
import org.apache.activemq.artemis.utils.SimpleIDGenerator;
|
||||||
|
import org.apache.qpid.proton.Proton;
|
||||||
|
import org.apache.qpid.proton.amqp.Symbol;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
||||||
|
import org.apache.qpid.proton.message.Message;
|
||||||
|
import org.apache.qpid.proton.message.ProtonJMessage;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some simple performance tests for the Message Transformers.
|
||||||
|
*/
|
||||||
|
@Ignore("Useful for profiling but slow and not meant as a unit test")
|
||||||
|
public class JMSTransformationSpeedComparisonTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName test = new TestName();
|
||||||
|
|
||||||
|
private IDGenerator idGenerator;
|
||||||
|
private ProtonMessageConverter converter;
|
||||||
|
|
||||||
|
private final int WARM_CYCLES = 1000;
|
||||||
|
private final int PROFILE_CYCLES = 1000000;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
idGenerator = new SimpleIDGenerator(0);
|
||||||
|
converter = new ProtonMessageConverter(idGenerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBodyOnlyMessage() throws Exception {
|
||||||
|
|
||||||
|
Message message = Proton.message();
|
||||||
|
message.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
EncodedMessage encoded = encode(message);
|
||||||
|
|
||||||
|
// Warm up
|
||||||
|
for (int i = 0; i < WARM_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalDuration = 0;
|
||||||
|
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
for (int i = 0; i < PROFILE_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
totalDuration += System.nanoTime() - startTime;
|
||||||
|
|
||||||
|
LOG_RESULTS(totalDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessageWithNoPropertiesOrAnnotations() throws Exception {
|
||||||
|
|
||||||
|
Message message = Proton.message();
|
||||||
|
|
||||||
|
message.setAddress("queue://test-queue");
|
||||||
|
message.setDeliveryCount(1);
|
||||||
|
message.setCreationTime(System.currentTimeMillis());
|
||||||
|
message.setContentType("text/plain");
|
||||||
|
message.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(message);
|
||||||
|
|
||||||
|
// Warm up
|
||||||
|
for (int i = 0; i < WARM_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalDuration = 0;
|
||||||
|
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
for (int i = 0; i < PROFILE_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
totalDuration += System.nanoTime() - startTime;
|
||||||
|
|
||||||
|
LOG_RESULTS(totalDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTypicalQpidJMSMessage() throws Exception {
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(createTypicalQpidJMSMessage());
|
||||||
|
|
||||||
|
// Warm up
|
||||||
|
for (int i = 0; i < WARM_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalDuration = 0;
|
||||||
|
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
for (int i = 0; i < PROFILE_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
totalDuration += System.nanoTime() - startTime;
|
||||||
|
|
||||||
|
LOG_RESULTS(totalDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComplexQpidJMSMessage() throws Exception {
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(createComplexQpidJMSMessage());
|
||||||
|
|
||||||
|
// Warm up
|
||||||
|
for (int i = 0; i < WARM_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalDuration = 0;
|
||||||
|
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
for (int i = 0; i < PROFILE_CYCLES; ++i) {
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
totalDuration += System.nanoTime() - startTime;
|
||||||
|
|
||||||
|
LOG_RESULTS(totalDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTypicalQpidJMSMessageInBoundOnly() throws Exception {
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(createTypicalQpidJMSMessage());
|
||||||
|
|
||||||
|
// Warm up
|
||||||
|
for (int i = 0; i < WARM_CYCLES; ++i) {
|
||||||
|
converter.inbound(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalDuration = 0;
|
||||||
|
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
for (int i = 0; i < PROFILE_CYCLES; ++i) {
|
||||||
|
converter.inbound(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalDuration += System.nanoTime() - startTime;
|
||||||
|
|
||||||
|
LOG_RESULTS(totalDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTypicalQpidJMSMessageOutBoundOnly() throws Exception {
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(createTypicalQpidJMSMessage());
|
||||||
|
ServerMessage intermediate = converter.inbound(encoded);
|
||||||
|
|
||||||
|
// Warm up
|
||||||
|
for (int i = 0; i < WARM_CYCLES; ++i) {
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalDuration = 0;
|
||||||
|
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
for (int i = 0; i < PROFILE_CYCLES; ++i) {
|
||||||
|
encode(converter.outbound(intermediate, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
totalDuration += System.nanoTime() - startTime;
|
||||||
|
|
||||||
|
LOG_RESULTS(totalDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message createTypicalQpidJMSMessage() {
|
||||||
|
Map<String, Object> applicationProperties = new HashMap<>();
|
||||||
|
Map<Symbol, Object> messageAnnotations = new HashMap<>();
|
||||||
|
|
||||||
|
applicationProperties.put("property-1", "string");
|
||||||
|
applicationProperties.put("property-2", 512);
|
||||||
|
applicationProperties.put("property-3", true);
|
||||||
|
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-msg-type"), 0);
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-dest"), 0);
|
||||||
|
|
||||||
|
Message message = Proton.message();
|
||||||
|
|
||||||
|
message.setAddress("queue://test-queue");
|
||||||
|
message.setDeliveryCount(1);
|
||||||
|
message.setApplicationProperties(new ApplicationProperties(applicationProperties));
|
||||||
|
message.setMessageAnnotations(new MessageAnnotations(messageAnnotations));
|
||||||
|
message.setCreationTime(System.currentTimeMillis());
|
||||||
|
message.setContentType("text/plain");
|
||||||
|
message.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message createComplexQpidJMSMessage() {
|
||||||
|
Map<String, Object> applicationProperties = new HashMap<>();
|
||||||
|
Map<Symbol, Object> messageAnnotations = new HashMap<>();
|
||||||
|
|
||||||
|
applicationProperties.put("property-1", "string-1");
|
||||||
|
applicationProperties.put("property-2", 512);
|
||||||
|
applicationProperties.put("property-3", true);
|
||||||
|
applicationProperties.put("property-4", "string-2");
|
||||||
|
applicationProperties.put("property-5", 512);
|
||||||
|
applicationProperties.put("property-6", true);
|
||||||
|
applicationProperties.put("property-7", "string-3");
|
||||||
|
applicationProperties.put("property-8", 512);
|
||||||
|
applicationProperties.put("property-9", true);
|
||||||
|
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-msg-type"), 0);
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-dest"), 0);
|
||||||
|
|
||||||
|
Message message = Proton.message();
|
||||||
|
|
||||||
|
// Header Values
|
||||||
|
message.setPriority((short) 9);
|
||||||
|
message.setDurable(true);
|
||||||
|
message.setDeliveryCount(2);
|
||||||
|
message.setTtl(5000);
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
message.setMessageId("ID:SomeQualifier:0:0:1");
|
||||||
|
message.setGroupId("Group-ID-1");
|
||||||
|
message.setGroupSequence(15);
|
||||||
|
message.setAddress("queue://test-queue");
|
||||||
|
message.setReplyTo("queue://reply-queue");
|
||||||
|
message.setCreationTime(System.currentTimeMillis());
|
||||||
|
message.setContentType("text/plain");
|
||||||
|
message.setCorrelationId("ID:SomeQualifier:0:7:9");
|
||||||
|
message.setUserId("username".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
// Application Properties / Message Annotations / Body
|
||||||
|
message.setApplicationProperties(new ApplicationProperties(applicationProperties));
|
||||||
|
message.setMessageAnnotations(new MessageAnnotations(messageAnnotations));
|
||||||
|
message.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EncodedMessage encode(Object target) {
|
||||||
|
if (target instanceof ProtonJMessage) {
|
||||||
|
ProtonJMessage amqp = (ProtonJMessage) target;
|
||||||
|
|
||||||
|
ByteBuf nettyBuffer = Unpooled.buffer(1024);
|
||||||
|
amqp.encode(new NettyWritable(nettyBuffer));
|
||||||
|
|
||||||
|
return new EncodedMessage(0, nettyBuffer.array(), nettyBuffer.arrayOffset() + nettyBuffer.readerIndex(), nettyBuffer.readableBytes());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LOG_RESULTS(long duration) {
|
||||||
|
String result = "[JMS] Total time for " + PROFILE_CYCLES + " cycles of transforms = " + TimeUnit.NANOSECONDS.toMillis(duration) + " ms -> "
|
||||||
|
+ test.getMethodName();
|
||||||
|
|
||||||
|
System.out.println(result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,264 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.converter.message;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.server.ServerMessage;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.converter.ProtonMessageConverter;
|
||||||
|
import org.apache.activemq.artemis.utils.IDGenerator;
|
||||||
|
import org.apache.activemq.artemis.utils.SimpleIDGenerator;
|
||||||
|
import org.apache.qpid.proton.Proton;
|
||||||
|
import org.apache.qpid.proton.amqp.Symbol;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
|
||||||
|
import org.apache.qpid.proton.amqp.messaging.Section;
|
||||||
|
import org.apache.qpid.proton.codec.CompositeWritableBuffer;
|
||||||
|
import org.apache.qpid.proton.codec.DroppingWritableBuffer;
|
||||||
|
import org.apache.qpid.proton.codec.WritableBuffer;
|
||||||
|
import org.apache.qpid.proton.message.Message;
|
||||||
|
import org.apache.qpid.proton.message.ProtonJMessage;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests some basic encode / decode functionality on the transformers.
|
||||||
|
*/
|
||||||
|
public class MessageTransformationTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TestName test = new TestName();
|
||||||
|
|
||||||
|
private IDGenerator idGenerator;
|
||||||
|
private ProtonMessageConverter converter;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
idGenerator = new SimpleIDGenerator(0);
|
||||||
|
converter = new ProtonMessageConverter(idGenerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeDecodeFidelity() throws Exception {
|
||||||
|
Map<String, Object> applicationProperties = new HashMap<>();
|
||||||
|
Map<Symbol, Object> messageAnnotations = new HashMap<>();
|
||||||
|
|
||||||
|
applicationProperties.put("property-1", "string");
|
||||||
|
applicationProperties.put("property-2", 512);
|
||||||
|
applicationProperties.put("property-3", true);
|
||||||
|
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-msg-type"), 0);
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-dest"), 0);
|
||||||
|
|
||||||
|
Message incomingMessage = Proton.message();
|
||||||
|
|
||||||
|
incomingMessage.setAddress("queue://test-queue");
|
||||||
|
incomingMessage.setDeliveryCount(1);
|
||||||
|
incomingMessage.setApplicationProperties(new ApplicationProperties(applicationProperties));
|
||||||
|
incomingMessage.setMessageAnnotations(new MessageAnnotations(messageAnnotations));
|
||||||
|
incomingMessage.setCreationTime(System.currentTimeMillis());
|
||||||
|
incomingMessage.setContentType("text/plain");
|
||||||
|
incomingMessage.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(incomingMessage);
|
||||||
|
|
||||||
|
ServerMessage outbound = converter.inbound(encoded);
|
||||||
|
Message outboudMessage = ((EncodedMessage) converter.outbound(outbound, outbound.getLongProperty("JMSXDeliveryCount").intValue())).decode();
|
||||||
|
|
||||||
|
// Test that message details are equal
|
||||||
|
assertEquals(incomingMessage.getAddress(), outboudMessage.getAddress());
|
||||||
|
assertEquals(incomingMessage.getDeliveryCount(), outboudMessage.getDeliveryCount());
|
||||||
|
assertEquals(incomingMessage.getCreationTime(), outboudMessage.getCreationTime());
|
||||||
|
assertEquals(incomingMessage.getContentType(), outboudMessage.getContentType());
|
||||||
|
|
||||||
|
// Test Message annotations
|
||||||
|
ApplicationProperties incomingApplicationProperties = incomingMessage.getApplicationProperties();
|
||||||
|
ApplicationProperties outgoingApplicationProperties = outboudMessage.getApplicationProperties();
|
||||||
|
|
||||||
|
assertEquals(incomingApplicationProperties.getValue(), outgoingApplicationProperties.getValue());
|
||||||
|
|
||||||
|
// Test Message properties
|
||||||
|
MessageAnnotations incomingMessageAnnotations = incomingMessage.getMessageAnnotations();
|
||||||
|
MessageAnnotations outgoingMessageAnnotations = outboudMessage.getMessageAnnotations();
|
||||||
|
|
||||||
|
assertEquals(incomingMessageAnnotations.getValue(), outgoingMessageAnnotations.getValue());
|
||||||
|
|
||||||
|
// Test that bodies are equal
|
||||||
|
assertTrue(incomingMessage.getBody() instanceof AmqpValue);
|
||||||
|
assertTrue(outboudMessage.getBody() instanceof AmqpValue);
|
||||||
|
|
||||||
|
AmqpValue incomingBody = (AmqpValue) incomingMessage.getBody();
|
||||||
|
AmqpValue outgoingBody = (AmqpValue) outboudMessage.getBody();
|
||||||
|
|
||||||
|
assertTrue(incomingBody.getValue() instanceof String);
|
||||||
|
assertTrue(outgoingBody.getValue() instanceof String);
|
||||||
|
|
||||||
|
assertEquals(incomingBody.getValue(), outgoingBody.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBodyOnlyEncodeDecode() throws Exception {
|
||||||
|
|
||||||
|
Message incomingMessage = Proton.message();
|
||||||
|
|
||||||
|
incomingMessage.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(incomingMessage);
|
||||||
|
ServerMessage outbound = converter.inbound(encoded);
|
||||||
|
Message outboudMessage = ((EncodedMessage) converter.outbound(outbound, 1)).decode();
|
||||||
|
|
||||||
|
assertNull(outboudMessage.getHeader());
|
||||||
|
assertNull(outboudMessage.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPropertiesButNoHeadersEncodeDecode() throws Exception {
|
||||||
|
|
||||||
|
Message incomingMessage = Proton.message();
|
||||||
|
|
||||||
|
incomingMessage.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
incomingMessage.setMessageId("ID:SomeQualifier:0:0:1");
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(incomingMessage);
|
||||||
|
ServerMessage outbound = converter.inbound(encoded);
|
||||||
|
Message outboudMessage = ((EncodedMessage) converter.outbound(outbound, 1)).decode();
|
||||||
|
|
||||||
|
assertNull(outboudMessage.getHeader());
|
||||||
|
assertNotNull(outboudMessage.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHeaderButNoPropertiesEncodeDecode() throws Exception {
|
||||||
|
|
||||||
|
Message incomingMessage = Proton.message();
|
||||||
|
|
||||||
|
incomingMessage.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
incomingMessage.setDurable(true);
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(incomingMessage);
|
||||||
|
ServerMessage outbound = converter.inbound(encoded);
|
||||||
|
Message outboudMessage = ((EncodedMessage) converter.outbound(outbound, 1)).decode();
|
||||||
|
|
||||||
|
assertNotNull(outboudMessage.getHeader());
|
||||||
|
assertNull(outboudMessage.getProperties());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessageWithAmqpValueThatFailsJMSConversion() throws Exception {
|
||||||
|
|
||||||
|
Message incomingMessage = Proton.message();
|
||||||
|
|
||||||
|
incomingMessage.setBody(new AmqpValue(new Boolean(true)));
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(incomingMessage);
|
||||||
|
ServerMessage outbound = converter.inbound(encoded);
|
||||||
|
Message outboudMessage = ((EncodedMessage) converter.outbound(outbound, 1)).decode();
|
||||||
|
|
||||||
|
Section section = outboudMessage.getBody();
|
||||||
|
assertNotNull(section);
|
||||||
|
assertTrue(section instanceof AmqpValue);
|
||||||
|
AmqpValue amqpValue = (AmqpValue) section;
|
||||||
|
assertNotNull(amqpValue.getValue());
|
||||||
|
assertTrue(amqpValue.getValue() instanceof Boolean);
|
||||||
|
assertEquals(true, amqpValue.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComplexQpidJMSMessageEncodeDecode() throws Exception {
|
||||||
|
|
||||||
|
Map<String, Object> applicationProperties = new HashMap<>();
|
||||||
|
Map<Symbol, Object> messageAnnotations = new HashMap<>();
|
||||||
|
|
||||||
|
applicationProperties.put("property-1", "string-1");
|
||||||
|
applicationProperties.put("property-2", 512);
|
||||||
|
applicationProperties.put("property-3", true);
|
||||||
|
applicationProperties.put("property-4", "string-2");
|
||||||
|
applicationProperties.put("property-5", 512);
|
||||||
|
applicationProperties.put("property-6", true);
|
||||||
|
applicationProperties.put("property-7", "string-3");
|
||||||
|
applicationProperties.put("property-8", 512);
|
||||||
|
applicationProperties.put("property-9", true);
|
||||||
|
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-msg-type"), 0);
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-dest"), 0);
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-jms-reply-to"), 0);
|
||||||
|
messageAnnotations.put(Symbol.valueOf("x-opt-delivery-delay"), 2000);
|
||||||
|
|
||||||
|
Message message = Proton.message();
|
||||||
|
|
||||||
|
// Header Values
|
||||||
|
message.setPriority((short) 9);
|
||||||
|
message.setDurable(true);
|
||||||
|
message.setDeliveryCount(2);
|
||||||
|
message.setTtl(5000);
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
message.setMessageId("ID:SomeQualifier:0:0:1");
|
||||||
|
message.setGroupId("Group-ID-1");
|
||||||
|
message.setGroupSequence(15);
|
||||||
|
message.setAddress("queue://test-queue");
|
||||||
|
message.setReplyTo("queue://reply-queue");
|
||||||
|
message.setCreationTime(System.currentTimeMillis());
|
||||||
|
message.setContentType("text/plain");
|
||||||
|
message.setCorrelationId("ID:SomeQualifier:0:7:9");
|
||||||
|
message.setUserId("username".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
// Application Properties / Message Annotations / Body
|
||||||
|
message.setApplicationProperties(new ApplicationProperties(applicationProperties));
|
||||||
|
message.setMessageAnnotations(new MessageAnnotations(messageAnnotations));
|
||||||
|
message.setBody(new AmqpValue("String payload for AMQP message conversion performance testing."));
|
||||||
|
|
||||||
|
EncodedMessage encoded = encode(message);
|
||||||
|
ServerMessage outbound = converter.inbound(encoded);
|
||||||
|
Message outboudMessage = ((EncodedMessage) converter.outbound(outbound, 1)).decode();
|
||||||
|
|
||||||
|
assertNotNull(outboudMessage.getHeader());
|
||||||
|
assertNotNull(outboudMessage.getProperties());
|
||||||
|
assertNotNull(outboudMessage.getMessageAnnotations());
|
||||||
|
assertNotNull(outboudMessage.getApplicationProperties());
|
||||||
|
assertNull(outboudMessage.getDeliveryAnnotations());
|
||||||
|
assertNull(outboudMessage.getFooter());
|
||||||
|
|
||||||
|
assertEquals(9, outboudMessage.getApplicationProperties().getValue().size());
|
||||||
|
assertEquals(4, outboudMessage.getMessageAnnotations().getValue().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private EncodedMessage encode(Message message) {
|
||||||
|
ProtonJMessage amqp = (ProtonJMessage) message;
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(new byte[1024 * 4]);
|
||||||
|
final DroppingWritableBuffer overflow = new DroppingWritableBuffer();
|
||||||
|
int c = amqp.encode(new CompositeWritableBuffer(new WritableBuffer.ByteBufferWrapper(buffer), overflow));
|
||||||
|
if (overflow.position() > 0) {
|
||||||
|
buffer = ByteBuffer.wrap(new byte[1024 * 4 + overflow.position()]);
|
||||||
|
c = amqp.encode(new WritableBuffer.ByteBufferWrapper(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EncodedMessage(1, buffer.array(), 0, c);
|
||||||
|
}
|
||||||
|
}
|
|
@ -203,6 +203,30 @@ public class AmqpMessage {
|
||||||
return message.getProperties().getTo();
|
return message.getProperties().getTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the replyTo address which is applied to the AMQP message reply-to field in the message properties
|
||||||
|
*
|
||||||
|
* @param address The replyTo address that should be applied in the Message To field.
|
||||||
|
*/
|
||||||
|
public void setReplyToAddress(String address) {
|
||||||
|
checkReadOnly();
|
||||||
|
lazyCreateProperties();
|
||||||
|
getWrappedMessage().setReplyTo(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the set replyTo address that was set in the Message To field.
|
||||||
|
*
|
||||||
|
* @return the set replyTo address String form or null if not set.
|
||||||
|
*/
|
||||||
|
public String getReplyToAddress() {
|
||||||
|
if (message.getProperties() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return message.getProperties().getReplyTo();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the MessageId property on an outbound message using the provided String
|
* Sets the MessageId property on an outbound message using the provided String
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,6 +16,25 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.tests.integration.amqp;
|
package org.apache.activemq.artemis.tests.integration.amqp;
|
||||||
|
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.DELAYED_DELIVERY;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.PRODUCT;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.VERSION;
|
||||||
|
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.contains;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
import javax.jms.BytesMessage;
|
||||||
import javax.jms.Connection;
|
import javax.jms.Connection;
|
||||||
import javax.jms.ConnectionFactory;
|
import javax.jms.ConnectionFactory;
|
||||||
|
@ -36,21 +55,9 @@ import javax.jms.StreamMessage;
|
||||||
import javax.jms.TemporaryQueue;
|
import javax.jms.TemporaryQueue;
|
||||||
import javax.jms.TextMessage;
|
import javax.jms.TextMessage;
|
||||||
import javax.jms.Topic;
|
import javax.jms.Topic;
|
||||||
|
import javax.jms.TopicPublisher;
|
||||||
import javax.jms.TopicSession;
|
import javax.jms.TopicSession;
|
||||||
import javax.jms.TopicSubscriber;
|
import javax.jms.TopicSubscriber;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
import org.apache.activemq.artemis.core.postoffice.Bindings;
|
import org.apache.activemq.artemis.core.postoffice.Bindings;
|
||||||
|
@ -83,11 +90,6 @@ import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.DELAYED_DELIVERY;
|
|
||||||
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.PRODUCT;
|
|
||||||
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.VERSION;
|
|
||||||
import static org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport.contains;
|
|
||||||
|
|
||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public class ProtonTest extends ProtonTestBase {
|
public class ProtonTest extends ProtonTestBase {
|
||||||
|
|
||||||
|
@ -179,6 +181,31 @@ public class ProtonTest extends ProtonTestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendAndReceiveOnTopic() throws Exception {
|
||||||
|
Connection connection = createConnection("myClientId");
|
||||||
|
try {
|
||||||
|
TopicSession session = (TopicSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||||
|
Topic topic = session.createTopic("amqp_testtopic");
|
||||||
|
TopicSubscriber consumer = session.createSubscriber(topic);
|
||||||
|
TopicPublisher producer = session.createPublisher(topic);
|
||||||
|
|
||||||
|
TextMessage message = session.createTextMessage("test-message");
|
||||||
|
producer.send(message);
|
||||||
|
producer.close();
|
||||||
|
|
||||||
|
connection.start();
|
||||||
|
|
||||||
|
message = (TextMessage) consumer.receive(1000);
|
||||||
|
assertNotNull(message);
|
||||||
|
assertNotNull(message.getText());
|
||||||
|
} finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDurableSubscriptionUnsubscribe() throws Exception {
|
public void testDurableSubscriptionUnsubscribe() throws Exception {
|
||||||
Connection connection = createConnection("myClientId");
|
Connection connection = createConnection("myClientId");
|
||||||
|
@ -495,7 +522,7 @@ public class ProtonTest extends ProtonTestBase {
|
||||||
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||||
javax.jms.Queue queue = createQueue(address);
|
javax.jms.Queue queue = createQueue(address);
|
||||||
MessageProducer p = session.createProducer(queue);
|
MessageProducer p = session.createProducer(queue);
|
||||||
ArrayList list = new ArrayList();
|
ArrayList<String> list = new ArrayList<>();
|
||||||
list.add("aString");
|
list.add("aString");
|
||||||
ObjectMessage objectMessage = session.createObjectMessage(list);
|
ObjectMessage objectMessage = session.createObjectMessage(list);
|
||||||
p.send(objectMessage);
|
p.send(objectMessage);
|
||||||
|
@ -507,7 +534,7 @@ public class ProtonTest extends ProtonTestBase {
|
||||||
|
|
||||||
objectMessage = (ObjectMessage) cons.receive(5000);
|
objectMessage = (ObjectMessage) cons.receive(5000);
|
||||||
assertNotNull(objectMessage);
|
assertNotNull(objectMessage);
|
||||||
list = (ArrayList) objectMessage.getObject();
|
list = (ArrayList<String>) objectMessage.getObject();
|
||||||
assertEquals(list.get(0), "aString");
|
assertEquals(list.get(0), "aString");
|
||||||
connection.close();
|
connection.close();
|
||||||
}
|
}
|
||||||
|
@ -586,7 +613,7 @@ public class ProtonTest extends ProtonTestBase {
|
||||||
fillAddress(destinationAddress);
|
fillAddress(destinationAddress);
|
||||||
|
|
||||||
AmqpClient client = new AmqpClient(new URI(tcpAmqpConnectionUri), userName, password);
|
AmqpClient client = new AmqpClient(new URI(tcpAmqpConnectionUri), userName, password);
|
||||||
AmqpConnection amqpConnection = amqpConnection = client.connect();
|
AmqpConnection amqpConnection = client.connect();
|
||||||
try {
|
try {
|
||||||
AmqpSession session = amqpConnection.createSession();
|
AmqpSession session = amqpConnection.createSession();
|
||||||
AmqpSender sender = session.createSender(destinationAddress);
|
AmqpSender sender = session.createSender(destinationAddress);
|
||||||
|
@ -860,7 +887,7 @@ public class ProtonTest extends ProtonTestBase {
|
||||||
AmqpMessage request = new AmqpMessage();
|
AmqpMessage request = new AmqpMessage();
|
||||||
request.setApplicationProperty("_AMQ_ResourceName", "core.server");
|
request.setApplicationProperty("_AMQ_ResourceName", "core.server");
|
||||||
request.setApplicationProperty("_AMQ_OperationName", "getQueueNames");
|
request.setApplicationProperty("_AMQ_OperationName", "getQueueNames");
|
||||||
request.setApplicationProperty("JMSReplyTo", destinationAddress);
|
request.setReplyToAddress(destinationAddress);
|
||||||
request.setText("[]");
|
request.setText("[]");
|
||||||
|
|
||||||
sender.send(request);
|
sender.send(request);
|
||||||
|
|
Loading…
Reference in New Issue