com.aerospike.client.util.Packer Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2012-2014 by Aerospike.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
******************************************************************************/
package com.aerospike.client.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.aerospike.client.AerospikeException;
import com.aerospike.client.Value;
import com.aerospike.client.command.Buffer;
import com.aerospike.client.command.ParticleType;
/**
* Serialize collection objects using MessagePack format specification:
*
* http://wiki.msgpack.org/display/MSGPACK/Format+specification#Formatspecification-int32
*/
public final class Packer {
public static byte[] pack(Value[] val) throws AerospikeException {
try {
Packer packer = new Packer();
packer.packValueArray(val);
return packer.toByteArray();
}
catch (Exception e) {
throw new AerospikeException.Serialize(e);
}
}
public static byte[] pack(List> val) throws AerospikeException {
try {
Packer packer = new Packer();
packer.packList(val);
return packer.toByteArray();
}
catch (Exception e) {
throw new AerospikeException.Serialize(e);
}
}
public static byte[] pack(Map,?> val) throws AerospikeException {
try {
Packer packer = new Packer();
packer.packMap(val);
return packer.toByteArray();
}
catch (Exception e) {
throw new AerospikeException.Serialize(e);
}
}
private byte[] buffer;
private int offset;
private ArrayList bufferList;
public Packer() {
this.buffer = ThreadLocalData.getBuffer();
}
public void packValueArray(Value[] values) throws IOException {
packArrayBegin(values.length);
for (Value value : values) {
value.pack(this);
}
}
public void packList(List> list) throws IOException {
packArrayBegin(list.size());
for (Object obj : list) {
packObject(obj);
}
}
private void packArrayBegin(int size) {
if (size < 16) {
packByte(0x90 | size);
}
else if (size < 65536) {
packShort(0xdc, size);
} else {
packInt(0xdd, size);
}
}
public void packMap(Map,?> map) throws IOException {
packMapBegin(map.size());
for (Entry,?> entry : map.entrySet()) {
packObject(entry.getKey());
packObject(entry.getValue());
}
}
private void packMapBegin(int size) {
if (size < 16) {
packByte(0x80 | size);
} else if (size < 65536) {
packShort(0xde, size);
} else {
packInt(0xdf, size);
}
}
public void packBytes(byte[] b) {
packByteArrayBegin(b.length + 1);
packByte(ParticleType.BLOB);
packByteArray(b, 0, b.length);
}
public void packBytes(byte[] b, int offset, int length) {
packByteArrayBegin(length + 1);
packByte(ParticleType.BLOB);
packByteArray(b, offset, length);
}
public void packBlob(Object val) throws IOException {
ByteArrayOutputStream bstream = new ByteArrayOutputStream();
ObjectOutputStream ostream = new ObjectOutputStream(bstream);
ostream.writeObject(val);
ostream.close();
byte[] bytes = bstream.toByteArray();
packByteArrayBegin(bytes.length + 1);
packByte(ParticleType.JBLOB);
packByteArray(bytes, 0, bytes.length);
}
private void packByteArrayBegin(int len) {
if (len < 32) {
packByte(0xa0 | len);
} else if (len < 65536) {
packShort(0xda, len);
} else {
packInt(0xdb, len);
}
}
private void packObject(Object obj) throws IOException {
if (obj == null) {
packNil();
return;
}
if (obj instanceof Value) {
Value value = (Value) obj;
value.pack(this);
return;
}
if (obj instanceof byte[]) {
packBytes((byte[]) obj);
return;
}
if (obj instanceof String) {
packString((String) obj);
return;
}
if (obj instanceof Integer) {
packInt((Integer) obj);
return;
}
if (obj instanceof Long) {
packLong((Long) obj);
return;
}
if (obj instanceof List>) {
packList((List>) obj);
return;
}
if (obj instanceof Map,?>) {
packMap((Map,?>) obj);
return;
}
packBlob(obj);
}
public void packLong(long val) {
if (val >= 0L) {
if (val < 128L) {
packByte((int)val);
return;
}
if (val < 256L) {
packByte(0xcc, (int)val);
return;
}
if (val < 65536L) {
packShort(0xcd, (int)val);
return;
}
if (val < 4294967296L) {
packInt(0xce, (int)val);
return;
}
packLong(0xcf, val);
}
else {
if (val >= -32) {
packByte(0xe0 | ((int)val + 32));
return;
}
if (val >= Byte.MIN_VALUE) {
packByte(0xd0, (int)val);
return;
}
if (val >= Short.MIN_VALUE) {
packShort(0xd1, (int)val);
return;
}
if (val >= Integer.MIN_VALUE) {
packInt(0xd2, (int)val);
return;
}
packLong(0xd3, val);
}
}
public void packInt(int val) {
if (val >= 0) {
if (val < 128) {
packByte(val);
return;
}
if (val < 256) {
packByte(0xcc, val);
return;
}
if (val < 65536) {
packShort(0xcd, val);
return;
}
packInt(0xce, val);
}
else {
if (val >= -32) {
packByte(0xe0 | (val + 32));
return;
}
if (val >= Byte.MIN_VALUE) {
packByte(0xd0, val);
return;
}
if (val >= Short.MIN_VALUE) {
packShort(0xd1, val);
return;
}
packInt(0xd2, val);
}
}
public void packString(String val) {
int size = Buffer.estimateSizeUtf8(val) + 1;
packByteArrayBegin(size);
if (offset + size > buffer.length) {
resize(size);
}
buffer[offset++] = (byte)ParticleType.STRING;
offset += Buffer.stringToUtf8(val, buffer, offset);
}
private void packByteArray(byte[] src, int srcOffset, int srcLength) {
if (offset + srcLength > buffer.length) {
resize(srcLength);
}
System.arraycopy(src, srcOffset, buffer, offset, srcLength);
offset += srcLength;
}
private void packLong(int type, long val) {
if (offset + 9 > buffer.length) {
resize(9);
}
buffer[offset++] = (byte)type;
Buffer.longToBytes(val, buffer, offset);
offset += 8;
}
private void packInt(int type, int val) {
if (offset + 5 > buffer.length) {
resize(5);
}
buffer[offset++] = (byte)type;
Buffer.intToBytes(val, buffer, offset);
offset += 4;
}
private void packShort(int type, int val) {
if (offset + 3 > buffer.length) {
resize(3);
}
buffer[offset++] = (byte)type;
Buffer.shortToBytes(val, buffer, offset);
offset += 2;
}
private void packByte(int type, int val) {
if (offset + 2 > buffer.length) {
resize(2);
}
buffer[offset++] = (byte)type;
buffer[offset++] = (byte)val;
}
public void packNil() {
if (offset >= buffer.length) {
resize(1);
}
buffer[offset++] = (byte)0xc0;
}
private void packByte(int val) {
if (offset >= buffer.length) {
resize(1);
}
buffer[offset++] = (byte)val;
}
private void resize(int size) {
if (bufferList == null) {
bufferList = new ArrayList();
}
bufferList.add(new BufferItem(buffer, offset));
if (size < buffer.length) {
size = buffer.length;
}
buffer = new byte[size];
offset = 0;
}
public byte[] toByteArray() {
if (bufferList != null) {
int size = offset;
for (BufferItem item : bufferList) {
size += item.length;
}
byte[] target = new byte[size];
size = 0;
for (BufferItem item : bufferList) {
System.arraycopy(item.buffer, 0, target, size, item.length);
size += item.length;
}
System.arraycopy(buffer, 0, target, size, offset);
return target;
}
else {
byte[] target = new byte[offset];
System.arraycopy(buffer, 0, target, 0, offset);
return target;
}
}
private static final class BufferItem {
private byte[] buffer;
private int length;
private BufferItem(byte[] buffer, int length) {
this.buffer = buffer;
this.length = length;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy