/*
* Copyright © 2015 Cask Data, Inc.
*
* 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 co.cask.cdap.data.stream.service.upload;
import co.cask.cdap.api.stream.StreamEventData;
import co.cask.cdap.common.NotFoundException;
import co.cask.cdap.common.io.ByteBuffers;
import co.cask.cdap.data.stream.service.ConcurrentStreamWriter;
import co.cask.cdap.data.stream.service.MutableStreamEventData;
import co.cask.cdap.proto.Id;
import com.google.common.base.Throwables;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A {@link ContentWriter} that buffer all events in memory and write to the actual stream writer when closed.
*/
final class BufferedContentWriter implements ContentWriter, Iterable<ByteBuffer> {
private final Id.Stream streamId;
private final ConcurrentStreamWriter streamWriter;
private final Map<String, String> headers;
private final List<ByteBuffer> bodies;
BufferedContentWriter(Id.Stream streamId, ConcurrentStreamWriter streamWriter, Map<String, String> headers) {
this.streamId = streamId;
this.streamWriter = streamWriter;
this.headers = ImmutableMap.copyOf(headers);
this.bodies = Lists.newLinkedList();
}
@Override
public void append(ByteBuffer body, boolean immutable) throws IOException {
if (immutable) {
bodies.add(body);
} else {
bodies.add(ByteBuffers.copy(body));
}
}
@Override
public void appendAll(Iterator<ByteBuffer> bodies, boolean immutable) throws IOException {
while (bodies.hasNext()) {
append(bodies.next(), immutable);
}
}
@Override
public void close() throws IOException {
try {
streamWriter.enqueue(streamId, new StreamEventDataIterator(headers, bodies.iterator()));
} catch (NotFoundException e) {
throw Throwables.propagate(e);
}
}
@Override
public void cancel() {
// No-op
}
@Override
public Iterator<ByteBuffer> iterator() {
return bodies.iterator();
}
private static final class StreamEventDataIterator extends AbstractIterator<StreamEventData> {
private final Iterator<? extends ByteBuffer> bodies;
private final MutableStreamEventData streamEventData;
private StreamEventDataIterator(Map<String, String> headers, Iterator<? extends ByteBuffer> bodies) {
this.bodies = bodies;
this.streamEventData = new MutableStreamEventData().setHeaders(headers);
}
@Override
protected StreamEventData computeNext() {
if (!bodies.hasNext()) {
return endOfData();
}
return streamEventData.setBody(bodies.next());
}
}
}