package com.linkedin.r2.message.stream.entitystream;
import com.linkedin.data.ByteString;
/**
* This is a convenient class to connect two entity streams and apply certain extra logic when passing along
* read requests or data. E.g. wrap and handling errors, data transformation, etc.
*
* @author Zhenkai Zhu
*/
public class BaseConnector implements Reader, Writer
{
private volatile WriteHandle _wh;
private volatile ReadHandle _rh;
private int _outstanding;
private volatile boolean _aborted;
private volatile Throwable _error;
public BaseConnector()
{
_outstanding = 0;
_aborted = false;
}
@Override
public void onInit(ReadHandle rh)
{
_rh = wrapReadHandle(rh);
}
@Override
public void onInit(final WriteHandle wh)
{
_wh = wrapWriteHandle(wh);
}
@Override
public void onDataAvailable(ByteString data)
{
if (!_aborted)
{
_outstanding--;
_wh.write(data);
int diff = _wh.remaining() - _outstanding;
if (diff > 0)
{
_rh.request(diff);
_outstanding += diff;
}
}
}
@Override
public void onDone()
{
_wh.done();
}
@Override
public void onError(Throwable e)
{
if (_wh != null)
{
_wh.error(e);
}
else
{
_error = e;
}
}
@Override
public void onWritePossible()
{
if (_error == null)
{
_outstanding = _wh.remaining();
_rh.request(_outstanding);
}
else
{
_wh.error(_error);
}
}
@Override
public void onAbort(Throwable e)
{
_aborted = true;
_rh.cancel();
}
public void cancel()
{
if (_rh != null)
{
_rh.cancel();
}
}
protected WriteHandle wrapWriteHandle(WriteHandle wh)
{
return wh;
}
protected ReadHandle wrapReadHandle(ReadHandle rh)
{
return rh;
}
protected final WriteHandle getWriteHandle()
{
return _wh;
}
protected final ReadHandle getReadHandle()
{
return _rh;
}
}