io.datakernel.stream.processor.StreamGsonDeserializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of async-streams Show documentation
Show all versions of async-streams Show documentation
Composable asynchronous/reactive streams with powerful data processing capabilities.
The newest version!
/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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 io.datakernel.stream.processor;
import com.google.gson.Gson;
import io.datakernel.bytebuf.ByteBuf;
import io.datakernel.bytebuf.ByteBufPool;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.stream.AbstractStreamTransformer_1_1;
import io.datakernel.stream.StreamDataReceiver;
import java.util.ArrayDeque;
public final class StreamGsonDeserializer extends AbstractStreamTransformer_1_1 implements StreamDeserializer, StreamDataReceiver, StreamGsonDeserializerMBean {
private static final int INITIAL_BUFFER_SIZE = 1;
private final BufferReader bufferReader = new BufferReader();
private final ArrayDeque byteBufs;
private final int buffersPoolSize;
private final Gson gson;
private final Class type;
private ByteBuf buf;
private int jmxItems;
private int jmxBufs;
private long jmxBytes;
public StreamGsonDeserializer(Eventloop eventloop, Gson gson, Class type, int buffersPoolSize) {
super(eventloop);
this.buffersPoolSize = buffersPoolSize;
this.byteBufs = new ArrayDeque<>(buffersPoolSize);
this.gson = gson;
this.type = type;
this.buf = ByteBufPool.allocate(INITIAL_BUFFER_SIZE);
}
private static int findZero(byte[] b, int off, int len) {
for (int i = off; i < off + len; i++) {
if (b[i] == 0) {
return i;
}
}
return -1;
}
@Override
public void drainBuffersTo(StreamDataReceiver dataReceiver) {
for (ByteBuf byteBuf : byteBufs) {
dataReceiver.onData(byteBuf);
}
byteBufs.clear();
sendEndOfStream();
}
@Override
protected void doProduce() {
while (status == READY && !byteBufs.isEmpty()) {
ByteBuf srcBuf = byteBufs.peek();
while (status == READY && srcBuf.hasRemaining()) {
// read message body:
int zeroPos = findZero(srcBuf.array(), srcBuf.position(), srcBuf.remaining());
if (zeroPos == -1) {
buf = ByteBufPool.append(buf, srcBuf);
break;
}
int readLen = zeroPos - srcBuf.position();
if (buf.position() != 0) {
buf = ByteBufPool.append(buf, srcBuf, readLen);
bufferReader.set(buf.array(), 0, buf.position());
buf.position(0);
} else {
bufferReader.set(srcBuf.array(), srcBuf.position(), readLen);
srcBuf.advance(readLen);
}
srcBuf.advance(1);
T item = gson.fromJson(bufferReader, type);
//noinspection AssertWithSideEffects
assert jmxItems != ++jmxItems;
downstreamDataReceiver.onData(item);
}
if (status >= END_OF_STREAM)
return;
if (!srcBuf.hasRemaining()) {
byteBufs.poll();
srcBuf.recycle();
}
}
if (byteBufs.isEmpty()) {
if (getUpstreamStatus() == END_OF_STREAM) {
sendEndOfStream();
buf.recycle();
buf = null;
} else {
resumeUpstream();
}
}
}
@Override
public void onData(ByteBuf buf) {
jmxBufs++;
jmxBytes += buf.remaining();
byteBufs.offer(buf);
produce();
if (byteBufs.size() == buffersPoolSize) {
suspendUpstream();
}
}
@Override
public void onEndOfStream() {
produce();
}
@Override
protected void onResumed() {
resumeProduce();
}
@Override
public StreamDataReceiver getDataReceiver() {
return this;
}
@Override
public void onClosed() {
super.onClosed();
recycleBufs();
}
@Override
protected void onClosedWithError(Exception e) {
super.onClosedWithError(e);
recycleBufs();
}
private void recycleBufs() {
if (buf != null) {
buf.recycle();
buf = null;
}
for (ByteBuf byteBuf : byteBufs) {
byteBuf.recycle();
}
byteBufs.clear();
}
@Override
public int getItems() {
return jmxItems;
}
@Override
public int getBufs() {
return jmxBufs;
}
@Override
public long getBytes() {
return jmxBytes;
}
@SuppressWarnings({"AssertWithSideEffects", "ConstantConditions"})
@Override
public String toString() {
boolean assertOn = false;
assert assertOn = true;
return '{' + super.toString()
+ " items:" + (assertOn ? "" + jmxItems : "?")
+ " bufs:" + jmxBufs
+ " bytes:" + jmxBytes + '}';
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy