/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.translator.accumulo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Arrays;
import org.apache.accumulo.core.client.lexicoder.BigIntegerLexicoder;
import org.apache.accumulo.core.client.lexicoder.BytesLexicoder;
import org.apache.accumulo.core.client.lexicoder.DateLexicoder;
import org.apache.accumulo.core.client.lexicoder.DoubleLexicoder;
import org.apache.accumulo.core.client.lexicoder.IntegerLexicoder;
import org.apache.accumulo.core.client.lexicoder.LongLexicoder;
import org.apache.accumulo.core.client.lexicoder.StringLexicoder;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.core.types.BinaryType;
import org.teiid.core.types.BlobImpl;
import org.teiid.core.types.BlobType;
import org.teiid.core.types.ClobImpl;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.types.GeometryType;
import org.teiid.core.types.InputStreamFactory;
import org.teiid.core.types.SQLXMLImpl;
import org.teiid.core.types.TransformationException;
import org.teiid.core.util.ObjectConverterUtil;
public class AccumuloDataTypeManager {
public static byte[] EMPTY_BYTES = new byte[0];
private static BytesLexicoder bytesLexicoder = new BytesLexicoder();
private static BigIntegerLexicoder bigIntegerLexicoder = new BigIntegerLexicoder();
private static DateLexicoder dateLexicoder = new DateLexicoder();
private static DoubleLexicoder doubleLexicoder = new DoubleLexicoder();
private static IntegerLexicoder integerLexicoder = new IntegerLexicoder();
private static LongLexicoder longLexicoder = new LongLexicoder();
private static StringLexicoder stringLexicoder = new StringLexicoder();
private static Charset UTF_8 = Charset.forName("UTF-8");
public static byte[] serialize(Object value) {
if (value == null) {
return EMPTY_BYTES;
}
try {
if (value instanceof Clob) {
// TODO:Accumulo streaming support would have been good?
// this type materialization of the value is BAD
Clob clob = (Clob)value;
return ObjectConverterUtil.convertToByteArray(clob.getAsciiStream());
} else if (value instanceof GeometryType) {
GeometryType geometry = (GeometryType)value;
//TODO: handle srid
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectConverterUtil.write(baos, geometry.getBinaryStream(), -1, true);
int srid = geometry.getSrid();
baos.write((srid >>> 24) & 0xFF);
baos.write((srid >>> 16) & 0xFF);
baos.write((srid >>> 8) & 0xFF);
baos.write((srid >>> 0) & 0xFF);
return baos.toByteArray();
} else if (value instanceof Blob) {
// TODO: same as CLOB
Blob blob = (Blob)value;
return ObjectConverterUtil.convertToByteArray(blob.getBinaryStream());
} else if (value instanceof SQLXML) {
// TODO: same as CLOB
SQLXML xml = (SQLXML)value;
return ObjectConverterUtil.convertToByteArray(xml.getBinaryStream());
} else if (value instanceof BinaryType) {
BinaryType binary = (BinaryType)value;
return binary.getBytes();
} else if (value instanceof byte[]) {
return bytesLexicoder.encode((byte[])value);
}
else if (value instanceof Object[] ) {
throw new TeiidRuntimeException(AccumuloPlugin.Event.TEIID19003,
AccumuloPlugin.Util.gs(AccumuloPlugin.Event.TEIID19003));
}
else if (value instanceof String ||
value instanceof Boolean ||
value instanceof Byte ||
value instanceof Short ||
value instanceof Character ||
value instanceof Integer ||
value instanceof Long ||
value instanceof BigInteger ||
value instanceof BigDecimal ||
value instanceof Float ||
value instanceof Double ||
value instanceof Date ||
value instanceof Time ||
value instanceof Timestamp) {
return ((String)DataTypeManager.transformValue(value, String.class)).getBytes(UTF_8);
}
else {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(value);
oos.close();
baos.close();
return baos.toByteArray();
}
} catch (IOException e) {
throw new TeiidRuntimeException(e);
} catch (SQLException e) {
throw new TeiidRuntimeException(e);
} catch (TransformationException e) {
throw new TeiidRuntimeException(e);
}
}
public static Object deserialize(final byte[] value, final Class<?> expectedType) {
if (value == null || Arrays.equals(value, EMPTY_BYTES)) {
return null;
}
try {
if (expectedType.isAssignableFrom(Clob.class)) {
return new ClobImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return ObjectConverterUtil.convertToInputStream(value);
}
}, -1);
} else if (expectedType.isAssignableFrom(Blob.class)) {
return new BlobType(new BlobImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return ObjectConverterUtil.convertToInputStream(value);
}
}));
} else if (expectedType.isAssignableFrom(SQLXML.class)) {
return new SQLXMLImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return ObjectConverterUtil.convertToInputStream(value);
}
});
} else if (expectedType.isAssignableFrom(BinaryType.class)) {
return new BinaryType(value);
} else if (expectedType.isAssignableFrom(GeometryType.class)) {
GeometryType result = new GeometryType(Arrays.copyOf(value, value.length -4));
int srid = (((value[value.length - 4] & 0xff) << 24) +
((value[value.length - 3] & 0xff) << 16) +
((value[value.length - 2] & 0xff) << 8) +
((value[value.length - 1] & 0xff) << 0));
result.setSrid(srid);
return result;
} else if (expectedType.isAssignableFrom(byte[].class)) {
return value;
} else if (expectedType.isAssignableFrom(String.class)
|| expectedType.isAssignableFrom(Boolean.class)
|| expectedType.isAssignableFrom(Boolean.class)
|| expectedType.isAssignableFrom(Byte.class)
|| expectedType.isAssignableFrom(Short.class)
|| expectedType.isAssignableFrom(Character.class)
|| expectedType.isAssignableFrom(Integer.class)
|| expectedType.isAssignableFrom(Long.class)
|| expectedType.isAssignableFrom(BigInteger.class)
|| expectedType.isAssignableFrom(BigDecimal.class)
|| expectedType.isAssignableFrom(Float.class)
|| expectedType.isAssignableFrom(Double.class)
|| expectedType.isAssignableFrom(Date.class)
|| expectedType.isAssignableFrom(Time.class)
|| expectedType.isAssignableFrom(Timestamp.class)) {
return DataTypeManager.transformValue(new String(value, UTF_8), expectedType);
}
else {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(value));
Object obj = ois.readObject();
ois.close();
return obj;
}
} catch (ClassNotFoundException e) {
throw new TeiidRuntimeException(e);
} catch (IOException e) {
throw new TeiidRuntimeException(e);
} catch (TransformationException e) {
throw new TeiidRuntimeException(e);
}
}
private static byte[] toLexiCode(Object value) {
if (value == null) {
return EMPTY_BYTES;
}
try {
if (value instanceof java.sql.Date
|| value instanceof java.sql.Timestamp
|| value instanceof java.sql.Time) {
return dateLexicoder.encode((java.util.Date)value);
} else if (value instanceof Long) {
return longLexicoder.encode((Long)value);
} else if (value instanceof Double) {
return doubleLexicoder.encode((Double)value);
} else if (value instanceof Float) {
return doubleLexicoder.encode(((Float)value).doubleValue());
} else if (value instanceof Integer) {
return integerLexicoder.encode((Integer)value);
} else if (value instanceof BigInteger) {
return bigIntegerLexicoder.encode((BigInteger)value);
} else if (value instanceof BigDecimal) {
return stringLexicoder.encode(((BigDecimal)value).toPlainString());
} else if (value instanceof Byte) {
return integerLexicoder.encode(((Byte)value).intValue());
} else if (value instanceof Short) {
return integerLexicoder.encode(((Short)value).intValue());
} else if (value instanceof Clob) {
// TODO:Accumulo streaming support would have been good?
// this type materialization of the value is BAD
Clob clob = (Clob)value;
return bytesLexicoder.encode(ObjectConverterUtil.convertToByteArray(clob.getAsciiStream()));
} else if (value instanceof Blob) {
// TODO: same as CLOB
Blob blob = (Blob)value;
return bytesLexicoder.encode(ObjectConverterUtil.convertToByteArray(blob.getBinaryStream()));
} else if (value instanceof SQLXML) {
// TODO: same as CLOB
SQLXML xml = (SQLXML)value;
return bytesLexicoder.encode(ObjectConverterUtil.convertToByteArray(xml.getBinaryStream()));
} else if (value instanceof BinaryType) {
BinaryType binary = (BinaryType)value;
return bytesLexicoder.encode(binary.getBytes());
} else if (value instanceof GeometryType) {
GeometryType geometry = (GeometryType)value;
return bytesLexicoder.encode(ObjectConverterUtil.convertToByteArray(geometry.getBinaryStream()));
} else if (value instanceof byte[]) {
return bytesLexicoder.encode((byte[])value);
}
else if (value instanceof Object[] ) {
throw new TeiidRuntimeException(AccumuloPlugin.Event.TEIID19003, AccumuloPlugin.Util.gs(AccumuloPlugin.Event.TEIID19003));
}
return stringLexicoder.encode(((String)DataTypeManager.transformValue(value, String.class)));
} catch (TransformationException e) {
throw new TeiidRuntimeException(e);
} catch (SQLException e) {
throw new TeiidRuntimeException(e);
} catch (IOException e) {
throw new TeiidRuntimeException(e);
}
}
private static Object fromLexiCode(final byte[] value, final Class<?> expectedType) {
if (value == null || Arrays.equals(value, EMPTY_BYTES)) {
return null;
}
if (expectedType.isAssignableFrom(String.class)) {
return stringLexicoder.decode(value);
} else if (expectedType.isAssignableFrom(java.sql.Date.class)) {
return new java.sql.Date(dateLexicoder.decode(value).getTime());
} else if (expectedType.isAssignableFrom(java.sql.Timestamp.class)) {
return new java.sql.Timestamp(dateLexicoder.decode(value).getTime());
} else if (expectedType.isAssignableFrom(java.sql.Time.class)) {
return new java.sql.Time(dateLexicoder.decode(value).getTime());
} else if (expectedType.isAssignableFrom(Long.class)) {
return longLexicoder.decode(value);
} else if (expectedType.isAssignableFrom( Double.class)) {
return doubleLexicoder.decode(value);
} else if (expectedType.isAssignableFrom(Float.class)) {
return doubleLexicoder.decode(value).floatValue();
} else if (expectedType.isAssignableFrom(Integer.class)) {
return integerLexicoder.decode(value);
} else if (expectedType.isAssignableFrom(BigInteger.class)) {
return bigIntegerLexicoder.decode(value);
} else if (expectedType.isAssignableFrom(BigDecimal.class)) {
return new BigDecimal(stringLexicoder.decode(value));
} else if (expectedType.isAssignableFrom(Byte.class)) {
return integerLexicoder.decode(value).byteValue();
} else if (expectedType.isAssignableFrom(Short.class)) {
return integerLexicoder.decode(value).shortValue();
} else if (expectedType.isAssignableFrom(Clob.class)) {
return new ClobImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return ObjectConverterUtil.convertToInputStream(bytesLexicoder.decode(value));
}
}, -1);
} else if (expectedType.isAssignableFrom(Blob.class)) {
return new BlobType(new BlobImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return ObjectConverterUtil.convertToInputStream(bytesLexicoder.decode(value));
}
}));
} else if (expectedType.isAssignableFrom(SQLXML.class)) {
return new SQLXMLImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return ObjectConverterUtil.convertToInputStream(bytesLexicoder.decode(value));
}
});
} else if (expectedType.isAssignableFrom(BinaryType.class)) {
return new BinaryType(bytesLexicoder.decode(value));
} else if (expectedType.isAssignableFrom(GeometryType.class)) {
return new GeometryType(bytesLexicoder.decode(value));
} else if (expectedType.isAssignableFrom(byte[].class)) {
return bytesLexicoder.decode(value);
}
else {
throw new TeiidRuntimeException(AccumuloPlugin.Event.TEIID19004,
AccumuloPlugin.Util.gs(AccumuloPlugin.Event.TEIID19004,
expectedType.getName()));
}
}
}