/*
* Copyright 2014 NAVER Corp.
*
* Licensed 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 com.navercorp.pinpoint.common.util;
import com.navercorp.pinpoint.common.buffer.AutomaticBuffer;
import com.navercorp.pinpoint.common.buffer.Buffer;
import com.navercorp.pinpoint.common.buffer.FixedBuffer;
import com.navercorp.pinpoint.thrift.dto.TAnnotation;
import com.navercorp.pinpoint.thrift.dto.TAnnotationValue;
import com.navercorp.pinpoint.thrift.dto.TIntStringStringValue;
import com.navercorp.pinpoint.thrift.dto.TIntStringValue;
/**
* @author emeroad
*/
public class AnnotationTranscoder {
static final byte CODE_STRING = 0;
static final byte CODE_NULL = 1;
static final byte CODE_INT = 2;
static final byte CODE_LONG = 3;
static final byte CODE_BOOLEAN_TRUE = 4;
static final byte CODE_BOOLEAN_FALSE = 5;
static final byte CODE_BYTEARRAY = 6;
static final byte CODE_BYTE = 7;
static final byte CODE_SHORT = 8;
static final byte CODE_FLOAT = 9;
static final byte CODE_DOUBLE = 10;
static final byte CODE_TOSTRING = 11;
// multivalue
static final byte CODE_INT_STRING = 20;
static final byte CODE_INT_STRING_STRING = 21;
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
public Object getMappingValue(TAnnotation annotation) {
final TAnnotationValue value = annotation.getValue();
if (value == null) {
return null;
}
return value.getFieldValue();
}
public Object decode(final byte dataType, final byte[] data) {
switch (dataType) {
case CODE_STRING:
return decodeString(data);
case CODE_BOOLEAN_TRUE:
return Boolean.TRUE;
case CODE_BOOLEAN_FALSE:
return Boolean.FALSE;
case CODE_INT: {
return BytesUtils.bytesToSVar32(data, 0);
}
case CODE_LONG: {
return BytesUtils.bytesToSVar64(data, 0);
}
case CODE_BYTE:
return data[0];
case CODE_SHORT:
// need short casting
return (short)BytesUtils.bytesToSVar32(data, 0);
case CODE_FLOAT:
return Float.intBitsToFloat(BytesUtils.bytesToInt(data, 0));
case CODE_DOUBLE:
return Double.longBitsToDouble(BytesUtils.bytesToLong(data, 0));
case CODE_BYTEARRAY:
return data;
case CODE_NULL:
return null;
case CODE_TOSTRING:
return decodeString(data);
case CODE_INT_STRING:
return decodeIntStringValue(data);
case CODE_INT_STRING_STRING:
return decodeIntStringStringValue(data);
}
throw new IllegalArgumentException("unsupported DataType:" + dataType);
}
public byte getTypeCode(Object o) {
if (o == null) {
return CODE_NULL;
}
if (o instanceof String) {
return CODE_STRING;
} else if (o instanceof Long) {
return CODE_LONG;
} else if (o instanceof Integer) {
return CODE_INT;
} else if (o instanceof Boolean) {
if (Boolean.TRUE.equals(o)) {
return CODE_BOOLEAN_TRUE;
}
return CODE_BOOLEAN_FALSE;
} else if (o instanceof Byte) {
return CODE_BYTE;
} else if (o instanceof Short) {
return CODE_SHORT;
} else if (o instanceof Float) {
// not supported by thrift
return CODE_FLOAT;
} else if (o instanceof Double) {
return CODE_DOUBLE;
} else if (o instanceof byte[]) {
return CODE_BYTEARRAY;
} else if(o instanceof TIntStringValue) {
return CODE_INT_STRING;
} else if(o instanceof TIntStringStringValue) {
return CODE_INT_STRING_STRING;
}
return CODE_TOSTRING;
}
public byte[] encode(Object o, int typeCode) {
switch (typeCode) {
case CODE_STRING:
return encodeString((String) o);
case CODE_INT: {
return BytesUtils.intToSVar32((Integer) o);
}
case CODE_BOOLEAN_TRUE: {
return EMPTY_BYTE_ARRAY;
}
case CODE_BOOLEAN_FALSE: {
return EMPTY_BYTE_ARRAY;
}
case CODE_LONG: {
return BytesUtils.longToSVar64((Long) o);
}
case CODE_BYTE: {
final byte[] bytes = new byte[1];
bytes[0] = (Byte)o;
return bytes;
}
case CODE_SHORT: {
return BytesUtils.intToSVar32((Short) o);
}
case CODE_FLOAT: {
final byte[] buffer = new byte[BytesUtils.INT_BYTE_LENGTH];
BytesUtils.writeInt(Float.floatToRawIntBits((Float) o), buffer, 0);
return buffer;
}
case CODE_DOUBLE: {
final byte[] buffer = new byte[BytesUtils.LONG_BYTE_LENGTH];
BytesUtils.writeLong(Double.doubleToRawLongBits((Double) o), buffer, 0);
return buffer;
}
case CODE_BYTEARRAY:
return (byte[]) o;
case CODE_NULL:
return null;
case CODE_TOSTRING:
final String str = o.toString();
return encodeString(str);
case CODE_INT_STRING:
return encodeIntStringValue(o);
case CODE_INT_STRING_STRING:
return encodeIntStringStringValue(o);
}
throw new IllegalArgumentException("unsupported DataType:" + typeCode + " data:" + o);
}
private Object decodeIntStringValue(byte[] data) {
final Buffer buffer = new FixedBuffer(data);
final int intValue = buffer.readSVInt();
final String stringValue = BytesUtils.toString(buffer.readPrefixedBytes());
return new IntStringValue(intValue, stringValue);
}
private byte[] encodeIntStringValue(Object value) {
final TIntStringValue tIntStringValue = (TIntStringValue) value;
final int intValue = tIntStringValue.getIntValue();
final byte[] stringValue = BytesUtils.toBytes(tIntStringValue.getStringValue());
// TODO increase by a more precise value
final int bufferSize = getBufferSize(stringValue, 4 + 8);
final Buffer buffer = new AutomaticBuffer(bufferSize);
buffer.putSVInt(intValue);
buffer.putPrefixedBytes(stringValue);
return buffer.getBuffer();
}
private int getBufferSize(byte[] stringValue, int reserve) {
if (stringValue == null) {
return reserve;
} else {
return stringValue.length + reserve;
}
}
private Object decodeIntStringStringValue(byte[] data) {
final Buffer buffer = new FixedBuffer(data);
final int intValue = buffer.readSVInt();
final String stringValue1 = BytesUtils.toString(buffer.readPrefixedBytes());
final String stringValue2 = BytesUtils.toString(buffer.readPrefixedBytes());
return new IntStringStringValue(intValue, stringValue1, stringValue2);
}
private byte[] encodeIntStringStringValue(Object o) {
final TIntStringStringValue tIntStringStringValue = (TIntStringStringValue) o;
final int intValue = tIntStringStringValue.getIntValue();
final byte[] stringValue1 = BytesUtils.toBytes(tIntStringStringValue.getStringValue1());
final byte[] stringValue2 = BytesUtils.toBytes(tIntStringStringValue.getStringValue2());
// TODO increase by a more precise value
final int bufferSize = getBufferSize(stringValue1, stringValue2, 4 + 8);
final Buffer buffer = new AutomaticBuffer(bufferSize);
buffer.putSVInt(intValue);
buffer.putPrefixedBytes(stringValue1);
buffer.putPrefixedBytes(stringValue2);
return buffer.getBuffer();
}
private int getBufferSize(byte[] stringValue1, byte[] stringValue2, int reserve) {
int length = 0;
if (stringValue1 != null) {
length += stringValue1.length;
}
if (stringValue2 != null) {
length += stringValue2.length;
}
return length + reserve;
}
/**
* Decode the string with the current character set.
*/
protected String decodeString(byte[] data) {
return BytesUtils.toString(data);
}
/**
* Encode a string into the current character set.
*/
protected byte[] encodeString(String in) {
return BytesUtils.toBytes(in);
}
}