/**
* 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.flink.python.api.streaming.plan;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.flink.api.java.tuple.Tuple;
import static org.apache.flink.python.api.streaming.data.PythonReceiver.createTuple;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_BOOLEAN;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_BYTE;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_BYTES;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_DOUBLE;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_FLOAT;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_INTEGER;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_LONG;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_NULL;
import static org.apache.flink.python.api.streaming.util.SerializationUtils.TYPE_STRING;
import org.apache.flink.configuration.ConfigConstants;
import org.apache.flink.python.api.types.CustomTypeWrapper;
/**
* Instances of this class can be used to receive data from the plan process.
*/
public class PythonPlanReceiver {
private final DataInputStream input;
public PythonPlanReceiver(InputStream input) {
this.input = new DataInputStream(input);
}
public Object getRecord() throws IOException {
return getRecord(false);
}
public Object getRecord(boolean normalized) throws IOException {
return getDeserializer().deserialize(normalized);
}
private Deserializer getDeserializer() throws IOException {
byte type = input.readByte();
if (type >= 0 && type < 26) {
Deserializer[] d = new Deserializer[type];
for (int x = 0; x < d.length; x++) {
d[x] = getDeserializer();
}
return new TupleDeserializer(d);
}
switch (type) {
case TYPE_BOOLEAN:
return new BooleanDeserializer();
case TYPE_BYTE:
return new ByteDeserializer();
case TYPE_INTEGER:
return new IntDeserializer();
case TYPE_LONG:
return new LongDeserializer();
case TYPE_FLOAT:
return new FloatDeserializer();
case TYPE_DOUBLE:
return new DoubleDeserializer();
case TYPE_STRING:
return new StringDeserializer();
case TYPE_BYTES:
return new BytesDeserializer();
case TYPE_NULL:
return new NullDeserializer();
default:
return new CustomTypeDeserializer(type);
}
}
private abstract static class Deserializer<T> {
public T deserialize() throws IOException {
return deserialize(false);
}
public abstract T deserialize(boolean normalized) throws IOException;
}
private static class TupleDeserializer extends Deserializer<Tuple> {
private final Deserializer[] deserializer;
public TupleDeserializer(Deserializer[] deserializer) {
this.deserializer = deserializer;
}
@Override
public Tuple deserialize(boolean normalized) throws IOException {
Tuple result = createTuple(deserializer.length);
for (int x = 0; x < result.getArity(); x++) {
result.setField(deserializer[x].deserialize(normalized), x);
}
return result;
}
}
private class CustomTypeDeserializer extends Deserializer<CustomTypeWrapper> {
private final byte type;
public CustomTypeDeserializer(byte type) {
this.type = type;
}
@Override
public CustomTypeWrapper deserialize(boolean normalized) throws IOException {
int size = input.readInt();
byte[] data = new byte[size];
input.readFully(data);
return new CustomTypeWrapper(type, data);
}
}
private class BooleanDeserializer extends Deserializer<Boolean> {
@Override
public Boolean deserialize(boolean normalized) throws IOException {
return input.readBoolean();
}
}
private class ByteDeserializer extends Deserializer<Byte> {
@Override
public Byte deserialize(boolean normalized) throws IOException {
return input.readByte();
}
}
private class IntDeserializer extends Deserializer<Integer> {
@Override
public Integer deserialize(boolean normalized) throws IOException {
return input.readInt();
}
}
private class LongDeserializer extends Deserializer<Object> {
@Override
public Object deserialize(boolean normalized) throws IOException {
if (normalized) {
return new Long(input.readLong()).intValue();
} else {
return input.readLong();
}
}
}
private class FloatDeserializer extends Deserializer<Object> {
@Override
public Object deserialize(boolean normalized) throws IOException {
if (normalized) {
return (double) input.readFloat();
} else {
return input.readFloat();
}
}
}
private class DoubleDeserializer extends Deserializer<Double> {
@Override
public Double deserialize(boolean normalized) throws IOException {
return input.readDouble();
}
}
private class StringDeserializer extends Deserializer<String> {
@Override
public String deserialize(boolean normalized) throws IOException {
int size = input.readInt();
byte[] buffer = new byte[size];
input.readFully(buffer);
return new String(buffer, ConfigConstants.DEFAULT_CHARSET);
}
}
private class NullDeserializer extends Deserializer<Object> {
@Override
public Object deserialize(boolean normalized) throws IOException {
return null;
}
}
private class BytesDeserializer extends Deserializer<byte[]> {
@Override
public byte[] deserialize(boolean normalized) throws IOException {
int size = input.readInt();
byte[] buffer = new byte[size];
input.readFully(buffer);
return buffer;
}
}
}