/** * diqube: Distributed Query Base. * * Copyright (C) 2015 Bastian Gloeckle * * This file is part of diqube. * * diqube is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.diqube.thrift.util; import java.util.ArrayList; import java.util.List; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import org.apache.thrift.transport.TTransportFactory; /** * {@link TTransport} facade that can remember bytes read/written. * * @author Bastian Gloeckle */ public class RememberingTransport extends TTransport { private TTransport delegate; private List<byte[]> rememberedReadBytes; private List<byte[]> rememberedWriteBytes; public RememberingTransport(TTransport delegate) { this.delegate = delegate; } public void startRemeberingReadBytes() { rememberedReadBytes = new ArrayList<>(); } public byte[] stopRememberingReadBytes() { int resLen = 0; for (byte[] b : rememberedReadBytes) resLen += b.length; byte[] res = new byte[resLen]; int outPos = 0; for (byte[] b : rememberedReadBytes) { System.arraycopy(b, 0, res, outPos, b.length); outPos += b.length; } rememberedReadBytes = null; return res; } public void startRemeberingWriteBytes() { rememberedWriteBytes = new ArrayList<>(); } public byte[] stopRememberingWriteBytes() { int resLen = 0; for (byte[] b : rememberedWriteBytes) resLen += b.length; byte[] res = new byte[resLen]; int outPos = 0; for (byte[] b : rememberedWriteBytes) { System.arraycopy(b, 0, res, outPos, b.length); outPos += b.length; } rememberedReadBytes = null; return res; } @Override public boolean isOpen() { return delegate.isOpen(); } @Override public boolean peek() { return delegate.peek(); } @Override public void open() throws TTransportException { delegate.open(); } @Override public void close() { delegate.close(); } @Override public int read(byte[] buf, int off, int len) throws TTransportException { int res = delegate.read(buf, off, len); if (rememberedReadBytes != null) { byte[] remember = new byte[len]; System.arraycopy(buf, off, remember, 0, res); rememberedReadBytes.add(remember); } return res; } @Override public int readAll(byte[] buf, int off, int len) throws TTransportException { int res = delegate.readAll(buf, off, len); if (rememberedReadBytes != null) { byte[] remember = new byte[len]; System.arraycopy(buf, off, remember, 0, res); rememberedReadBytes.add(remember); } return res; } @Override public int hashCode() { return delegate.hashCode(); } @Override public void write(byte[] buf) throws TTransportException { delegate.write(buf); if (rememberedWriteBytes != null) { byte[] remember = new byte[buf.length]; System.arraycopy(buf, 0, remember, 0, buf.length); rememberedWriteBytes.add(remember); } } @Override public void write(byte[] buf, int off, int len) throws TTransportException { delegate.write(buf, off, len); if (rememberedWriteBytes != null) { byte[] remember = new byte[len]; System.arraycopy(buf, off, remember, 0, len); rememberedWriteBytes.add(remember); } } @Override public void flush() throws TTransportException { delegate.flush(); } @Override public byte[] getBuffer() { // do not allow the underlying bufer to be read if there is one, as we cannot remember anything then. return null; } @Override public int getBufferPosition() { // do not allow the underlying bufer to be read if there is one, as we cannot remember anything then. return -1; } @Override public int getBytesRemainingInBuffer() { // do not allow the underlying bufer to be read if there is one, as we cannot remember anything then. return -1; } @Override public boolean equals(Object obj) { return delegate.equals(obj); } @Override public void consumeBuffer(int len) { // do not allow the underlying bufer to be read if there is one, as we cannot remember anything then. // noop. } @Override public String toString() { return "[RememberingTransport:" + delegate.toString() + "]"; } public static class Factory extends TTransportFactory { private TTransportFactory delegateFactory; public Factory(TTransportFactory delegateFactory) { this.delegateFactory = delegateFactory; } @Override public TTransport getTransport(TTransport trans) { return new RememberingTransport(delegateFactory.getTransport(trans)); } } }