package com.linkedin.r2.message.stream.entitystream; import com.linkedin.data.ByteString; import java.util.Arrays; import java.util.Iterator; /** * @author Ang Xu */ public class CompositeWriter implements Writer { private Iterator<EntityStream> _entityStreams; private WriteHandle _wh; private int _outstanding; private boolean _aborted = false; private ReadHandle _currentRh; private ReaderImpl _reader = new ReaderImpl(); public CompositeWriter(Writer... writers) { this(toEntityStreams(writers)); } public CompositeWriter(EntityStream... entityStreams) { this(Arrays.asList(entityStreams)); } public CompositeWriter(Iterable<EntityStream> entityStreams) { _entityStreams = entityStreams.iterator(); _outstanding = 0; } @Override public void onInit(WriteHandle wh) { _wh = wh; readNextStream(); } @Override public void onWritePossible() { _outstanding = _wh.remaining(); _currentRh.request(_outstanding); } @Override public void onAbort(Throwable e) { _aborted = true; _currentRh.cancel(); cancelAll(); } private void readNextStream() { if (_entityStreams.hasNext()) { EntityStream stream = _entityStreams.next(); stream.setReader(_reader); } else { _wh.done(); } } private void cancelAll() { while (_entityStreams.hasNext()) { EntityStream stream = _entityStreams.next(); stream.setReader(new CancelingReader()); } } private class ReaderImpl implements Reader { @Override public void onInit(ReadHandle rh) { _currentRh = rh; if (_outstanding > 0) { _currentRh.request(_outstanding); } } @Override public void onDataAvailable(ByteString data) { if (!_aborted) { _wh.write(data); _outstanding--; int diff = _wh.remaining() - _outstanding; if (diff > 0) { _currentRh.request(diff); _outstanding += diff; } } } @Override public void onDone() { if (!_aborted) { readNextStream(); } } @Override public void onError(Throwable e) { _wh.error(e); cancelAll(); } } private static EntityStream[] toEntityStreams(Writer... writers) { EntityStream[] entityStreams = new EntityStream[writers.length]; for (int i = 0; i < writers.length; ++i) { entityStreams[i] = EntityStreams.newEntityStream(writers[i]); } return entityStreams; } }