org.apache.activemq.artemis.jms.client.ActiveMQObjectMessage Maven / Gradle / Ivy
/*
* 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.JMSException;
import jakarta.jms.MessageFormatException;
import jakarta.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.ActiveMQException;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.client.ClientMessage;
import org.apache.activemq.artemis.api.core.client.ClientSession;
import org.apache.activemq.artemis.utils.ObjectInputStreamWithClassLoader;
/**
* ActiveMQ Artemis implementation of a JMS ObjectMessage.
*
* Don't used ObjectMessage if you want good performance!
*
* Serialization is slooooow!
*/
public class ActiveMQObjectMessage extends ActiveMQMessage implements ObjectMessage {
public static final byte TYPE = Message.OBJECT_TYPE;
// keep a snapshot of the Serializable Object as a byte[] to provide Object isolation
private byte[] data;
private final ConnectionFactoryOptions options;
protected ActiveMQObjectMessage(final ClientSession session, ConnectionFactoryOptions options) {
super(ActiveMQObjectMessage.TYPE, session);
this.options = options;
}
protected ActiveMQObjectMessage(final ClientMessage message,
final ClientSession session,
ConnectionFactoryOptions options) {
super(message, session);
this.options = options;
}
/**
* A copy constructor for foreign JMS ObjectMessages.
*/
public ActiveMQObjectMessage(final ObjectMessage foreign,
final ClientSession session,
ConnectionFactoryOptions options) throws JMSException {
super(foreign, ActiveMQObjectMessage.TYPE, session);
setObject(foreign.getObject());
this.options = options;
}
@Override
public byte getType() {
return ActiveMQObjectMessage.TYPE;
}
@Override
public void doBeforeSend() throws Exception {
message.getBodyBuffer().clear();
if (data != null) {
message.getBodyBuffer().writeInt(data.length);
message.getBodyBuffer().writeBytes(data);
}
super.doBeforeSend();
}
@Override
public void doBeforeReceive() throws ActiveMQException {
super.doBeforeReceive();
try {
int len = message.getBodyBuffer().readInt();
data = new byte[len];
message.getBodyBuffer().readBytes(data);
} catch (Exception e) {
data = null;
}
}
// ObjectMessage implementation ----------------------------------
@Override
public void setObject(final Serializable object) throws JMSException {
checkWrite();
if (object != null) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
data = baos.toByteArray();
} catch (Exception e) {
JMSException je = new JMSException("Failed to serialize object");
je.setLinkedException(e);
je.initCause(e);
throw je;
}
}
}
// lazy deserialize the Object the first time the client requests it
@Override
public Serializable getObject() throws JMSException {
if (data == null || data.length == 0) {
return null;
}
try (ObjectInputStreamWithClassLoader ois = new ObjectInputStreamWithClassLoader(new ByteArrayInputStream(data))) {
String denyList = getDeserializationDenyList();
if (denyList != null) {
ois.setDenyList(denyList);
}
String allowList = getDeserializationAllowList();
if (allowList != null) {
ois.setAllowList(allowList);
}
Serializable object = (Serializable) ois.readObject();
return object;
} catch (Exception e) {
JMSException je = new JMSException(e.getMessage());
je.setStackTrace(e.getStackTrace());
throw je;
}
}
@Override
public void clearBody() throws JMSException {
super.clearBody();
data = null;
}
@Override
protected T getBodyInternal(Class c) throws MessageFormatException {
try {
return (T) getObject();
} catch (JMSException e) {
throw new MessageFormatException("Deserialization error on ActiveMQObjectMessage");
}
}
@Override
public boolean isBodyAssignableTo(Class c) {
if (data == null) // we have no body
return true;
try {
return Serializable.class == c || Object.class == c || c.isInstance(getObject());
} catch (JMSException e) {
return false;
}
}
private String getDeserializationDenyList() {
if (options == null) {
return null;
} else {
return options.getDeserializationDenyList();
}
}
private String getDeserializationAllowList() {
if (options == null) {
return null;
} else {
return options.getDeserializationAllowList();
}
}
}