/** * Copyright (c) 2011-2015 Exxeleron GmbH * * 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.exxeleron.qjava; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * Default {@link QReader} implementation. */ public class DefaultQReader extends QReader { /** * @see com.exxeleron.qjava.QReader#readObject() */ protected Object readObject() throws QException, IOException { final QType qtype = QType.getQType(reader.get()); if ( qtype == QType.GENERAL_LIST ) { return readGeneralList(); } else if ( qtype == QType.ERROR ) { throw readError(); } else if ( qtype == QType.DICTIONARY ) { return readDictionary(); } else if ( qtype == QType.TABLE ) { return readTable(); } else if ( qtype.getTypeCode() < 0 ) { return readAtom(qtype); } else if ( qtype.getTypeCode() >= QType.BOOL_LIST.getTypeCode() && qtype.getTypeCode() <= QType.TIME_LIST.getTypeCode() ) { return readList(qtype); } else if ( qtype.getTypeCode() >= QType.LAMBDA.getTypeCode() ) { return readFunction(qtype); } throw new QReaderException("Unable to deserialize q type: " + qtype); } @SuppressWarnings("incomplete-switch") protected Object readAtom( final QType qtype ) throws QException, UnsupportedEncodingException { switch ( qtype ) { case BOOL: return reader.get() == 1 ? true : false; case GUID: return readGuid(); case BYTE: return reader.get(); case SHORT: return reader.getShort(); case INT: return reader.getInt(); case LONG: return reader.getLong(); case FLOAT: return reader.getFloat(); case DOUBLE: return reader.getDouble(); case CHAR: return (char) reader.get(); case SYMBOL: return reader.getSymbol(); case TIMESTAMP: return new QTimestamp(reader.getLong()); case MONTH: return new QMonth(reader.getInt()); case DATE: return new QDate(reader.getInt()); case DATETIME: return new QDateTime(reader.getDouble()); case TIMESPAN: return new QTimespan(reader.getLong()); case MINUTE: return new QMinute(reader.getInt()); case SECOND: return new QSecond(reader.getInt()); case TIME: return new QTime(reader.getInt()); } throw new QReaderException("Unable to deserialize q type: " + qtype); } @SuppressWarnings("incomplete-switch") protected Object readList( final QType qtype ) throws QException, UnsupportedEncodingException { reader.get(); // ignore attributes final int length = reader.getInt(); switch ( qtype ) { case BOOL_LIST: { final boolean[] list = new boolean[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.get() == 1 ? true : false; } return list; } case GUID_LIST: { final UUID[] list = new UUID[length]; for ( int i = 0; i < length; i++ ) { list[i] = readGuid(); } return list; } case BYTE_LIST: { final byte[] list = new byte[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.get(); } return list; } case SHORT_LIST: { final short[] list = new short[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.getShort(); } return list; } case INT_LIST: { final int[] list = new int[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.getInt(); } return list; } case LONG_LIST: { final long[] list = new long[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.getLong(); } return list; } case FLOAT_LIST: { final float[] list = new float[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.getFloat(); } return list; } case DOUBLE_LIST: { final double[] list = new double[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.getDouble(); } return list; } case STRING: { final byte[] buffer = new byte[length]; reader.get(buffer, 0, length); return new String(buffer, getEncoding()).toCharArray(); } case SYMBOL_LIST: { final String[] list = new String[length]; for ( int i = 0; i < length; i++ ) { list[i] = reader.getSymbol(); } return list; } case TIMESTAMP_LIST: { final QTimestamp[] list = new QTimestamp[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QTimestamp(reader.getLong()); } return list; } case MONTH_LIST: { final QMonth[] list = new QMonth[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QMonth(reader.getInt()); } return list; } case DATE_LIST: { final QDate[] list = new QDate[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QDate(reader.getInt()); } return list; } case DATETIME_LIST: { final QDateTime[] list = new QDateTime[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QDateTime(reader.getDouble()); } return list; } case TIMESPAN_LIST: { final QTimespan[] list = new QTimespan[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QTimespan(reader.getLong()); } return list; } case MINUTE_LIST: { final QMinute[] list = new QMinute[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QMinute(reader.getInt()); } return list; } case SECOND_LIST: { final QSecond[] list = new QSecond[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QSecond(reader.getInt()); } return list; } case TIME_LIST: { final QTime[] list = new QTime[length]; for ( int i = 0; i < length; i++ ) { list[i] = new QTime(reader.getInt()); } return list; } } throw new QReaderException("Unable to deserialize q type: " + qtype); } protected UUID readGuid() { return reader.getUUID(); } protected Object[] readGeneralList() throws QException, IOException { reader.get(); // ignore attributes final int length = reader.getInt(); final Object[] list = new Object[length]; for ( int i = 0; i < length; i++ ) { list[i] = readObject(); } return list; } protected QException readError() throws IOException { return new QException(reader.getSymbol()); } protected Object readDictionary() throws QException, IOException { final Object keys = readObject(); final Object values = readObject(); if ( keys != null && keys.getClass().isArray() && (values != null && values.getClass().isArray() || values instanceof QTable) ) { return new QDictionary(keys, values); } else if ( keys instanceof QTable && values instanceof QTable ) { return new QKeyedTable((QTable) keys, (QTable) values); } throw new QReaderException("Cannot create valid dictionary object from mapping: " + keys + " to " + values); } protected QTable readTable() throws QException, IOException { reader.get(); // attributes reader.get(); // dict type stamp return new QTable((String[]) readObject(), (Object[]) readObject()); } protected QFunction readFunction( final QType qtype ) throws QException, IOException { if ( qtype == QType.LAMBDA ) { reader.getSymbol(); // ignore context final String expression = new String((char[]) readObject()); return new QLambda(expression); } else if ( qtype == QType.PROJECTION ) { final int length = reader.getInt(); final Object[] parameters = new Object[length]; for ( int i = 0; i < length; i++ ) { parameters[i] = readObject(); } return new QProjection(parameters); } else if ( qtype == QType.UNARY_PRIMITIVE_FUNC ) { final byte code = reader.get(); return code == 0 ? null : new QFunction(qtype.getTypeCode()); } else if ( qtype.getTypeCode() < QType.PROJECTION.getTypeCode() ) { reader.get(); // ignore function code return new QFunction(qtype.getTypeCode()); } else if ( qtype == QType.COMPOSITION_FUNC ) { final int length = reader.getInt(); final Object[] parameters = new Object[length]; for ( int i = 0; i < length; i++ ) { parameters[i] = readObject(); } return new QFunction(qtype.getTypeCode()); } else { readObject(); // ignore function object return new QFunction(qtype.getTypeCode()); } } @SuppressWarnings("rawtypes") private static final Map<QType, Class> fromQ = Collections.unmodifiableMap(new HashMap<QType, Class>() { private static final long serialVersionUID = 7199217298785029445L; { put(QType.GENERAL_LIST, Object[].class); put(QType.BOOL, Boolean.class); put(QType.BOOL_LIST, boolean[].class); put(QType.BYTE, Byte.class); put(QType.BYTE_LIST, byte[].class); put(QType.GUID, UUID.class); put(QType.GUID_LIST, UUID[].class); put(QType.SHORT, Short.class); put(QType.SHORT_LIST, short[].class); put(QType.INT, Integer.class); put(QType.INT_LIST, int[].class); put(QType.LONG, Long.class); put(QType.LONG_LIST, long[].class); put(QType.FLOAT, Float.class); put(QType.FLOAT_LIST, float[].class); put(QType.DOUBLE, Double.class); put(QType.DOUBLE_LIST, double[].class); put(QType.CHAR, Character.class); put(QType.STRING, char[].class); put(QType.SYMBOL, String.class); put(QType.SYMBOL_LIST, String[].class); put(QType.TIMESTAMP, QTimestamp.class); put(QType.TIMESTAMP_LIST, QTimestamp[].class); put(QType.MONTH, QMonth.class); put(QType.MONTH_LIST, QMonth[].class); put(QType.DATE, QDate.class); put(QType.DATE_LIST, QDate[].class); put(QType.DATETIME, QDateTime.class); put(QType.DATETIME_LIST, QDateTime[].class); put(QType.TIMESPAN, QTimespan.class); put(QType.TIMESPAN_LIST, QTimespan[].class); put(QType.MINUTE, QMinute.class); put(QType.MINUTE_LIST, QMinute[].class); put(QType.SECOND, QSecond.class); put(QType.SECOND_LIST, QSecond[].class); put(QType.TIME, QTime.class); put(QType.TIME_LIST, QTime[].class); put(QType.ERROR, QException.class); put(QType.DICTIONARY, QDictionary.class); put(QType.TABLE, QTable.class); put(QType.KEYED_TABLE, QKeyedTable.class); put(QType.LAMBDA, QLambda.class); } }); /** * Returns default mapping for particular q type. * * @param type * Requested q type * @return type of the object being a result of q message deserialization * @throws QReaderException */ public static Class<?> getType( final QType type ) throws QReaderException { if ( fromQ.containsKey(type) ) { return fromQ.get(type); } else { throw new QReaderException("Cannot deserialize object of type: " + type); } } }