org.apache.qpid.jms.message.JmsMessage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qpid-jms-client Show documentation
Show all versions of qpid-jms-client Show documentation
The core JMS Client implementation
/*
* 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.qpid.jms.message;
import static org.apache.qpid.jms.message.JmsMessagePropertySupport.convertPropertyTo;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import jakarta.jms.DeliveryMode;
import jakarta.jms.Destination;
import jakarta.jms.JMSException;
import jakarta.jms.MessageFormatException;
import jakarta.jms.MessageNotReadableException;
import jakarta.jms.MessageNotWriteableException;
import org.apache.qpid.jms.JmsAcknowledgeCallback;
import org.apache.qpid.jms.JmsConnection;
import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
import org.apache.qpid.jms.message.facade.JmsMessageFacade;
public class JmsMessage implements jakarta.jms.Message {
private static final String ID_PREFIX = "ID:";
protected transient JmsAcknowledgeCallback acknowledgeCallback;
protected transient JmsConnection connection;
protected final JmsMessageFacade facade;
protected boolean readOnly;
protected boolean readOnlyBody;
protected boolean readOnlyProperties;
protected boolean validatePropertyNames = true;
public JmsMessage(JmsMessageFacade facade) {
this.facade = facade;
}
public JmsMessage copy() throws JMSException {
JmsMessage other = new JmsMessage(facade.copy());
other.copy(this);
return other;
}
protected void copy(JmsMessage other) {
this.readOnlyBody = other.readOnlyBody;
this.readOnlyProperties = other.readOnlyProperties;
this.acknowledgeCallback = other.acknowledgeCallback;
this.connection = other.connection;
this.validatePropertyNames = other.validatePropertyNames;
}
@Override
public int hashCode() {
Object id = facade.getMessageId();
if (id != null) {
return id.hashCode();
} else {
return super.hashCode();
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || o.getClass() != getClass()) {
return false;
}
JmsMessage msg = (JmsMessage) o;
Object oMsg = msg.facade.getMessageId();
Object thisMsg = facade.getMessageId();
return thisMsg != null && oMsg != null && oMsg.equals(thisMsg);
}
@Override
public void acknowledge() throws JMSException {
if (acknowledgeCallback != null) {
try {
acknowledgeCallback.acknowledge();
acknowledgeCallback = null;
} catch (Throwable e) {
throw JmsExceptionSupport.create(e);
}
}
}
@Override
public boolean isBodyAssignableTo(@SuppressWarnings("rawtypes") Class target) throws JMSException {
return true;
}
@Override
public final T getBody(Class asType) throws JMSException {
if (isBodyAssignableTo(asType)) {
return doGetBody(asType);
}
throw new MessageFormatException("Message body cannot be read as type: " + asType);
}
protected T doGetBody(Class asType) throws JMSException {
return null;
}
@Override
public void clearBody() throws JMSException {
checkReadOnly();
readOnlyBody = false;
facade.clearBody();
}
public boolean isValidatePropertyNames() {
return validatePropertyNames;
}
public void setValidatePropertyNames(boolean validatePropertyNames) {
this.validatePropertyNames = validatePropertyNames;
}
public boolean isReadOnly() {
return this.readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
public boolean isReadOnlyBody() {
return this.readOnlyBody;
}
public void setReadOnlyBody(boolean readOnlyBody) {
this.readOnlyBody = readOnlyBody;
}
public boolean isReadOnlyProperties() {
return this.readOnlyProperties;
}
public void setReadOnlyProperties(boolean readOnlyProperties) {
this.readOnlyProperties = readOnlyProperties;
}
@Override
public String getJMSMessageID() throws JMSException {
String id = facade.getMessageId();
if (id != null && !id.startsWith(ID_PREFIX)) {
id = ID_PREFIX + id;
}
return id;
}
@Override
public void setJMSMessageID(String value) throws JMSException {
checkReadOnly();
facade.setMessageId(value);
}
@Override
public long getJMSTimestamp() throws JMSException {
return facade.getTimestamp();
}
@Override
public void setJMSTimestamp(long timestamp) throws JMSException {
checkReadOnly();
facade.setTimestamp(timestamp);
}
@Override
public String getJMSCorrelationID() throws JMSException {
return facade.getCorrelationId();
}
@Override
public void setJMSCorrelationID(String correlationId) throws JMSException {
checkReadOnly();
facade.setCorrelationId(correlationId);
}
@Override
public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
return facade.getCorrelationIdBytes();
}
@Override
public void setJMSCorrelationIDAsBytes(byte[] correlationId) throws JMSException {
checkReadOnly();
facade.setCorrelationIdBytes(correlationId);
}
@Override
public Destination getJMSReplyTo() throws JMSException {
return facade.getReplyTo();
}
@Override
public void setJMSReplyTo(Destination destination) throws JMSException {
checkReadOnly();
facade.setReplyTo(JmsMessageTransformation.transformDestination(connection, destination));
}
@Override
public Destination getJMSDestination() throws JMSException {
return facade.getDestination();
}
@Override
public void setJMSDestination(Destination destination) throws JMSException {
checkReadOnly();
facade.setDestination(JmsMessageTransformation.transformDestination(connection, destination));
}
@Override
public int getJMSDeliveryMode() throws JMSException {
return facade.isPersistent() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT;
}
@Override
public void setJMSDeliveryMode(int mode) throws JMSException {
checkReadOnly();
switch (mode) {
case DeliveryMode.PERSISTENT:
facade.setPersistent(true);
break;
case DeliveryMode.NON_PERSISTENT:
facade.setPersistent(false);
break;
default:
throw new JMSException(String.format("Invalid DeliveryMode specific: %d", mode));
}
}
@Override
public boolean getJMSRedelivered() throws JMSException {
return facade.isRedelivered();
}
@Override
public void setJMSRedelivered(boolean redelivered) throws JMSException {
checkReadOnly();
facade.setRedelivered(redelivered);
}
@Override
public String getJMSType() throws JMSException {
return facade.getType();
}
@Override
public void setJMSType(String type) throws JMSException {
checkReadOnly();
facade.setType(type);
}
@Override
public long getJMSExpiration() throws JMSException {
return facade.getExpiration();
}
@Override
public void setJMSExpiration(long expiration) throws JMSException {
checkReadOnly();
facade.setExpiration(expiration);
}
@Override
public int getJMSPriority() throws JMSException {
return facade.getPriority();
}
@Override
public void setJMSPriority(int priority) throws JMSException {
checkReadOnly();
if (priority < 0 || priority > 9) {
throw new JMSException(String.format("Priority value given {%d} is out of range (0..9)", priority));
}
facade.setPriority(priority);
}
@Override
public long getJMSDeliveryTime() throws JMSException {
return facade.getDeliveryTime();
}
@Override
public void setJMSDeliveryTime(long deliveryTime) throws JMSException {
checkReadOnly();
facade.setDeliveryTime(deliveryTime, true);
}
@Override
public void clearProperties() throws JMSException {
checkReadOnly();
JmsMessagePropertyIntercepter.clearProperties(this, true);
}
@Override
public boolean propertyExists(String name) throws JMSException {
return JmsMessagePropertyIntercepter.propertyExists(this, name);
}
@Override
public Enumeration> getPropertyNames() throws JMSException {
return Collections.enumeration(JmsMessagePropertyIntercepter.getPropertyNames(this, true));
}
/**
* return all property names, including standard JMS properties and JMSX
* properties
*
* @return Enumeration of all property names on this message
*
* @throws JMSException if an error occurs while reading the properties from the Message.
*/
public Enumeration> getAllPropertyNames() throws JMSException {
Set result = new HashSet();
result.addAll(JmsMessagePropertyIntercepter.getAllPropertyNames(this));
return Collections.enumeration(result);
}
@Override
public void setObjectProperty(String name, Object value) throws JMSException {
checkReadOnly();
JmsMessagePropertyIntercepter.setProperty(this, name, value);
}
@Override
public Object getObjectProperty(String name) throws JMSException {
return JmsMessagePropertyIntercepter.getProperty(this, name);
}
@Override
public boolean getBooleanProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), Boolean.class);
}
@Override
public byte getByteProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), Byte.class);
}
@Override
public short getShortProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), Short.class);
}
@Override
public int getIntProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), Integer.class);
}
@Override
public long getLongProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), Long.class);
}
@Override
public float getFloatProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), Float.class);
}
@Override
public double getDoubleProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), Double.class);
}
@Override
public String getStringProperty(String name) throws JMSException {
return convertPropertyTo(name, getObjectProperty(name), String.class);
}
@Override
public void setBooleanProperty(String name, boolean value) throws JMSException {
setObjectProperty(name, Boolean.valueOf(value));
}
@Override
public void setByteProperty(String name, byte value) throws JMSException {
setObjectProperty(name, Byte.valueOf(value));
}
@Override
public void setShortProperty(String name, short value) throws JMSException {
setObjectProperty(name, Short.valueOf(value));
}
@Override
public void setIntProperty(String name, int value) throws JMSException {
setObjectProperty(name, Integer.valueOf(value));
}
@Override
public void setLongProperty(String name, long value) throws JMSException {
setObjectProperty(name, Long.valueOf(value));
}
@Override
public void setFloatProperty(String name, float value) throws JMSException {
setObjectProperty(name, Float.valueOf(value));
}
@Override
public void setDoubleProperty(String name, double value) throws JMSException {
setObjectProperty(name, Double.valueOf(value));
}
@Override
public void setStringProperty(String name, String value) throws JMSException {
setObjectProperty(name, value);
}
public JmsAcknowledgeCallback getAcknowledgeCallback() {
return acknowledgeCallback;
}
public void setAcknowledgeCallback(JmsAcknowledgeCallback jmsAcknowledgeCallback) {
this.acknowledgeCallback = jmsAcknowledgeCallback;
}
/**
* Used to trigger processing required to place the message in a state where it is
* ready to be written to the wire. This processing can include such tasks as ensuring
* that the proper message headers are set or compressing message bodies etc. During this
* call the message is placed in a read-only mode and will not be returned to a writable
* state until send completion is triggered.
*
* @param producerTtl
* the time to live value that the producer was configured with at send time.
*
* @throws JMSException if an error occurs while preparing the message for send.
*/
public void onSend(long producerTtl) throws JMSException {
setReadOnly(true);
facade.onSend(producerTtl);
}
/**
* Used to trigger processing required to place the message into a writable state once
* again following completion of the send operation.
*/
public void onSendComplete() {
setReadOnly(false);
}
/**
* Used to trigger processing required before dispatch of a message to its intended
* consumer. This method should perform any needed decoding or message property
* processing prior to the message arriving at a consumer.
*
* @throws JMSException if an error occurs while preparing the message for dispatch.
*/
public void onDispatch() throws JMSException {
setReadOnly(false);
setReadOnlyBody(true);
setReadOnlyProperties(true);
facade.onDispatch();
}
public JmsConnection getConnection() {
return connection;
}
public void setConnection(JmsConnection connection) {
this.connection = connection;
}
public JmsMessageFacade getFacade() {
return this.facade;
}
public boolean isExpired() {
long expireTime = facade.getExpiration();
return expireTime > 0 && System.currentTimeMillis() > expireTime;
}
@Override
public String toString() {
return "JmsMessage { " + facade + " }";
}
//----- State validation methods -----------------------------------------//
protected void checkReadOnly() throws MessageNotWriteableException {
if (readOnly) {
throw new MessageNotWriteableException("Message is currently read-only");
}
}
protected void checkReadOnlyProperties() throws MessageNotWriteableException {
if (readOnly || readOnlyProperties) {
throw new MessageNotWriteableException("Message properties are read-only");
}
}
protected void checkReadOnlyBody() throws MessageNotWriteableException {
if (readOnly || readOnlyBody) {
throw new MessageNotWriteableException("Message body is read-only");
}
}
protected void checkWriteOnlyBody() throws MessageNotReadableException {
if (!readOnlyBody) {
throw new MessageNotReadableException("Message body is write-only");
}
}
}