/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.clients.fcp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import freenet.client.async.PersistenceDisabledException;
import freenet.support.Logger;
import freenet.support.api.Bucket;
import freenet.support.api.BucketFactory;
import freenet.support.api.RandomAccessBucket;
import freenet.support.io.BucketTools;
import freenet.support.io.FileUtil;
import freenet.support.io.NullBucket;
import freenet.support.io.NullOutputStream;
public abstract class DataCarryingMessage extends BaseDataCarryingMessage {
/** If this is a message from the client, then the Bucket was created by createBucket() and
* will be a RandomAccessBucket. However if it is a message we are sending to the client, it
* may not be. FIXME split up into two classes? */
protected Bucket bucket;
RandomAccessBucket createBucket(BucketFactory bf, long length, FCPServer server) throws IOException, PersistenceDisabledException {
return bf.makeBucket(length);
}
abstract String getIdentifier();
abstract boolean isGlobal();
protected boolean freeOnSent;
void setFreeOnSent() {
freeOnSent = true;
}
@Override
public void readFrom(InputStream is, BucketFactory bf, FCPServer server) throws IOException, MessageInvalidException {
long len = dataLength();
if(len < 0) return;
if(len == 0) {
bucket = new NullBucket();
return;
}
RandomAccessBucket tempBucket;
try {
tempBucket = createBucket(bf, len, server);
} catch (IOException e) {
Logger.error(this, "Bucket error: "+e, e);
FileUtil.copy(is, new NullOutputStream(), len);
throw new MessageInvalidException(ProtocolErrorMessage.INTERNAL_ERROR, e.toString(), getIdentifier(), isGlobal());
} catch (PersistenceDisabledException e) {
Logger.error(this, "Bucket error: "+e, e);
FileUtil.copy(is, new NullOutputStream(), len);
throw new MessageInvalidException(ProtocolErrorMessage.PERSISTENCE_DISABLED, null, getIdentifier(), isGlobal());
}
BucketTools.copyFrom(tempBucket, is, len);
this.bucket = tempBucket;
}
@Override
protected void writeData(OutputStream os) throws IOException {
long len = dataLength();
if(len > 0) BucketTools.copyTo(bucket, os, len);
if(freeOnSent) bucket.free(); // Always transient so no removeFrom() needed.
}
@Override
String getEndString() {
return "Data";
}
/** Should only be called from code parsing a message sent to us, in which case Bucket will be a
* RandomAccessBucket, which it needs to be as it's likely to be inserted. If we are sending a
* message to the client, it might not be. FIXME split up into two classes? */
public RandomAccessBucket getRandomAccessBucket() {
return (RandomAccessBucket) bucket;
}
}