/* * 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.client.batch; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import org.teiid.client.ResizingArrayList; import org.teiid.core.types.BinaryType; import org.teiid.core.types.DataTypeManagerService; import org.teiid.core.types.DataTypeManagerService.DefaultDataTypes; import org.teiid.core.types.XMLType; import org.teiid.designer.runtime.version.spi.ITeiidServerVersion; /** * @since 4.2 */ public class Batch1Serializer extends Batch0Serializer{ protected Batch1Serializer(ITeiidServerVersion teiidVersion, byte version) { super(teiidVersion, version); serializers.put(DataTypeManagerService.DefaultDataTypes.VARBINARY.getId(), new ColumnSerializer[] { new BinaryColumnSerializer() }); version1serializers.put(DataTypeManagerService.DefaultDataTypes.XML.getId(), new XmlColumnSerializer1_B1()); version1serializers.put(DataTypeManagerService.DefaultDataTypes.OBJECT.getId(), new ObjectColumnSerializer1_B1(DataTypeManagerService.DefaultDataTypes.VARBINARY.ordinal())); version1serializers.put(DataTypeManagerService.DefaultDataTypes.VARBINARY.getId(), new BinaryColumnSerializer1()); } /** * @param teiidVersion */ public Batch1Serializer(ITeiidServerVersion teiidVersion) { this(teiidVersion, (byte) 1); } protected class BinaryColumnSerializer1 extends ColumnSerializer { @Override public void writeObject(ObjectOutput out, Object obj, Map<Object, Integer> cache, byte version) throws IOException { byte[] bytes = ((BinaryType)obj).getBytes(); out.writeInt(bytes.length); //in theory this could be a short, but we're not strictly enforcing the length out.write(bytes); } @Override public Object readObject(ObjectInput in, List<Object> cache, byte version) throws IOException { int length = in.readInt(); byte[] bytes = new byte[length]; in.readFully(bytes); return new BinaryType(bytes); } } protected class BinaryColumnSerializer extends ColumnSerializer { @Override public void writeObject(ObjectOutput out, Object obj, Map<Object, Integer> cache, byte version) throws IOException { //uses object serialization for compatibility with legacy clients super.writeObject(out, ((BinaryType)obj).getBytesDirect(), cache, version); } @Override public Object readObject(ObjectInput in, List<Object> cache, byte version) throws IOException, ClassNotFoundException { //won't actually be used byte[] bytes = (byte[])super.readObject(in, cache, version); return new BinaryType(bytes); } } protected class ObjectColumnSerializer1_B1 extends ObjectColumnSerializer1 { private int highestKnownCode; public ObjectColumnSerializer1_B1() { this.highestKnownCode = -1; } public ObjectColumnSerializer1_B1(int highestKnownCode) { this.highestKnownCode = highestKnownCode; } @Override public void writeObject(ObjectOutput out, Object obj, Map<Object, Integer> cache, byte version) throws IOException { DefaultDataTypes dataType = getDataTypeManager().getDataType(obj.getClass()); int code = dataType.ordinal(); out.writeByte((byte)code); writeObject(out, obj, code, cache, version); } public void writeObject(ObjectOutput out, Object obj, int code, Map<Object, Integer> cache, byte version) throws IOException { if (code == DefaultDataTypes.BOOLEAN.ordinal()) { if (Boolean.TRUE.equals(obj)) { out.write((byte)1); } else { out.write((byte)0); } } else if (code <= this.highestKnownCode && code != DefaultDataTypes.OBJECT.ordinal()) { DefaultDataTypes dataType = DefaultDataTypes.valueOf(getTeiidVersion(), code); ColumnSerializer s = getSerializer(dataType.getId(), version); s.writeObject(out, obj, cache, version); } else { super.writeObject(out, obj, cache, version); } } @Override public boolean usesCache(byte version) { return version >= 3; } } private class XmlColumnSerializer1_B1 extends XmlColumnSerializer1 { @Override public void writeObject(ObjectOutput out, Object obj, Map<Object, Integer> cache, byte version) throws IOException { ((XMLType)obj).writeExternal(out, (byte) 1); } @Override public Object readObject(ObjectInput in, List<Object> cache, byte version) throws IOException, ClassNotFoundException { XMLType xt = new XMLType(); xt.readExternal(in, (byte) 1); return xt; } } @Override public List<List<Object>> readBatch(ObjectInput in, String[] types) throws IOException, ClassNotFoundException { int rows = 0; try { rows = in.readInt(); } catch (IOException e) { //7.4 compatibility if (types == null || types.length == 0) { List<Object>[] result = (List[])in.readObject(); ArrayList<List<Object>> batch = new ArrayList<List<Object>>(); batch.addAll(Arrays.asList(result)); return batch; } throw e; } if (rows == 0) { return new ArrayList<List<Object>>(0); } if (rows == -1) { return null; } byte version = (byte)0; if (rows < 0) { rows = -(rows+1); version = in.readByte(); } int columns = in.readInt(); List<List<Object>> batch = new ResizingArrayList<List<Object>>(rows); int numBytes = rows/8; int extraRows = rows % 8; for (int currentRow = 0; currentRow < rows; currentRow++) { batch.add(currentRow, Arrays.asList(new Object[columns])); } byte[] isNullBuffer = new byte[(extraRows > 0) ? numBytes + 1: numBytes]; List<Object> cache = null; for (int col = 0; col < columns; col++) { ColumnSerializer serializer = getSerializer(types[col], version); if (cache == null && serializer.usesCache(version)) { cache = new ArrayList<Object>(); } serializer.readColumn(in, col, batch, isNullBuffer, cache, version); } return batch; } }