blob: 24a802caf515627e0d67ca086d53952dd757a147 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* more patents listed at http://www.pivotal.io/patents.
*========================================================================
*/
package com.gemstone.gemfire.internal.util;
import java.io.IOException;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.distributed.internal.DMStats;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.internal.ByteArrayDataInput;
import com.gemstone.gemfire.internal.DSCODE;
import com.gemstone.gemfire.internal.HeapDataOutputStream;
import com.gemstone.gemfire.internal.Version;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.Chunk;
import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
import com.gemstone.gemfire.pdx.internal.PdxInputStream;
/**
* A "blob" is a serialized representation of an object into a byte[].
* BlobHelper provides utility methods for
* serializing and deserializing the object.
*
*
*/
public class BlobHelper {
/**
* A blob is a serialized Object. This method serializes the object into a
* blob and returns the byte array that contains the blob.
*/
public static byte[] serializeToBlob(Object obj) throws IOException {
return serializeToBlob(obj, null);
}
/**
* A blob is a serialized Object. This method serializes the
* object into a blob and returns the byte array that contains the blob.
*/
public static byte[] serializeToBlob(Object obj, Version version)
throws IOException
{
final long start = startSerialization();
HeapDataOutputStream hdos = new HeapDataOutputStream(version);
DataSerializer.writeObject(obj, hdos);
byte[] result = hdos.toByteArray();
endSerialization(start, result.length);
return result;
}
/**
* A blob is a serialized Object. This method serializes the
* object into the given HeapDataOutputStream.
*/
public static void serializeTo(Object obj, HeapDataOutputStream hdos)
throws IOException
{
final int startBytes = hdos.size();
final long start = startSerialization();
DataSerializer.writeObject(obj, hdos);
endSerialization(start, hdos.size()-startBytes);
}
/**
* A blob is a serialized Object. This method
* returns the deserialized object.
*/
public static Object deserializeBlob(byte[] blob) throws IOException,
ClassNotFoundException {
return deserializeBlob(blob, null, null);
}
/**
* A blob is a serialized Object. This method
* returns the deserialized object.
*/
public static Object deserializeBlob(byte[] blob, Version version,
ByteArrayDataInput in) throws IOException, ClassNotFoundException {
Object result;
final long start = startDeserialization();
/*
final StaticSystemCallbacks sysCb;
if (version != null && (sysCb = GemFireCacheImpl.FactoryStatics
.systemCallbacks) != null) {
// may need to change serialized shape for SQLFire
result = sysCb.fromVersion(blob, true, version, in);
}
else*/ if (blob.length > 0 && blob[0] == DSCODE.PDX) {
// If the first byte of blob indicates a pdx then wrap
// blob in a PdxInputStream instead.
// This will prevent us from making a copy of the byte[]
// every time we deserialize a PdxInstance.
PdxInputStream is = new PdxInputStream(blob);
result = DataSerializer.readObject(is);
} else {
// if we have a nested pdx then we want to make a copy
// when a PdxInstance is created so that the byte[] will
// just have the pdx bytes and not the outer objects bytes.
if (in == null) {
in = new ByteArrayDataInput();
}
in.initialize(blob, version);
result = DataSerializer.readObject(in);
}
endDeserialization(start, blob.length);
// this causes a small performance drop in d-no-ack performance tests
// if (dis.available() != 0) {
// LogWriterI18n lw = InternalDistributedSystem.getLoggerI18n();
// if (lw != null && lw.warningEnabled()) {
// lw.warning(
// LocalizedStrings.BlobHelper_DESERIALIZATION_OF_A_0_DID_NOT_READ_1_BYTES_THIS_INDICATES_A_LOGIC_ERROR_IN_THE_SERIALIZATION_CODE_FOR_THIS_CLASS,
// new Object[] {((result!=null) ? result.getClass().getName() : "NULL"), Integer.valueOf(dis.available())});
//
// }
// }
return result;
}
/**
* A blob is a serialized Object. This method
* returns the deserialized object.
* If a PdxInstance is returned then it will refer to Chunk's off-heap memory
* with an unretained reference.
*/
public static @Unretained Object deserializeOffHeapBlob(Chunk blob) throws IOException, ClassNotFoundException {
Object result;
final long start = startDeserialization();
// For both top level and nested pdxs we just want a reference to this off-heap blob.
// No copies.
// For non-pdx we want a stream that will read directly from the chunk.
PdxInputStream is = new PdxInputStream(blob);
result = DataSerializer.readObject(is);
endDeserialization(start, blob.getDataSize());
return result;
}
public static Object deserializeBuffer(ByteArrayDataInput in, int numBytes)
throws IOException, ClassNotFoundException {
final long start = startDeserialization();
Object result = DataSerializer.readObject(in);
endDeserialization(start, numBytes);
return result;
}
private static long startSerialization() {
long result = 0;
DMStats stats = InternalDistributedSystem.getDMStats();
if (stats != null) {
result = stats.startSerialization();
}
return result;
}
private static void endSerialization(long start, int bytes) {
DMStats stats = InternalDistributedSystem.getDMStats();
if (stats != null) {
stats.endSerialization(start, bytes);
}
}
private static long startDeserialization() {
long result = 0;
DMStats stats = InternalDistributedSystem.getDMStats();
if (stats != null) {
result = stats.startDeserialization();
}
return result;
}
private static void endDeserialization(long start, int bytes) {
DMStats stats = InternalDistributedSystem.getDMStats();
if (stats != null) {
stats.endDeserialization(start, bytes);
}
}
}