/* * 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; } }