blob: c46be5d2025d9dd02de6f691e1fa640b7267a754 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.ignite.internal.binary.builder;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.ignite.binary.BinaryObjectException;
import org.apache.ignite.internal.binary.BinaryContext;
import org.apache.ignite.internal.binary.BinaryObjectImpl;
import org.apache.ignite.internal.binary.BinaryPositionReadable;
import org.apache.ignite.internal.binary.BinaryPrimitives;
import org.apache.ignite.internal.binary.BinaryReaderExImpl;
import org.apache.ignite.internal.binary.BinarySchema;
import org.apache.ignite.internal.binary.BinaryUtils;
import org.apache.ignite.internal.binary.BinaryWriterExImpl;
import org.apache.ignite.internal.binary.GridBinaryMarshaller;
import org.apache.ignite.internal.binary.streams.BinaryHeapInputStream;
import org.apache.ignite.internal.util.typedef.internal.U;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
*
*/
public class BinaryBuilderReader implements BinaryPositionReadable {
/** */
private final BinaryContext ctx;
/** */
private final byte[] arr;
/** */
private final BinaryReaderExImpl reader;
/** */
private final Map<Integer, BinaryObjectBuilderImpl> objMap;
/** */
private int pos;
/**
* Constructor.
*
* @param objImpl Binary object
*/
BinaryBuilderReader(BinaryObjectImpl objImpl) {
ctx = objImpl.context();
arr = objImpl.array();
pos = objImpl.start();
reader = new BinaryReaderExImpl(ctx,
BinaryHeapInputStream.create(arr, pos),
ctx.configuration().getClassLoader(),
false);
objMap = new HashMap<>();
}
/**
* Copying constructor.
*
* @param other Other reader.
* @param start Start position.
*/
BinaryBuilderReader(BinaryBuilderReader other, int start) {
this.ctx = other.ctx;
this.arr = other.arr;
this.pos = start;
reader = new BinaryReaderExImpl(ctx,
BinaryHeapInputStream.create(arr, start),
null,
other.reader.handles(),
false);
this.objMap = other.objMap;
}
/**
* @return Binary context.
*/
public BinaryContext binaryContext() {
return ctx;
}
/**
* @param obj Mutable binary object.
*/
public void registerObject(BinaryObjectBuilderImpl obj) {
objMap.put(obj.start(), obj);
}
/**
* Get schema of the object, starting at the given position.
*
* @return Object's schema.
*/
public BinarySchema schema() {
return reader.getOrCreateSchema();
}
/**
* @return Read int value.
*/
public int readInt() {
int res = readInt(0);
pos += 4;
return res;
}
/**
* @return Read int value.
*/
public byte readByte() {
return arr[pos++];
}
/**
* @return Read boolean value.
*/
public boolean readBoolean() {
return readByte() == 1;
}
/**
* @return Read int value.
*/
public byte readByte(int off) {
return arr[pos + off];
}
/**
* @param off Offset related to {@link #pos}
* @return Read int value.
*/
public int readInt(int off) {
return BinaryPrimitives.readInt(arr, pos + off);
}
/**
* @param pos Position in the source array.
* @return Read byte value.
*/
@Override public byte readBytePositioned(int pos) {
return BinaryPrimitives.readByte(arr, pos);
}
/** {@inheritDoc} */
@Override public short readShortPositioned(int pos) {
return BinaryPrimitives.readShort(arr, pos);
}
/** {@inheritDoc} */
@Override public int readIntPositioned(int pos) {
return BinaryPrimitives.readInt(arr, pos);
}
/**
* @return Read length of array.
*/
public int readLength() {
return BinaryPrimitives.readInt(arr, pos);
}
/**
* Read string length.
*
* @return String length.
*/
public int readStringLength() {
return BinaryPrimitives.readInt(arr, pos);
}
/**
* Reads string.
*
* @return String.
*/
public String readString() {
byte flag = readByte();
if (flag == GridBinaryMarshaller.NULL)
return null;
if (flag != GridBinaryMarshaller.STRING)
throw new BinaryObjectException("Failed to deserialize String.");
int len = readInt();
String str = new String(arr, pos, len, UTF_8);
pos += len;
return str;
}
/**
*
*/
public void skipValue() {
byte type = arr[pos++];
int len;
switch (type) {
case GridBinaryMarshaller.NULL:
return;
case GridBinaryMarshaller.OBJ:
pos += readInt(GridBinaryMarshaller.TOTAL_LEN_POS - 1) - 1;
return;
case GridBinaryMarshaller.BOOLEAN:
case GridBinaryMarshaller.BYTE:
len = 1;
break;
case GridBinaryMarshaller.CHAR:
case GridBinaryMarshaller.SHORT:
len = 2;
break;
case GridBinaryMarshaller.HANDLE:
case GridBinaryMarshaller.FLOAT:
case GridBinaryMarshaller.INT:
len = 4;
break;
case GridBinaryMarshaller.ENUM:
//skipping type id and ordinal value
len = 8;
break;
case GridBinaryMarshaller.LONG:
case GridBinaryMarshaller.DOUBLE:
len = 8;
break;
case GridBinaryMarshaller.BYTE_ARR:
case GridBinaryMarshaller.BOOLEAN_ARR:
len = 4 + readLength();
break;
case GridBinaryMarshaller.STRING:
len = 4 + readStringLength();
break;
case GridBinaryMarshaller.DECIMAL:
len = /** scale */ 4 + /** mag len */ 4 + /** mag bytes count */ readInt(4);
break;
case GridBinaryMarshaller.UUID:
len = 8 + 8;
break;
case GridBinaryMarshaller.DATE:
len = 8;
break;
case GridBinaryMarshaller.TIMESTAMP:
len = 8 + 4;
break;
case GridBinaryMarshaller.TIME:
len = 8;
break;
case GridBinaryMarshaller.CHAR_ARR:
case GridBinaryMarshaller.SHORT_ARR:
len = 4 + readLength() * 2;
break;
case GridBinaryMarshaller.INT_ARR:
case GridBinaryMarshaller.FLOAT_ARR:
len = 4 + readLength() * 4;
break;
case GridBinaryMarshaller.LONG_ARR:
case GridBinaryMarshaller.DOUBLE_ARR:
len = 4 + readLength() * 8;
break;
case GridBinaryMarshaller.DECIMAL_ARR:
case GridBinaryMarshaller.DATE_ARR:
case GridBinaryMarshaller.TIMESTAMP_ARR:
case GridBinaryMarshaller.TIME_ARR:
case GridBinaryMarshaller.OBJ_ARR:
case GridBinaryMarshaller.ENUM_ARR:
case GridBinaryMarshaller.UUID_ARR:
case GridBinaryMarshaller.STRING_ARR: {
int size = readInt();
for (int i = 0; i < size; i++)
skipValue();
return;
}
case GridBinaryMarshaller.COL: {
int size = readInt();
pos++; // skip collection type
for (int i = 0; i < size; i++)
skipValue();
return;
}
case GridBinaryMarshaller.MAP: {
int size = readInt();
pos++; // skip collection type
for (int i = 0; i < size; i++) {
skipValue(); // skip key.
skipValue(); // skip value.
}
return;
}
case GridBinaryMarshaller.BINARY_OBJ:
len = readInt() + 4;
break;
default:
throw new BinaryObjectException("Invalid flag value: " + type);
}
pos += len;
}
/**
* @param pos Position.
* @param len Length.
* @return Object.
*/
public Object getValueQuickly(int pos, int len) {
byte type = arr[pos];
switch (type) {
case GridBinaryMarshaller.NULL:
return null;
case GridBinaryMarshaller.HANDLE: {
int objStart = pos - readIntPositioned(pos + 1);
BinaryObjectBuilderImpl res = objMap.get(objStart);
if (res == null) {
res = new BinaryObjectBuilderImpl(new BinaryBuilderReader(this, objStart), objStart);
objMap.put(objStart, res);
}
return res;
}
case GridBinaryMarshaller.OBJ: {
BinaryObjectBuilderImpl res = objMap.get(pos);
if (res == null) {
res = new BinaryObjectBuilderImpl(new BinaryBuilderReader(this, pos), pos);
objMap.put(pos, res);
}
return res;
}
case GridBinaryMarshaller.BYTE:
return arr[pos + 1];
case GridBinaryMarshaller.SHORT:
return BinaryPrimitives.readShort(arr, pos + 1);
case GridBinaryMarshaller.INT:
return BinaryPrimitives.readInt(arr, pos + 1);
case GridBinaryMarshaller.LONG:
return BinaryPrimitives.readLong(arr, pos + 1);
case GridBinaryMarshaller.FLOAT:
return BinaryPrimitives.readFloat(arr, pos + 1);
case GridBinaryMarshaller.DOUBLE:
return BinaryPrimitives.readDouble(arr, pos + 1);
case GridBinaryMarshaller.CHAR:
return BinaryPrimitives.readChar(arr, pos + 1);
case GridBinaryMarshaller.BOOLEAN:
return arr[pos + 1] != 0;
case GridBinaryMarshaller.DECIMAL:
case GridBinaryMarshaller.STRING:
case GridBinaryMarshaller.UUID:
case GridBinaryMarshaller.DATE:
case GridBinaryMarshaller.TIMESTAMP:
case GridBinaryMarshaller.TIME:
return new BinaryPlainLazyValue(this, pos, len);
case GridBinaryMarshaller.BYTE_ARR:
case GridBinaryMarshaller.SHORT_ARR:
case GridBinaryMarshaller.INT_ARR:
case GridBinaryMarshaller.LONG_ARR:
case GridBinaryMarshaller.FLOAT_ARR:
case GridBinaryMarshaller.DOUBLE_ARR:
case GridBinaryMarshaller.CHAR_ARR:
case GridBinaryMarshaller.BOOLEAN_ARR:
case GridBinaryMarshaller.DECIMAL_ARR:
case GridBinaryMarshaller.DATE_ARR:
case GridBinaryMarshaller.TIMESTAMP_ARR:
case GridBinaryMarshaller.TIME_ARR:
case GridBinaryMarshaller.UUID_ARR:
case GridBinaryMarshaller.STRING_ARR:
case GridBinaryMarshaller.ENUM_ARR:
case GridBinaryMarshaller.OBJ_ARR:
case GridBinaryMarshaller.COL:
case GridBinaryMarshaller.MAP:
return new LazyCollection(pos);
case GridBinaryMarshaller.ENUM: {
if (len == 1) {
assert readByte(pos) == GridBinaryMarshaller.NULL;
return null;
}
int mark = position();
position(pos + 1);
BinaryBuilderEnum builderEnum = new BinaryBuilderEnum(this);
position(mark);
return builderEnum;
}
case GridBinaryMarshaller.BINARY_OBJ: {
int size = readIntPositioned(pos + 1);
int start = readIntPositioned(pos + 4 + size);
BinaryObjectImpl binaryObj = new BinaryObjectImpl(ctx, arr, pos + 4 + start);
return new BinaryPlainBinaryObject(binaryObj);
}
case GridBinaryMarshaller.OPTM_MARSH: {
final BinaryHeapInputStream bin = BinaryHeapInputStream.create(arr, pos + 1);
final Object obj = BinaryUtils.doReadOptimized(bin, ctx, U.resolveClassLoader(ctx.configuration()));
return obj;
}
default:
throw new BinaryObjectException("Invalid flag value: " + type);
}
}
/**
* @return Parsed value.
*/
public Object parseValue() {
int valPos = pos;
byte type = arr[pos++];
int plainLazyValLen;
boolean modifiableLazyVal = false;
switch (type) {
case GridBinaryMarshaller.NULL:
return null;
case GridBinaryMarshaller.HANDLE: {
int objStart = pos - 1 - readInt();
BinaryObjectBuilderImpl res = objMap.get(objStart);
if (res == null) {
res = new BinaryObjectBuilderImpl(new BinaryBuilderReader(this, objStart), objStart);
objMap.put(objStart, res);
}
return res;
}
case GridBinaryMarshaller.OBJ: {
pos--;
BinaryObjectBuilderImpl res = objMap.get(pos);
if (res == null) {
res = new BinaryObjectBuilderImpl(new BinaryBuilderReader(this, pos), pos);
objMap.put(pos, res);
}
pos += readInt(GridBinaryMarshaller.TOTAL_LEN_POS);
return res;
}
case GridBinaryMarshaller.BYTE:
return arr[pos++];
case GridBinaryMarshaller.SHORT: {
Object res = BinaryPrimitives.readShort(arr, pos);
pos += 2;
return res;
}
case GridBinaryMarshaller.INT:
return readInt();
case GridBinaryMarshaller.LONG:
plainLazyValLen = 8;
break;
case GridBinaryMarshaller.FLOAT:
plainLazyValLen = 4;
break;
case GridBinaryMarshaller.DOUBLE:
plainLazyValLen = 8;
break;
case GridBinaryMarshaller.CHAR:
plainLazyValLen = 2;
break;
case GridBinaryMarshaller.BOOLEAN:
return arr[pos++] != 0;
case GridBinaryMarshaller.DECIMAL:
plainLazyValLen = /** scale */ 4 + /** mag len */ 4 + /** mag bytes count */ readInt(4);
break;
case GridBinaryMarshaller.STRING:
plainLazyValLen = 4 + readStringLength();
break;
case GridBinaryMarshaller.UUID:
plainLazyValLen = 8 + 8;
break;
case GridBinaryMarshaller.DATE:
plainLazyValLen = 8;
break;
case GridBinaryMarshaller.TIMESTAMP:
plainLazyValLen = 8 + 4;
break;
case GridBinaryMarshaller.TIME:
plainLazyValLen = 8;
break;
case GridBinaryMarshaller.BYTE_ARR:
plainLazyValLen = 4 + readLength();
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.SHORT_ARR:
plainLazyValLen = 4 + readLength() * 2;
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.INT_ARR:
plainLazyValLen = 4 + readLength() * 4;
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.LONG_ARR:
plainLazyValLen = 4 + readLength() * 8;
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.FLOAT_ARR:
plainLazyValLen = 4 + readLength() * 4;
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.DOUBLE_ARR:
plainLazyValLen = 4 + readLength() * 8;
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.CHAR_ARR:
plainLazyValLen = 4 + readLength() * 2;
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.BOOLEAN_ARR:
plainLazyValLen = 4 + readLength();
modifiableLazyVal = true;
break;
case GridBinaryMarshaller.OBJ_ARR:
return new BinaryObjectArrayLazyValue(this);
case GridBinaryMarshaller.DATE_ARR: {
int size = readInt();
Date[] res = new Date[size];
for (int i = 0; i < res.length; i++) {
byte flag = arr[pos++];
if (flag == GridBinaryMarshaller.NULL) continue;
if (flag != GridBinaryMarshaller.DATE)
throw new BinaryObjectException("Invalid flag value: " + flag);
long time = BinaryPrimitives.readLong(arr, pos);
pos += 8;
res[i] = new Date(time);
}
return res;
}
case GridBinaryMarshaller.TIMESTAMP_ARR: {
int size = readInt();
Timestamp[] res = new Timestamp[size];
for (int i = 0; i < res.length; i++) {
byte flag = arr[pos++];
if (flag == GridBinaryMarshaller.NULL)
continue;
if (flag != GridBinaryMarshaller.TIMESTAMP)
throw new BinaryObjectException("Invalid flag value: " + flag);
long time = BinaryPrimitives.readLong(arr, pos);
pos += 8;
int nano = BinaryPrimitives.readInt(arr, pos);
pos += 4;
Timestamp ts = new Timestamp(time);
ts.setNanos(ts.getNanos() + nano);
res[i] = ts;
}
return res;
}
case GridBinaryMarshaller.TIME_ARR: {
int size = readInt();
Time[] res = new Time[size];
for (int i = 0; i < res.length; i++) {
byte flag = arr[pos++];
if (flag == GridBinaryMarshaller.NULL) continue;
if (flag != GridBinaryMarshaller.TIME)
throw new BinaryObjectException("Invalid flag value: " + flag);
long time = BinaryPrimitives.readLong(arr, pos);
pos += 8;
res[i] = new Time(time);
}
return res;
}
case GridBinaryMarshaller.UUID_ARR:
case GridBinaryMarshaller.STRING_ARR:
case GridBinaryMarshaller.DECIMAL_ARR: {
int size = readInt();
for (int i = 0; i < size; i++) {
byte flag = arr[pos++];
if (flag == GridBinaryMarshaller.UUID)
pos += 8 + 8;
else if (flag == GridBinaryMarshaller.STRING)
pos += 4 + readStringLength();
else if (flag == GridBinaryMarshaller.DECIMAL) {
pos += 4; // scale value
pos += 4 + readLength();
}
else
assert flag == GridBinaryMarshaller.NULL;
}
return new BinaryModifiableLazyValue(this, valPos, pos - valPos);
}
case GridBinaryMarshaller.COL: {
int size = readInt();
byte colType = arr[pos++];
switch (colType) {
case GridBinaryMarshaller.USER_COL:
case GridBinaryMarshaller.ARR_LIST:
return new BinaryLazyArrayList(this, size);
case GridBinaryMarshaller.LINKED_LIST:
return new BinaryLazyLinkedList(this, size);
case GridBinaryMarshaller.HASH_SET:
case GridBinaryMarshaller.LINKED_HASH_SET:
return new BinaryLazySet(this, size);
}
throw new BinaryObjectException("Unknown collection type: " + colType);
}
case GridBinaryMarshaller.MAP:
return BinaryLazyMap.parseMap(this);
case GridBinaryMarshaller.ENUM:
return new BinaryBuilderEnum(this);
case GridBinaryMarshaller.ENUM_ARR:
return new BinaryEnumArrayLazyValue(this);
case GridBinaryMarshaller.BINARY_OBJ: {
int size = readInt();
pos += size;
int start = readInt();
BinaryObjectImpl binaryObj = new BinaryObjectImpl(ctx, arr,
pos - 4 - size + start);
return new BinaryPlainBinaryObject(binaryObj);
}
case GridBinaryMarshaller.OPTM_MARSH: {
final BinaryHeapInputStream bin = BinaryHeapInputStream.create(arr, pos);
final Object obj = BinaryUtils.doReadOptimized(bin, ctx, U.resolveClassLoader(ctx.configuration()));
pos = bin.position();
return obj;
}
default:
throw new BinaryObjectException("Invalid flag value: " + type);
}
BinaryAbstractLazyValue res;
if (modifiableLazyVal)
res = new BinaryModifiableLazyValue(this, valPos, 1 + plainLazyValLen);
else
res = new BinaryPlainLazyValue(this, valPos, 1 + plainLazyValLen);
pos += plainLazyValLen;
return res;
}
/**
* @return Array.
*/
public byte[] array() {
return arr;
}
/**
* @return Position of reader.
*/
public int position() {
return pos;
}
/**
* @param pos New pos.
*/
public void position(int pos) {
this.pos = pos;
}
/**
* @param n Number of bytes to skip.
*/
public void skip(int n) {
pos += n;
}
/**
* @return Reader.
*/
BinaryReaderExImpl reader() {
return reader;
}
/**
*
*/
private class LazyCollection implements BinaryLazyValue {
/** */
private final int valOff;
/** */
private Object col;
/**
* @param valOff Value.
*/
protected LazyCollection(int valOff) {
this.valOff = valOff;
}
/**
* @return Object.
*/
private Object wrappedCollection() {
if (col == null) {
position(valOff);
col = parseValue();
}
return col;
}
/** {@inheritDoc} */
@Override public void writeTo(BinaryWriterExImpl writer, BinaryBuilderSerializer ctx) {
ctx.writeValue(writer, wrappedCollection());
}
/** {@inheritDoc} */
@Override public Object value() {
return BinaryUtils.unwrapLazy(wrappedCollection());
}
}
}