/* ************************************************************************
#
# DivConq
#
# http://divconq.com/
#
# Copyright:
# Copyright 2014 eTimeline, LLC. All rights reserved.
#
# License:
# See the license.txt file in the project's top-level directory for details.
#
# Authors:
# * Andy White
#
************************************************************************ */
package divconq.ctp.stream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import io.netty.buffer.ByteBuf;
import divconq.ctp.CtpAdapter;
import divconq.ctp.f.BlockCommand;
import divconq.ctp.f.CtpFCommand;
import divconq.ctp.f.FileDescriptor;
import divconq.script.StackEntry;
import divconq.xml.XElement;
public class CtpStreamSource extends BaseStream implements IStreamSource {
protected CtpAdapter adapter = null;
protected boolean initialized = false;
protected List<FileEntry> entries = new ArrayList<>();
protected ReentrantLock entryLock = new ReentrantLock();
protected FileDescriptor currFile = null;
public CtpStreamSource(CtpAdapter adapter) {
this.adapter = adapter;
}
@Override
public void init(StackEntry stack, XElement el) {
}
public void setFinal() {
this.entryLock.lock();
try {
this.currFile = null;
this.entries.add(new FileEntry(FileDescriptor.FINAL, null));
}
finally {
this.entryLock.unlock();
}
}
public void addNext(BlockCommand cmd) {
this.entryLock.lock();
try {
if (this.currFile == null)
this.currFile = new FileDescriptor();
this.currFile.copyAttributes(cmd);
this.entries.add(new FileEntry(this.currFile, cmd.getData()));
if (this.currFile.isEof())
this.currFile = null;
}
finally {
this.entryLock.unlock();
}
}
@Override
public ReturnOption handle(FileDescriptor file, ByteBuf data) {
return null;
}
@Override
public void read() {
// if not initialized get the stream flowing by sending a READ
if (!this.initialized) {
this.initialized = true;
try {
this.adapter.sendCommand(CtpFCommand.STREAM_READ);
}
catch (Exception x) {
System.out.println("Error sending READ: " + x);
}
}
else {
// since only we remove, it is ok to check > 0 from here
// adding thread cannot add and call this at the same time
// when they do call us, they'll catch any missed entries.
while (this.entries.size() > 0) {
FileEntry f = null;
this.entryLock.lock();
try {
if (this.entries.size() > 0)
f = this.entries.remove(0);
}
finally {
this.entryLock.unlock();
}
if ((f != null) && (this.downstream.handle(f.file, f.data) != ReturnOption.CONTINUE))
return;
}
// if no entries (left or to start with) then ask for more
this.adapter.read();
}
}
protected class FileEntry {
protected FileDescriptor file = null;
protected ByteBuf data = null;
public FileEntry(FileDescriptor file, ByteBuf data) {
this.file = file;
this.data = data;
}
}
}