blob: 8f7ae40dfbb1b1cc2422cd940d1ae535aadb2cba [file] [log] [blame]
/*
* 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.geode.internal.util;
import java.io.IOException;
import org.apache.geode.DataSerializer;
import org.apache.geode.distributed.internal.DMStats;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.internal.ByteArrayDataInput;
import org.apache.geode.internal.DSCODE;
import org.apache.geode.internal.HeapDataOutputStream;
import org.apache.geode.internal.Version;
import org.apache.geode.internal.offheap.StoredObject;
import org.apache.geode.internal.offheap.annotations.Unretained;
import org.apache.geode.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.
*
* TODO: compare performance with org.apache.commons.lang3.SerializationUtils
*/
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();
if (blob.length > 0 && blob[0] == DSCODE.PDX.toByte()) {
// 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);
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(StoredObject 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;
}
/**
* Unused
*/
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);
}
}
}