/*
* 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.infinispan.api;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
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.HashMap;
import org.infinispan.protostream.descriptors.Type;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.core.types.BlobImpl;
import org.teiid.core.types.ClobImpl;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.types.InputStreamFactory;
import org.teiid.core.types.SQLXMLImpl;
import org.teiid.core.types.TransformationException;
import org.teiid.core.types.basic.ObjectToAnyTransform;
import org.teiid.core.util.ObjectConverterUtil;
import com.squareup.protoparser.DataType;
import com.squareup.protoparser.DataType.ScalarType;
public class ProtobufDataManager {
private static HashMap<ScalarType, String> protoTypes = new HashMap<ScalarType, String>();
private static HashMap<String, ScalarType> teiidTypes = new HashMap<String, ScalarType>();
static {
protoTypes.put(ScalarType.STRING, DataTypeManager.DefaultDataTypes.STRING);
protoTypes.put(ScalarType.BOOL, DataTypeManager.DefaultDataTypes.BOOLEAN);
protoTypes.put(ScalarType.FIXED32, DataTypeManager.DefaultDataTypes.INTEGER);
protoTypes.put(ScalarType.SFIXED32, DataTypeManager.DefaultDataTypes.INTEGER);
protoTypes.put(ScalarType.INT32, DataTypeManager.DefaultDataTypes.INTEGER);
protoTypes.put(ScalarType.SINT32, DataTypeManager.DefaultDataTypes.INTEGER);
protoTypes.put(ScalarType.UINT32, DataTypeManager.DefaultDataTypes.INTEGER);
protoTypes.put(ScalarType.FIXED64, DataTypeManager.DefaultDataTypes.LONG);
protoTypes.put(ScalarType.SFIXED64, DataTypeManager.DefaultDataTypes.LONG);
protoTypes.put(ScalarType.INT64, DataTypeManager.DefaultDataTypes.LONG);
protoTypes.put(ScalarType.SINT64, DataTypeManager.DefaultDataTypes.LONG);
protoTypes.put(ScalarType.UINT64, DataTypeManager.DefaultDataTypes.LONG);
protoTypes.put(ScalarType.FLOAT, DataTypeManager.DefaultDataTypes.FLOAT);
protoTypes.put(ScalarType.DOUBLE, DataTypeManager.DefaultDataTypes.DOUBLE);
protoTypes.put(ScalarType.BYTES, DataTypeManager.DefaultDataTypes.VARBINARY);
teiidTypes.put(DataTypeManager.DefaultDataTypes.STRING, ScalarType.STRING);
teiidTypes.put(DataTypeManager.DefaultDataTypes.BOOLEAN, ScalarType.BOOL);
teiidTypes.put(DataTypeManager.DefaultDataTypes.SHORT, ScalarType.INT32);
teiidTypes.put(DataTypeManager.DefaultDataTypes.BYTE, ScalarType.INT32);
teiidTypes.put(DataTypeManager.DefaultDataTypes.SHORT, ScalarType.INT32);
teiidTypes.put(DataTypeManager.DefaultDataTypes.INTEGER, ScalarType.INT32);
teiidTypes.put(DataTypeManager.DefaultDataTypes.LONG, ScalarType.INT64);
teiidTypes.put(DataTypeManager.DefaultDataTypes.FLOAT, ScalarType.FLOAT);
teiidTypes.put(DataTypeManager.DefaultDataTypes.DOUBLE, ScalarType.DOUBLE);
teiidTypes.put(DataTypeManager.DefaultDataTypes.BIG_DECIMAL, ScalarType.BYTES);
teiidTypes.put(DataTypeManager.DefaultDataTypes.DATE, ScalarType.STRING);
teiidTypes.put(DataTypeManager.DefaultDataTypes.TIME, ScalarType.STRING);
teiidTypes.put(DataTypeManager.DefaultDataTypes.TIMESTAMP, ScalarType.STRING);
teiidTypes.put(DataTypeManager.DefaultDataTypes.BLOB, ScalarType.BYTES);
teiidTypes.put(DataTypeManager.DefaultDataTypes.CLOB, ScalarType.BYTES);
teiidTypes.put(DataTypeManager.DefaultDataTypes.XML, ScalarType.BYTES);
teiidTypes.put(DataTypeManager.DefaultDataTypes.VARBINARY, ScalarType.BYTES);
// will fail for most values
teiidTypes.put(DataTypeManager.DefaultDataTypes.OBJECT, ScalarType.BYTES);
teiidTypes.put(DataTypeManager.DefaultDataTypes.GEOMETRY, ScalarType.BYTES);
}
public static String teiidType(DataType protoType, boolean array, boolean isEnum) {
// treat all enums as integers
if (isEnum) {
return DataTypeManager.DefaultDataTypes.INTEGER;
}
String type = protoTypes.get(protoType);
if (type == null) {
type = DataTypeManager.DefaultDataTypes.STRING; // special case for enum type
}
if (array) {
type += "[]";
}
return type;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Object convertToRuntime(Class expectedType, Object contents) throws IOException {
if (contents == null || expectedType.isInstance(contents)) {
return contents;
}
if (expectedType.isArray()) {
expectedType = expectedType.getComponentType();
}
if (contents instanceof Long) {
Long rawContents = (Long) contents;
if (expectedType.isAssignableFrom(Date.class)) {
return new Date(rawContents);
} else if (expectedType.isAssignableFrom(Timestamp.class)) {
return new Timestamp(rawContents);
} else if (expectedType.isAssignableFrom(Time.class)) {
return new Time(rawContents);
}
} else if (contents instanceof String) {
} else if (contents instanceof byte[]) {
byte[] rawContents = (byte[]) contents;
if (expectedType.isAssignableFrom(String.class)) {
try {
return new String(rawContents, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IOException(e);
}
} else if (expectedType.isAssignableFrom(BigInteger.class)) {
return new BigInteger(rawContents);
} else if (expectedType.isAssignableFrom(BigDecimal.class)) {
return new BigDecimal(new BigInteger(rawContents));
} else if (expectedType.isAssignableFrom(Clob.class)) {
return new ClobImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(rawContents);
}
}, -1);
} else if (expectedType.isAssignableFrom(Blob.class)) {
return new BlobImpl(new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(rawContents);
}
});
} else if (expectedType.isAssignableFrom(SQLXML.class)) {
return new SQLXMLImpl(rawContents);
}
} else {
try {
return ObjectToAnyTransform.INSTANCE.transform(contents, expectedType);
} catch (TransformationException e) {
throw new IOException(e);
}
}
return contents;
}
public static <T> T convertToInfinispan(Class<T> expectedType, Object contents) throws IOException {
if (contents == null || expectedType.isInstance(contents)) {
return expectedType.cast(contents);
}
// date/time
if (contents instanceof Date && expectedType.isAssignableFrom(Long.class)) {
return expectedType.cast(((Date) contents).getTime());
} else if (contents instanceof Timestamp && expectedType.isAssignableFrom(Long.class)) {
return expectedType.cast(((Timestamp) contents).getTime());
} else if (contents instanceof Time && expectedType.isAssignableFrom(Long.class)) {
return expectedType.cast(((Time) contents).getTime());
} else if (contents instanceof Date && expectedType.isAssignableFrom(byte[].class)) {
long l = ((Date) contents).getTime();
return expectedType.cast(java.nio.ByteBuffer.allocate(Long.SIZE / 8).putLong(l).array());
} else if (contents instanceof Timestamp && expectedType.isAssignableFrom(byte[].class)) {
long l = ((Timestamp) contents).getTime();
return expectedType.cast(java.nio.ByteBuffer.allocate(Long.SIZE / 8).putLong(l).array());
} else if (contents instanceof Time && expectedType.isAssignableFrom(byte[].class)) {
long l = ((Time) contents).getTime();
return expectedType.cast(java.nio.ByteBuffer.allocate(Long.SIZE / 8).putLong(l).array());
} else if (contents instanceof String && expectedType.isAssignableFrom(byte[].class)) {
return expectedType.cast(((String)contents).getBytes("UTF-8"));
} else if (contents instanceof Clob && expectedType.isAssignableFrom(byte[].class)) {
try {
return expectedType.cast(ObjectConverterUtil.convertToByteArray(((Clob) contents).getAsciiStream()));
} catch (SQLException e) {
throw new IOException(e);
}
} else if (contents instanceof Blob && expectedType.isAssignableFrom(byte[].class)) {
try {
return expectedType.cast(ObjectConverterUtil.convertToByteArray(((Blob) contents).getBinaryStream(),
DataTypeManager.MAX_VARBINARY_BYTES, true));
} catch (SQLException e) {
throw new IOException(e);
}
} else if (contents instanceof SQLXML && expectedType.isAssignableFrom(byte[].class)) {
try {
return expectedType.cast(ObjectConverterUtil.convertToByteArray(((SQLXML) contents).getBinaryStream(),
DataTypeManager.MAX_VARBINARY_BYTES, true));
} catch (SQLException e) {
throw new IOException(e);
}
} else if (contents instanceof BigInteger && expectedType.isAssignableFrom(String.class)) {
return expectedType.cast(((BigInteger) contents).toString());
} else if (contents instanceof BigDecimal && expectedType.isAssignableFrom(String.class)) {
return expectedType.cast(((BigDecimal) contents).toString());
} else if (contents instanceof BigInteger && expectedType.isAssignableFrom(byte[].class)) {
return expectedType.cast(((BigInteger) contents).toByteArray());
} else if (contents instanceof BigDecimal && expectedType.isAssignableFrom(byte[].class)) {
return expectedType.cast(((BigDecimal) contents).toBigInteger().toByteArray());
}
throw new IOException("unknown type to write:" + contents.getClass());
}
public static Type parseProtobufType(String name) {
switch (name) {
case "bool":
return Type.BOOL;
case "bytes":
return Type.BYTES;
case "double":
return Type.DOUBLE;
case "float":
return Type.FLOAT;
case "fixed32":
return Type.FIXED32;
case "fixed64":
return Type.FIXED64;
case "int32":
return Type.INT32;
case "int64":
return Type.INT64;
case "sfixed32":
return Type.SFIXED32;
case "sfixed64":
return Type.SFIXED64;
case "sint32":
return Type.SINT32;
case "sint64":
return Type.SINT64;
case "string":
return Type.STRING;
case "uint32":
return Type.UINT32;
case "uint64":
return Type.UINT64;
default:
throw new TeiidRuntimeException("unrecognised type in metadata :" + name);
}
}
public static Type getCompatibleProtobufType(Class<?> type) {
if (type.isAssignableFrom(String.class) || type.isAssignableFrom(Character.class)) {
return Type.STRING;
} else if (type.isAssignableFrom(Integer.class) || type.isAssignableFrom(Short.class)
|| type.isAssignableFrom(Byte.class)) {
return Type.INT32;
} else if (type.isAssignableFrom(Long.class)) {
return Type.INT64;
} else if (type.isAssignableFrom(Boolean.class)) {
return Type.BOOL;
} else if (type.isAssignableFrom(Float.class)) {
return Type.FLOAT;
} else if (type.isAssignableFrom(Double.class)) {
return Type.DOUBLE;
}
return Type.BYTES;
}
}