/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.communication.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.apache.commons.io.IOUtils;
import de.rcenvironment.core.communication.common.SerializationException;
import de.rcenvironment.core.toolkitbridge.transitional.StatsCounter;
/**
* Message-related utilities like serialization/deserialization.
*
* @author Robert Mischke
*/
public final class MessageUtils {
private static final int INITIAL_SERIALIZATION_BUFFER_SIZE = 512;
private MessageUtils() {}
/**
* Serializes an object for sending it as a byte array.
*
* @param object the object to serialize
* @return the byte array form of the object
* @throws SerializationException on serialization failure
*/
public static byte[] serializeObject(Serializable object) throws SerializationException {
return serialize(object);
}
/**
* Serializes an object for sending it as a byte array, but unlike
* {@link #serializeObject(Serializable)}, this method converts any
* {@link SerializationException} into a {@link RuntimeException}. This is intended for objects
* that were not received over the network, but generated locally instead. If such an object
* fails to serialize, it is the result of a local programming error, where throwing a
* {@link RuntimeException} is appropriate.
*
* @param object the object to serialize
* @return the byte array form of the object
*/
public static byte[] serializeSafeObject(Serializable object) {
try {
return serialize(object);
} catch (SerializationException e) {
throw new RuntimeException(e);
}
}
/**
* Deserializes an object from a byte array and returns it as a {@link Serializable}. This
* method should always be used when the serialized object may be of a non-primitive Java type
* to ensure proper OSGi classloader access.
*
* @param data the byte array form of the serialized object
*
* @return the reconstructed object
* @throws SerializationException on deserialization failure
*/
public static Serializable deserializeObject(byte[] data) throws SerializationException {
return deserializeObject(data, Serializable.class);
}
/**
* Deserializes an object from a byte array, with an explicit return type parameter. This method
* should always be used when the serialized object may be of a non-primitive Java type to
* ensure proper OSGi classloader access.
*
* @param data the byte array form of the serialized object
* @param <T> the type of the object to restore
* @param clazz the class of the object to restore
* @return the reconstructed object
* @throws SerializationException on deserialization failure
*/
@SuppressWarnings("unchecked")
public static <T> T deserializeObject(byte[] data, Class<T> clazz) throws SerializationException {
return (T) deserialize(data);
}
private static byte[] serialize(Serializable object) throws SerializationException {
StatsCounter.countClass("MessageUtils.serialize()", object);
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream(INITIAL_SERIALIZATION_BUFFER_SIZE);
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
} catch (IOException ex) {
throw new SerializationException(ex);
} finally {
IOUtils.closeQuietly(oos);
}
return baos.toByteArray();
}
private static Object deserialize(byte[] data) throws SerializationException {
if (data == null) {
throw new SerializationException(new NullPointerException());
}
if (data.length == 0) {
throw new SerializationException("Empty array passed for deserialization");
}
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new ByteArrayInputStream(data));
Object object = ois.readObject();
StatsCounter.countClass("MessageUtils.deserialize()", object);
return object;
} catch (ClassNotFoundException ex) {
throw new SerializationException(ex);
} catch (IOException ex) {
throw new SerializationException(ex);
} finally {
IOUtils.closeQuietly(ois);
}
}
}