/*
* 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.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.sql.Array;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.teiid.core.types.ArrayImpl;
import org.teiid.core.types.BlobType;
import org.teiid.core.types.DataTypeManagerService;
import org.teiid.core.types.DataTypeManagerService.DefaultDataTypes;
import org.teiid.core.types.GeometryType;
import org.teiid.designer.runtime.version.spi.ITeiidServerVersion;
/**
* @since 4.2
*
* <ul>
* <li>version 0: starts with 7.1 and uses simple serialization too broadly
* <li>version 1: starts with 8.0 uses better string, blob, clob, xml, etc.
* add varbinary support.
* however was possibly silently truncating date/time values that were
* outside of jdbc allowed values
* <li>version 2: starts with 8.2 and adds better array serialization and
* uses a safer date/time serialization
* <li>version 3: starts with 8.6 and adds better repeated string performance
* <li>version 4: starts with 8.10 and adds the geometry type
* </ul>
*/
public class Batch4Serializer extends Batch3Serializer {
private static final byte VERSION_GEOMETRY = (byte)4;
/**
* @param teiidVersion
*/
protected Batch4Serializer(ITeiidServerVersion teiidVersion, byte version) {
super(teiidVersion, version);
serializers.put(DataTypeManagerService.DefaultDataTypes.GEOMETRY.getId(), new ColumnSerializer[] {defaultSerializer, new GeometryColumnSerializer()});
serializers.put(DataTypeManagerService.DefaultDataTypes.OBJECT.getId(), new ColumnSerializer[] {defaultSerializer, new ObjectColumnSerializer_B4((byte)1)});
}
/**
* @param teiidVersion
*/
public Batch4Serializer(ITeiidServerVersion teiidVersion) {
this(teiidVersion, VERSION_GEOMETRY);
}
@Override
protected ColumnSerializer getArrayColumnSerializer2() {
return new ArrayColumnSerializer2(new ObjectColumnSerializer_B4((byte)2));
}
protected class ArrayColumnSerializer2_B4 extends ArrayColumnSerializer2 {
public ArrayColumnSerializer2_B4(ObjectColumnSerializer_B4 ser) {
super(ser);
}
@Override
public void writeObject(ObjectOutput out, Object obj, Map<Object, Integer> cache, byte version) throws IOException {
Object[] values = null;
try {
values = (Object[])((Array)obj).getArray();
} catch (SQLException e) {
out.writeInt(-1);
return;
}
out.writeInt(values.length);
DefaultDataTypes dataType = getDataTypeManager().getDataType(values.getClass().getComponentType());
int code = dataType.ordinal();
if (code == DefaultDataTypes.GEOMETRY.ordinal() && version < VERSION_GEOMETRY) {
code = DefaultDataTypes.BLOB.ordinal();
}
out.writeByte((byte)code);
for (int i = 0; i < values.length;) {
writeIsNullData(out, i, values);
int end = Math.min(values.length, i + 8);
for (; i < end; i++) {
if (values[i] != null) {
this.ser.writeObject(out, values[i], code, cache, version);
}
}
}
out.writeBoolean((obj instanceof ArrayImpl && ((ArrayImpl)obj).isZeroBased()));
}
}
protected class ObjectColumnSerializer_B4 extends ObjectColumnSerializer1_B1 {
byte defaultVersion;
public ObjectColumnSerializer_B4(byte version) {
super();
this.defaultVersion = version;
}
@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();
if (code == DefaultDataTypes.GEOMETRY.ordinal() && version < VERSION_GEOMETRY) {
code = DefaultDataTypes.BLOB.ordinal();
}
out.writeByte((byte)code);
writeObject(out, obj, code, cache, version < VERSION_GEOMETRY ? this.defaultVersion : version);
}
@Override
public void writeObject(ObjectOutput out, Object obj, int code, Map<Object, Integer> cache, byte effectiveVersion)
throws IOException {
if (code == DefaultDataTypes.BOOLEAN.ordinal()) {
if (Boolean.TRUE.equals(obj)) {
out.write((byte)1);
} else {
out.write((byte)0);
}
} else if (code == DefaultDataTypes.OBJECT.ordinal()) {
super.writeObject(out, obj, cache, effectiveVersion);
} else {
String name = getDataTypeManager().getDataTypeName(obj.getClass());
ColumnSerializer s = getSerializer(name, effectiveVersion);
s.writeObject(out, obj, cache, effectiveVersion);
}
}
@Override
public Object readObject(ObjectInput in, List<Object> cache, byte version) throws IOException, ClassNotFoundException {
int code = in.readByte();
return readObject(in, code, cache, version < VERSION_GEOMETRY ? this.defaultVersion : version);
}
@Override
public boolean usesCache(byte version) {
return version >= 3;
}
}
protected class GeometryColumnSerializer extends ColumnSerializer {
@Override
public void writeObject(ObjectOutput out, Object obj, Map<Object, Integer> cache, byte version) throws IOException {
((Externalizable)obj).writeExternal(out);
}
@Override
public Object readObject(ObjectInput in, List<Object> cache, byte version) throws IOException, ClassNotFoundException {
if (version < 4) {
BlobType bt = new BlobType();
bt.readExternal(in);
return bt;
}
GeometryType bt = new GeometryType();
bt.readExternal(in);
return bt;
}
}
}