package com.limegroup.gnutella.dime;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.limewire.nio.statemachine.ReadState;
/**
* Parser for creating DIMERecords from non-blocking input.
*
* See: http://www.gotdotnet.com/team/xml_wsspecs/dime/dime.htm
* (or http://www.perfectxml.com/DIME.asp )
* for information about DIME.
*/
public class AsyncDimeParser extends ReadState {
private static final Log LOG = LogFactory.getLog(AsyncDimeParser.class);
/** Whether or not we've read the last record. */
private boolean lastRead = false;
/** A list of DIMERecords this has read. */
private List<DIMERecord> records = new LinkedList<DIMERecord>();
private long amountRead = 0;
/** The AsyncDimeRecordReader we're using to read the current record. */
private AsyncDimeRecordReader reader;
@Override
protected boolean processRead(ReadableByteChannel channel, ByteBuffer buffer) throws IOException {
while(true) {
if(lastRead)
throw new IOException("already read last message.");
if(reader == null)
reader = new AsyncDimeRecordReader();
// Reader still needs more info.
try {
if(reader.process(channel, buffer))
return true;
} catch(DIMEException de) {
LOG.warn("Error processing DIME", de);
amountRead += reader.getAmountProcessed();
return false;
}
amountRead += reader.getAmountProcessed();
// Reader's read a full record.
DIMERecord next;
try {
next = reader.getRecord();
} catch(DIMEException de) {
LOG.warn("Error constructing DIME record", de);
return false;
}
if(next.isLastRecord())
lastRead = true;
if(records.isEmpty() && !next.isFirstRecord())
throw new IOException("middle of stream.");
else if(!records.isEmpty() && next.isFirstRecord())
throw new IOException("two first records.");
records.add(next);
reader = null;
if(lastRead)
return false;
}
}
public List<DIMERecord> getRecords() {
return records;
}
public long getAmountProcessed() {
return amountRead;
}
}