org.apache.activemq.artemis.jms.client.ActiveMQJMSProducer Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* 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.jms.client;
import jakarta.jms.BytesMessage;
import jakarta.jms.CompletionListener;
import jakarta.jms.Destination;
import jakarta.jms.JMSException;
import jakarta.jms.JMSProducer;
import jakarta.jms.JMSRuntimeException;
import jakarta.jms.MapMessage;
import jakarta.jms.Message;
import jakarta.jms.MessageFormatRuntimeException;
import jakarta.jms.MessageProducer;
import jakarta.jms.ObjectMessage;
import jakarta.jms.TextMessage;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.activemq.artemis.api.core.ActiveMQPropertyConversionException;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.utils.collections.TypedProperties;
/**
* NOTE: this class forwards {@link #setDisableMessageID(boolean)} and
* {@link #setDisableMessageTimestamp(boolean)} calls their equivalent at the
* {@link MessageProducer}. IF the user is using the producer in async mode, this may lead to races.
* We allow/tolerate this because these are just optional optimizations.
*/
public final class ActiveMQJMSProducer implements JMSProducer {
private final ActiveMQJMSContext context;
private final MessageProducer producer;
private final TypedProperties properties = new TypedProperties();
//we convert Strings to SimpleStrings so if getProperty is called the wrong object is returned, this list let's us return the
//correct type
private final List stringPropertyNames = new ArrayList<>();
private volatile CompletionListener completionListener;
private Destination jmsHeaderReplyTo;
private String jmsHeaderCorrelationID;
private byte[] jmsHeaderCorrelationIDAsBytes;
private String jmsHeaderType;
ActiveMQJMSProducer(ActiveMQJMSContext context, MessageProducer producer) {
this.context = context;
this.producer = producer;
}
@Override
public JMSProducer send(Destination destination, Message message) {
if (message == null) {
throw new MessageFormatRuntimeException("null message");
}
try {
if (jmsHeaderCorrelationID != null) {
message.setJMSCorrelationID(jmsHeaderCorrelationID);
}
if (jmsHeaderCorrelationIDAsBytes != null && jmsHeaderCorrelationIDAsBytes.length > 0) {
message.setJMSCorrelationIDAsBytes(jmsHeaderCorrelationIDAsBytes);
}
if (jmsHeaderReplyTo != null) {
message.setJMSReplyTo(jmsHeaderReplyTo);
}
if (jmsHeaderType != null) {
message.setJMSType(jmsHeaderType);
}
// XXX HORNETQ-1209 "JMS 2.0" can this be a foreign msg?
// if so, then "SimpleString" properties will trigger an error.
setProperties(message);
if (completionListener != null) {
CompletionListener wrapped = new CompletionListenerWrapper(completionListener);
producer.send(destination, message, wrapped);
} else {
producer.send(destination, message);
}
} catch (JMSException e) {
throw JmsExceptionUtils.convertToRuntimeException(e);
}
return this;
}
/**
* Sets all properties we carry onto the message.
*
* @param message
* @throws JMSException
*/
private void setProperties(Message message) throws JMSException {
properties.forEach((k, v) -> {
try {
message.setObjectProperty(k.toString(), v);
} catch (JMSException e) {
throw JmsExceptionUtils.convertToRuntimeException(e);
}
});
}
@Override
public JMSProducer send(Destination destination, String body) {
TextMessage message = context.createTextMessage(body);
send(destination, message);
return this;
}
@Override
public JMSProducer send(Destination destination, Map body) {
MapMessage message = context.createMapMessage();
if (body != null) {
try {
for (Entry entry : body.entrySet()) {
final String name = entry.getKey();
final Object v = entry.getValue();
if (v instanceof String) {
message.setString(name, (String) v);
} else if (v instanceof Long) {
message.setLong(name, (Long) v);
} else if (v instanceof Double) {
message.setDouble(name, (Double) v);
} else if (v instanceof Integer) {
message.setInt(name, (Integer) v);
} else if (v instanceof Character) {
message.setChar(name, (Character) v);
} else if (v instanceof Short) {
message.setShort(name, (Short) v);
} else if (v instanceof Boolean) {
message.setBoolean(name, (Boolean) v);
} else if (v instanceof Float) {
message.setFloat(name, (Float) v);
} else if (v instanceof Byte) {
message.setByte(name, (Byte) v);
} else if (v instanceof byte[]) {
byte[] array = (byte[]) v;
message.setBytes(name, array, 0, array.length);
} else {
message.setObject(name, v);
}
}
} catch (JMSException e) {
throw new MessageFormatRuntimeException(e.getMessage());
}
}
send(destination, message);
return this;
}
@Override
public JMSProducer send(Destination destination, byte[] body) {
BytesMessage message = context.createBytesMessage();
if (body != null) {
try {
message.writeBytes(body);
} catch (JMSException e) {
throw new MessageFormatRuntimeException(e.getMessage());
}
}
send(destination, message);
return this;
}
@Override
public JMSProducer send(Destination destination, Serializable body) {
ObjectMessage message = context.createObjectMessage(body);
send(destination, message);
return this;
}
@Override
public JMSProducer setDisableMessageID(boolean value) {
try {
producer.setDisableMessageID(value);
} catch (JMSException e) {
throw JmsExceptionUtils.convertToRuntimeException(e);
}
return this;
}
@Override
public boolean getDisableMessageID() {
try {
return producer.getDisableMessageID();
} catch (JMSException e) {
throw JmsExceptionUtils.convertToRuntimeException(e);
}
}
@Override
public JMSProducer setDisableMessageTimestamp(boolean value) {
try {
producer.setDisableMessageTimestamp(value);
} catch (JMSException e) {
throw JmsExceptionUtils.convertToRuntimeException(e);
}
return this;
}
@Override
public boolean getDisableMessageTimestamp() {
try {
return producer.getDisableMessageTimestamp();
} catch (JMSException e) {
throw JmsExceptionUtils.convertToRuntimeException(e);
}
}
@Override
public JMSProducer setDeliveryMode(int deliveryMode) {
try {
producer.setDeliveryMode(deliveryMode);
} catch (JMSException e) {
JMSRuntimeException e2 = new JMSRuntimeException(e.getMessage());
e2.initCause(e);
throw e2;
}
return this;
}
@Override
public int getDeliveryMode() {
try {
return producer.getDeliveryMode();
} catch (JMSException e) {
JMSRuntimeException e2 = new JMSRuntimeException(e.getMessage());
e2.initCause(e);
throw e2;
}
}
@Override
public JMSProducer setPriority(int priority) {
try {
producer.setPriority(priority);
} catch (JMSException e) {
JMSRuntimeException e2 = new JMSRuntimeException(e.getMessage());
e2.initCause(e);
throw e2;
}
return this;
}
@Override
public int getPriority() {
try {
return producer.getPriority();
} catch (JMSException e) {
JMSRuntimeException e2 = new JMSRuntimeException(e.getMessage());
e2.initCause(e);
throw e2;
}
}
@Override
public JMSProducer setTimeToLive(long timeToLive) {
try {
producer.setTimeToLive(timeToLive);
return this;
} catch (JMSException e) {
JMSRuntimeException e2 = new JMSRuntimeException(e.getMessage());
e2.initCause(e);
throw e2;
}
}
@Override
public long getTimeToLive() {
long timeToLive = 0;
try {
timeToLive = producer.getTimeToLive();
return timeToLive;
} catch (JMSException e) {
JMSRuntimeException e2 = new JMSRuntimeException(e.getMessage());
e2.initCause(e);
throw e2;
}
}
@Override
public JMSProducer setDeliveryDelay(long deliveryDelay) {
try {
producer.setDeliveryDelay(deliveryDelay);
return this;
} catch (JMSException e) {
JMSRuntimeException e2 = new JMSRuntimeException(e.getMessage());
e2.initCause(e);
throw e2;
}
}
@Override
public long getDeliveryDelay() {
long deliveryDelay = 0;
try {
deliveryDelay = producer.getDeliveryDelay();
} catch (Exception ignored) {
}
return deliveryDelay;
}
@Override
public JMSProducer setAsync(CompletionListener completionListener) {
this.completionListener = completionListener;
return this;
}
@Override
public CompletionListener getAsync() {
return completionListener;
}
@Override
public JMSProducer setProperty(String name, boolean value) {
checkName(name);
properties.putBooleanProperty(SimpleString.of(name), value);
return this;
}
@Override
public JMSProducer setProperty(String name, byte value) {
checkName(name);
properties.putByteProperty(SimpleString.of(name), value);
return this;
}
@Override
public JMSProducer setProperty(String name, short value) {
checkName(name);
properties.putShortProperty(SimpleString.of(name), value);
return this;
}
@Override
public JMSProducer setProperty(String name, int value) {
checkName(name);
properties.putIntProperty(SimpleString.of(name), value);
return this;
}
@Override
public JMSProducer setProperty(String name, long value) {
checkName(name);
properties.putLongProperty(SimpleString.of(name), value);
return this;
}
@Override
public JMSProducer setProperty(String name, float value) {
checkName(name);
properties.putFloatProperty(SimpleString.of(name), value);
return this;
}
@Override
public JMSProducer setProperty(String name, double value) {
checkName(name);
properties.putDoubleProperty(SimpleString.of(name), value);
return this;
}
@Override
public JMSProducer setProperty(String name, String value) {
checkName(name);
SimpleString key = SimpleString.of(name);
properties.putSimpleStringProperty(key, SimpleString.of(value));
stringPropertyNames.add(key);
return this;
}
@Override
public JMSProducer setProperty(String name, Object value) {
checkName(name);
try {
TypedProperties.setObjectProperty(SimpleString.of(name), value, properties);
} catch (ActiveMQPropertyConversionException amqe) {
throw new MessageFormatRuntimeException(amqe.getMessage());
} catch (RuntimeException e) {
throw new JMSRuntimeException(e.getMessage());
}
return this;
}
@Override
public JMSProducer clearProperties() {
try {
stringPropertyNames.clear();
properties.clear();
} catch (RuntimeException e) {
throw new JMSRuntimeException(e.getMessage());
}
return this;
}
@Override
public boolean propertyExists(String name) {
return properties.containsProperty(SimpleString.of(name));
}
@Override
public boolean getBooleanProperty(String name) {
try {
return properties.getBooleanProperty(SimpleString.of(name));
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
} catch (RuntimeException e) {
throw new JMSRuntimeException(e.getMessage());
}
}
@Override
public byte getByteProperty(String name) {
try {
return properties.getByteProperty(SimpleString.of(name));
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
}
}
@Override
public short getShortProperty(String name) {
try {
return properties.getShortProperty(SimpleString.of(name));
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
}
}
@Override
public int getIntProperty(String name) {
try {
return properties.getIntProperty(SimpleString.of(name));
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
}
}
@Override
public long getLongProperty(String name) {
try {
return properties.getLongProperty(SimpleString.of(name));
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
}
}
@Override
public float getFloatProperty(String name) {
try {
return properties.getFloatProperty(SimpleString.of(name));
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
}
}
@Override
public double getDoubleProperty(String name) {
try {
return properties.getDoubleProperty(SimpleString.of(name));
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
}
}
@Override
public String getStringProperty(String name) {
try {
SimpleString prop = properties.getSimpleStringProperty(SimpleString.of(name));
if (prop == null)
return null;
return prop.toString();
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
} catch (RuntimeException e) {
throw new JMSRuntimeException(e.getMessage());
}
}
@Override
public Object getObjectProperty(String name) {
try {
SimpleString key = SimpleString.of(name);
Object property = properties.getProperty(key);
if (stringPropertyNames.contains(key)) {
property = property.toString();
}
return property;
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
} catch (RuntimeException e) {
throw new JMSRuntimeException(e.getMessage());
}
}
@Override
public Set getPropertyNames() {
try {
return properties.getMapNames();
} catch (ActiveMQPropertyConversionException ce) {
throw new MessageFormatRuntimeException(ce.getMessage());
} catch (RuntimeException e) {
throw new JMSRuntimeException(e.getMessage());
}
}
@Override
public JMSProducer setJMSCorrelationIDAsBytes(byte[] correlationID) {
if (correlationID == null || correlationID.length == 0) {
throw new JMSRuntimeException("Please specify a non-zero length byte[]");
}
jmsHeaderCorrelationIDAsBytes = Arrays.copyOf(correlationID, correlationID.length);
return this;
}
@Override
public byte[] getJMSCorrelationIDAsBytes() {
return Arrays.copyOf(jmsHeaderCorrelationIDAsBytes, jmsHeaderCorrelationIDAsBytes.length);
}
@Override
public JMSProducer setJMSCorrelationID(String correlationID) {
jmsHeaderCorrelationID = correlationID;
return this;
}
@Override
public String getJMSCorrelationID() {
return jmsHeaderCorrelationID;
}
@Override
public JMSProducer setJMSType(String type) {
jmsHeaderType = type;
return this;
}
@Override
public String getJMSType() {
return jmsHeaderType;
}
@Override
public JMSProducer setJMSReplyTo(Destination replyTo) {
jmsHeaderReplyTo = replyTo;
return this;
}
@Override
public Destination getJMSReplyTo() {
return jmsHeaderReplyTo;
}
private void checkName(String name) {
if (name == null) {
throw ActiveMQJMSClientBundle.BUNDLE.nameCannotBeNull();
}
if (name.equals("")) {
throw ActiveMQJMSClientBundle.BUNDLE.nameCannotBeEmpty();
}
}
final class CompletionListenerWrapper implements CompletionListener {
private final CompletionListener wrapped;
CompletionListenerWrapper(CompletionListener wrapped) {
this.wrapped = wrapped;
}
@Override
public void onCompletion(Message message) {
context.getThreadAwareContext().setCurrentThread(true);
try {
wrapped.onCompletion(message);
} finally {
context.getThreadAwareContext().clearCurrentThread(true);
}
}
@Override
public void onException(Message message, Exception exception) {
context.getThreadAwareContext().setCurrentThread(true);
try {
wrapped.onException(message, exception);
} finally {
context.getThreadAwareContext().clearCurrentThread(true);
}
}
}
}