Author: toad
Date: 2005-10-29 15:07:27 +0000 (Sat, 29 Oct 2005)
New Revision: 7466
Modified:
trunk/freenet/src/freenet/client/ArchiveManager.java
trunk/freenet/src/freenet/client/ArchiveStoreContext.java
trunk/freenet/src/freenet/client/ArchiveStoreItem.java
trunk/freenet/src/freenet/client/ClientMetadata.java
trunk/freenet/src/freenet/client/DefaultMIMETypes.java
trunk/freenet/src/freenet/client/ErrorArchiveStoreItem.java
trunk/freenet/src/freenet/client/FetchException.java
trunk/freenet/src/freenet/client/FetchResult.java
trunk/freenet/src/freenet/client/Fetcher.java
trunk/freenet/src/freenet/client/FetcherContext.java
trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
trunk/freenet/src/freenet/client/Metadata.java
trunk/freenet/src/freenet/client/RealArchiveStoreItem.java
trunk/freenet/src/freenet/support/io/FileBucket.java
trunk/freenet/src/freenet/support/io/FileBucketFactory.java
Log:
Lots of javadocs, swat some minor logic errors.
Modified: trunk/freenet/src/freenet/client/ArchiveManager.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveManager.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/ArchiveManager.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -28,7 +28,7 @@
/**
* Cache of recently decoded archives:
* - Keep up to N ArchiveHandler's in RAM (this can be large; we don't keep the
- * files open due to the limitations of the API)
+ * files open due to the limitations of the java.util.zip API)
* - Keep up to Y bytes (after padding and overheads) of decoded data on disk
* (the OS is quite capable of determining what to keep in actual RAM)
*
@@ -36,6 +36,19 @@
*/
public class ArchiveManager {
+ /**
+ * Create an ArchiveManager.
+ * @param maxHandlers The maximum number of cached ArchiveHandler's.
+ * @param maxCachedData The maximum size of the cache directory, in
bytes.
+ * @param maxArchiveSize The maximum size of an archive.
+ * @param maxArchivedFileSize The maximum extracted size of a single
file in any
+ * archive.
+ * @param maxCachedElements The maximum number of cached elements (an
element is a
+ * file extracted from an archive. It is stored, encrypted and padded,
in a single
+ * file.
+ * @param cacheDir The directory in which to store cached data.
+ * @param random A random source for the encryption keys used by stored
files.
+ */
ArchiveManager(int maxHandlers, long maxCachedData, long
maxArchiveSize, long maxArchivedFileSize, int maxCachedElements, File cacheDir,
RandomSource random) {
maxArchiveHandlers = maxHandlers;
archiveHandlers = new LRUHashtable();
@@ -59,12 +72,14 @@
final int maxArchiveHandlers;
final LRUHashtable archiveHandlers;
- public synchronized void putCached(FreenetURI key, ArchiveHandler zip) {
+ /** Add an ArchiveHandler by key */
+ private synchronized void putCached(FreenetURI key, ArchiveHandler zip)
{
archiveHandlers.push(key, zip);
while(archiveHandlers.size() > maxArchiveHandlers)
archiveHandlers.popKey(); // dump it
}
+ /** Get an ArchiveHandler by key */
public ArchiveHandler getCached(FreenetURI key) {
ArchiveHandler handler = (ArchiveHandler)
archiveHandlers.get(key);
archiveHandlers.push(key, handler);
@@ -80,9 +95,13 @@
// Data cache
+ /** Maximum cached data in bytes */
final long maxCachedData;
+ /** Currently cached data in bytes */
long cachedData;
+ /** Cache directory */
final File cacheDir;
+ /** Map from ArchiveKey to ArchiveStoreElement */
final LRUHashtable storedData;
/**
@@ -91,6 +110,7 @@
* It will try to serve from cache, but if that fails, will
* re-fetch.
* @param key The key of the archive that we are extracting data from.
+ * @param archiveType The archive type, defined in Metadata.
* @return An archive handler.
*/
public synchronized ArchiveHandler makeHandler(FreenetURI key, short
archiveType) {
@@ -101,15 +121,26 @@
return handler;
}
- public synchronized Bucket getCached(FreenetURI key, String filename) {
+ /**
+ * Get a cached, previously extracted, file from an archive.
+ * @param key The key used to fetch the archive.
+ * @param filename The name of the file within the archive.
+ * @return A Bucket containing the data requested, or null.
+ * @throws ArchiveFailureException
+ */
+ public synchronized Bucket getCached(FreenetURI key, String filename)
throws ArchiveFailureException {
ArchiveKey k = new ArchiveKey(key, filename);
- RealArchiveStoreItem ase = (RealArchiveStoreItem)
storedData.get(k);
+ ArchiveStoreItem asi = (ArchiveStoreItem) storedData.get(k);
+ if(asi == null) return null;
// Promote to top of LRU
- storedData.push(k, ase);
- if(ase == null) return null;
- return ase.dataAsBucket();
+ storedData.push(k, asi);
+ return asi.getDataOrThrow();
}
+ /**
+ * Remove a file from the cache.
+ * @param item The ArchiveStoreItem to remove.
+ */
synchronized void removeCachedItem(ArchiveStoreItem item) {
storedData.removeKey(item.key);
}
@@ -278,6 +309,15 @@
}
}
+ /**
+ * Add an error element to the cache. This happens when a single file
in the archive
+ * is invalid (usually because it is too large).
+ * @param ctx The ArchiveStoreContext which must be notified about this
element's creation.
+ * @param key The key from which the archive was fetched.
+ * @param name The name of the file within the archive.
+ * @param error The error message to be included on the eventual
exception thrown,
+ * if anyone tries to extract the data for this element.
+ */
private void addErrorElement(ArchiveStoreContext ctx, FreenetURI key,
String name, String error) {
ErrorArchiveStoreItem element = new ErrorArchiveStoreItem(ctx,
key, name, error);
synchronized(storedData) {
@@ -302,7 +342,7 @@
* Call synchronized on storedData.
*/
private void trimStoredData() {
- while(cachedData > maxCachedData) {
+ while(cachedData > maxCachedData || storedData.size() >
maxCachedElements) {
ArchiveStoreItem e = (ArchiveStoreItem)
storedData.popValue();
e.finalize();
}
@@ -319,7 +359,7 @@
random.nextBytes(randomFilename);
String filename = HexUtil.bytesToHex(randomFilename);
File myFile = new File(cacheDir, filename);
- FileBucket fb = new FileBucket(myFile, false, true);
+ FileBucket fb = new FileBucket(myFile, false, true, false);
byte[] cipherKey = new byte[32];
random.nextBytes(cipherKey);
@@ -331,11 +371,17 @@
}
}
+ /**
+ * Is the given MIME type an archive type that we can deal with?
+ */
public static boolean isUsableArchiveType(String type) {
return type.equals("application/zip") ||
type.equals("application/x-zip");
// Update when add new archive types
}
+ /** If the given MIME type is an archive type that we can deal with,
+ * get its archive type number (see the ARCHIVE_ constants in Metadata).
+ */
public static short getArchiveType(String type) {
if(type.equals("application/zip") ||
type.equals("application/x-zip"))
return Metadata.ARCHIVE_ZIP;
Modified: trunk/freenet/src/freenet/client/ArchiveStoreContext.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveStoreContext.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/ArchiveStoreContext.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -30,11 +30,19 @@
// Need to do anything here?
}
+ /**
+ * Get the metadata for a given archive.
+ * @return A Bucket containing the metadata, in binary format, for the
archive.
+ */
public Bucket getMetadata(ArchiveContext archiveContext, FetcherContext
fetchContext, ClientMetadata dm, int recursionLevel,
boolean dontEnterImplicitArchives) throws
ArchiveFailureException, ArchiveRestartException, MetadataParseException,
FetchException {
return get(".metadata", archiveContext, fetchContext, dm,
recursionLevel, dontEnterImplicitArchives);
}
+ /**
+ * Fetch a file in an archive. Will check the cache first, then fetch
the archive if
+ * necessary.
+ */
public Bucket get(String internalName, ArchiveContext archiveContext,
FetcherContext fetchContext, ClientMetadata dm, int recursionLevel,
boolean dontEnterImplicitArchives) throws
ArchiveFailureException, ArchiveRestartException, MetadataParseException,
FetchException {
@@ -96,6 +104,9 @@
/** Index of still-cached ArchiveStoreItems with this key */
final DoublyLinkedListImpl myItems;
+ /**
+ * Remove all ArchiveStoreItems with this key from the cache.
+ */
public void removeAllCachedItems() {
synchronized(myItems) {
ArchiveStoreItem item;
@@ -106,12 +117,14 @@
}
}
+ /** Notify that a new archive store item with this key has been added
to the cache. */
public void addItem(ArchiveStoreItem item) {
synchronized(myItems) {
myItems.push(item);
}
}
+ /** Notify that an archive store item with this key has been expelled
from the cache. */
public void removeItem(ArchiveStoreItem item) {
synchronized(myItems) {
myItems.remove(item);
Modified: trunk/freenet/src/freenet/client/ArchiveStoreItem.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveStoreItem.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/ArchiveStoreItem.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -1,5 +1,6 @@
package freenet.client;
+import freenet.support.Bucket;
import freenet.support.DoublyLinkedListImpl;
/**
@@ -9,6 +10,7 @@
final ArchiveKey key;
final ArchiveStoreContext context;
+ /** Basic constructor. */
ArchiveStoreItem(ArchiveKey key, ArchiveStoreContext context) {
this.key = key;
this.context = context;
@@ -21,4 +23,9 @@
public void finalize() {
context.removeItem(this);
}
+
+ /**
+ * Return cached data as a Bucket, or throw an ArchiveFailureException.
+ */
+ abstract Bucket getDataOrThrow() throws ArchiveFailureException;
}
Modified: trunk/freenet/src/freenet/client/ClientMetadata.java
===================================================================
--- trunk/freenet/src/freenet/client/ClientMetadata.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/ClientMetadata.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -17,6 +17,8 @@
mimeType = null;
}
+ /** Get the document MIME type. Will always be a valid MIME type,
unless there
+ * has been an error; if it is unknown, will return
application/octet-stream. */
public String getMIMEType() {
if(mimeType == null || mimeType.length() == 0)
return DefaultMIMETypes.DEFAULT_MIME_TYPE;
Modified: trunk/freenet/src/freenet/client/DefaultMIMETypes.java
===================================================================
--- trunk/freenet/src/freenet/client/DefaultMIMETypes.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/DefaultMIMETypes.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -3,6 +3,8 @@
import java.util.HashMap;
import java.util.Vector;
+import freenet.support.Logger;
+
/**
* Holds the default MIME types.
*/
@@ -11,47 +13,85 @@
/** Default MIME type - what to set it to if we don't know any better */
public static final String DEFAULT_MIME_TYPE =
"application/octet-stream";
+ /** MIME types: number -> name */
private static Vector mimeTypesByNumber = new Vector();
+ /** MIME types: name -> number */
private static HashMap mimeTypesByName = new HashMap();
+ /** MIME types by extension. One extension maps to one MIME type, but
not necessarily
+ * the other way around. */
private static HashMap mimeTypesByExtension = new HashMap();
+ /**
+ * Add a MIME type, without any extensions.
+ * @param number The number of the MIME type for compression. This
*must not change*
+ * for a given type, or the metadata format will be affected.
+ * @param type The actual MIME type string. Do not include ;charset=
etc; these are
+ * parameters and there is a separate mechanism for them.
+ */
protected static synchronized void addMIMEType(short number, String
type) {
String s = (String) mimeTypesByNumber.get(number);
if(s != null) throw new IllegalArgumentException("Already used:
"+number);
mimeTypesByNumber.set(number, type);
mimeTypesByName.put(type, new Short(number));
}
-
+
+ /**
+ * Add a MIME type.
+ * @param number The number of the MIME type for compression. This
*must not change*
+ * for a given type, or the metadata format will be affected.
+ * @param type The actual MIME type string. Do not include ;charset=
etc; these are
+ * parameters and there is a separate mechanism for them.
+ * @param extensions An array of common extensions for files of this
type. Must be
+ * unique for the type.
+ */
protected static synchronized void addMIMEType(short number, String
type, String[] extensions) {
addMIMEType(number, type);
Short t = new Short(type);
if(extensions != null)
- for(int i=0;i<extensions.length;i++)
-
mimeTypesByExtension.put(extensions[i].toLowerCase(), t);
+ for(int i=0;i<extensions.length;i++) {
+ String ext = extensions[i].toLowerCase();
+ if(mimeTypesByExtension.containsKey(ext)) {
+ Logger.error(DefaultMIMETypes.class,
"Extension already registered to number "+mimeTypesByExtension.get(ext));
+ } else
+ mimeTypesByExtension.put(ext, t);
+ }
+
}
-
+
+ /**
+ * Add a MIME type, with extensions separated by spaces. This is more
or less
+ * the format in /etc/mime-types.
+ */
protected static synchronized void addMIMEType(short number, String
type, String extensions) {
addMIMEType(number, type, extensions.split(" "));
}
-
+
+ /**
+ * Get a known MIME type by number.
+ */
public static String byNumber(short x) {
if(x > mimeTypesByNumber.size() || x < 0)
return null;
return (String) mimeTypesByNumber.get(x);
}
+ /**
+ * Get the number of a MIME type, or -1 if it is not in the table of
known MIME
+ * types, in which case it will have to be sent uncompressed.
+ */
public static short byName(String s) {
Short x = (Short) mimeTypesByName.get(s);
if(x != null) return x.shortValue();
else return -1;
}
- // From toad's /etc/mime.types
- // cat /etc/mime.types | sed "/^$/d;/#/d" | tr --squeeze '\t' ' ' |
- // (y=0; while read x; do echo "$x" |
- // sed -n "s/^\([^ ]*\)$/addMIMEType\($y, \"\1\"\);/p;s/^\([^ (),]\+\)
\(.*\)$/addMIMEType\($y, \"\1\", \"\2\"\);/p;"; y=$((y+1)); done)
+ /* From toad's /etc/mime.types
+ * cat /etc/mime.types | sed "/^$/d;/#/d" | tr --squeeze '\t' ' ' |
+ * (y=0; while read x; do echo "$x" |
+ * sed -n "s/^\([^ ]*\)$/addMIMEType\($y, \"\1\"\);/p;s/^\([^ (),]\+\)
\(.*\)$/addMIMEType\($y, \"\1\", \"\2\"\);/p;"; y=$((y+1)); done)
+ */
static {
addMIMEType((short)0, "application/activemessage");
Modified: trunk/freenet/src/freenet/client/ErrorArchiveStoreItem.java
===================================================================
--- trunk/freenet/src/freenet/client/ErrorArchiveStoreItem.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/ErrorArchiveStoreItem.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -1,11 +1,21 @@
package freenet.client;
import freenet.keys.FreenetURI;
+import freenet.support.Bucket;
class ErrorArchiveStoreItem extends ArchiveStoreItem {
+ /** Error message. Usually something about the file being too big. */
String error;
+ /**
+ * Create a placeholder item for a file which could not be extracted
from the archive.
+ * @param ctx The context object which tracks all the items with this
key.
+ * @param key2 The key from which the archive was fetched.
+ * @param name The name of the file which failed to extract.
+ * @param error The error message to be included in the thrown
exception when
+ * somebody tries to get the data.
+ */
public ErrorArchiveStoreItem(ArchiveStoreContext ctx, FreenetURI key2,
String name, String error) {
super(new ArchiveKey(key2, name), ctx);
this.error = error;
@@ -14,5 +24,13 @@
public void finalize() {
super.finalize();
}
+
+ /**
+ * Throws an exception with the given error message, because this file
could not be
+ * extracted from the archive.
+ */
+ Bucket getDataOrThrow() throws ArchiveFailureException {
+ throw new ArchiveFailureException(error);
+ }
}
Modified: trunk/freenet/src/freenet/client/FetchException.java
===================================================================
--- trunk/freenet/src/freenet/client/FetchException.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/FetchException.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -1,11 +1,20 @@
package freenet.client;
+/**
+ * Generic exception thrown by a Fetcher. All other exceptions are converted
to one of
+ * these to tell the client.
+ */
public class FetchException extends Exception {
private static final long serialVersionUID = -1106716067841151962L;
final int mode;
+ /** Get the failure mode. */
+ public int getMode() {
+ return mode;
+ }
+
public FetchException(int m) {
mode = m;
}
@@ -21,27 +30,29 @@
}
/** Too many levels of recursion into archives */
- static final int TOO_DEEP_ARCHIVE_RECURSION = 1;
+ public static final int TOO_DEEP_ARCHIVE_RECURSION = 1;
/** Don't know what to do with splitfile */
- static final int UNKNOWN_SPLITFILE_METADATA = 2;
+ public static final int UNKNOWN_SPLITFILE_METADATA = 2;
/** Too many ordinary redirects */
- static final int TOO_MANY_REDIRECTS = 3;
+ public static final int TOO_MANY_REDIRECTS = 3;
/** Don't know what to do with metadata */
- static final int UNKNOWN_METADATA = 3;
+ public static final int UNKNOWN_METADATA = 3;
/** Got a MetadataParseException */
- static final int INVALID_METADATA = 4;
+ public static final int INVALID_METADATA = 4;
/** Got an ArchiveFailureException */
- static final int ARCHIVE_FAILURE = 5;
+ public static final int ARCHIVE_FAILURE = 5;
/** Failed to decode a block */
- static final int BLOCK_DECODE_ERROR = 6;
+ public static final int BLOCK_DECODE_ERROR = 6;
/** Too many split metadata levels */
- static final int TOO_MANY_METADATA_LEVELS = 7;
+ public static final int TOO_MANY_METADATA_LEVELS = 7;
/** Too many archive restarts */
- static final int TOO_MANY_ARCHIVE_RESTARTS = 8;
+ public static final int TOO_MANY_ARCHIVE_RESTARTS = 8;
/** Too deep recursion */
- static final int TOO_MUCH_RECURSION = 9;
+ public static final int TOO_MUCH_RECURSION = 9;
/** Tried to access an archive file but not in an archive */
- static final int NOT_IN_ARCHIVE = 10;
+ public static final int NOT_IN_ARCHIVE = 10;
/** Has more metastrings, can't fulfill them */
- static final int HAS_MORE_METASTRINGS = 11;
+ public static final int HAS_MORE_METASTRINGS = 11;
+ /** Internal error, probably failed to read from a bucket */
+ public static final int BUCKET_ERROR = 12;
}
Modified: trunk/freenet/src/freenet/client/FetchResult.java
===================================================================
--- trunk/freenet/src/freenet/client/FetchResult.java 2005-10-28 22:54:13 UTC
(rev 7465)
+++ trunk/freenet/src/freenet/client/FetchResult.java 2005-10-29 15:07:27 UTC
(rev 7466)
@@ -18,7 +18,8 @@
data = fetched;
}
- /** If so, get the MIME type */
+ /** Get the MIME type of the fetched data.
+ * If unknown, returns application/octet-stream. */
public String getMimeType() {
return metadata.getMIMEType();
}
Modified: trunk/freenet/src/freenet/client/Fetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/Fetcher.java 2005-10-28 22:54:13 UTC
(rev 7465)
+++ trunk/freenet/src/freenet/client/Fetcher.java 2005-10-29 15:07:27 UTC
(rev 7466)
@@ -16,16 +16,41 @@
*/
class Fetcher {
+ /** The original URI to be fetched. */
final FreenetURI origURI;
+ /** The settings for the fetch e.g. max file size */
final FetcherContext ctx;
+ /** The archive context object to be passed down the entire request.
This is
+ * recreated if we get an ArchiveRestartException. It does loop
detection, partly
+ * in order to prevent rare deadlocks.
+ */
ArchiveContext archiveContext;
- public Fetcher(FreenetURI uri, FetcherContext ctx, ArchiveContext
archiveContext) {
- this.origURI = uri;
- this.ctx = ctx;
- this.archiveContext = archiveContext;
+ /**
+ * Local-only constructor, with ArchiveContext, for recursion via e.g.
archives.
+ */
+ Fetcher(FreenetURI uri, FetcherContext fctx, ArchiveContext actx) {
+ origURI = uri;
+ ctx = fctx;
+ archiveContext = actx;
}
+ /**
+ * Create a Fetcher. Public constructor, for when starting a new
request chain.
+ * @param uri The key to fetch.
+ * @param ctx The settings for the fetch.
+ */
+ public Fetcher(FreenetURI uri, FetcherContext ctx) {
+ this(uri, ctx, new ArchiveContext());
+ }
+
+ /**
+ * Fetch the key. Called by clients.
+ * @return The key requested's data and client metadata.
+ * @throws FetchException If we cannot fetch the key for some reason.
Various
+ * other exceptions are used internally; they are converted to a
FetchException
+ * by this driver routine.
+ */
public FetchResult run() throws FetchException {
for(int i=0;i<ctx.maxArchiveRestarts;i++) {
try {
@@ -46,7 +71,8 @@
}
/**
- * Fetch a key.
+ * Fetch a key, within an overall fetch process. Called by self in
recursion, and
+ * called by driver function @see run() .
* @param dm The client metadata object to accumulate client metadata
in.
* @param recursionLevel The recursion level. Incremented every time we
enter
* realRun(). If it goes above a certain limit, we throw a
FetchException.
@@ -127,7 +153,11 @@
} else if(metadata.isArchiveManifest()) {
container = ctx.archiveManager.makeHandler(thisKey,
metadata.getArchiveType());
Bucket metadataBucket =
container.getMetadata(archiveContext, ctx, dm, recursionLevel, true);
- metadata = Metadata.construct(metadataBucket);
+ try {
+ metadata = Metadata.construct(metadataBucket);
+ } catch (IOException e) {
+ throw new
FetchException(FetchException.BUCKET_ERROR);
+ }
return runMetadata(dm, recursionLevel+1, key,
metaStrings, metadata, container, thisKey, dontEnterImplicitArchives);
} else if(metadata.isArchiveInternalRedirect()) {
if(container == null)
@@ -144,7 +174,11 @@
// Possible implicit archive inside
archive?
container =
ctx.archiveManager.makeHandler(thisKey,
ArchiveManager.getArchiveType(dm.getMIMEType()));
Bucket metadataBucket =
container.getMetadata(archiveContext, ctx, dm, recursionLevel, true);
- metadata =
Metadata.construct(metadataBucket);
+ try {
+ metadata =
Metadata.construct(metadataBucket);
+ } catch (IOException e) {
+ throw new
FetchException(FetchException.BUCKET_ERROR);
+ }
return runMetadata(dm,
recursionLevel+1, key, metaStrings, metadata, container, thisKey,
dontEnterImplicitArchives);
}
Bucket result =
container.get(metadata.getZIPInternalName(), archiveContext, ctx, dm,
recursionLevel, true);
@@ -155,7 +189,11 @@
// Doesn't have to be a splitfile; could be from a ZIP
or a plain file.
metadata.setSimpleRedirect();
FetchResult res = runMetadata(dm, recursionLevel, key,
metaStrings, metadata, container, thisKey, true);
- metadata = Metadata.construct(res.data);
+ try {
+ metadata = Metadata.construct(res.data);
+ } catch (IOException e) {
+ throw new
FetchException(FetchException.BUCKET_ERROR);
+ }
return runMetadata(dm, recursionLevel, key,
metaStrings, metadata, container, thisKey, dontEnterImplicitArchives);
} else if(metadata.isSingleFileRedirect()) {
FreenetURI uri = metadata.getSingleTarget();
@@ -168,7 +206,11 @@
// We might not have to fetch it.
container =
ctx.archiveManager.makeHandler(uri,
ArchiveManager.getArchiveType(dm.getMIMEType()));
Bucket metadataBucket =
container.getMetadata(archiveContext, ctx, dm, recursionLevel, true);
- metadata =
Metadata.construct(metadataBucket);
+ try {
+ metadata =
Metadata.construct(metadataBucket);
+ } catch (IOException e) {
+ throw new
FetchException(FetchException.BUCKET_ERROR);
+ }
return runMetadata(dm,
recursionLevel+1, key, metaStrings, metadata, container, thisKey,
dontEnterImplicitArchives);
}
}
@@ -181,7 +223,11 @@
// We know target is not metadata.
container =
ctx.archiveManager.makeHandler(thisKey,
ArchiveManager.getArchiveType(dm.getMIMEType()));
Bucket metadataBucket =
container.getMetadata(archiveContext, ctx, dm, recursionLevel, true);
- metadata = Metadata.construct(metadataBucket);
+ try {
+ metadata =
Metadata.construct(metadataBucket);
+ } catch (IOException e) {
+ throw new
FetchException(FetchException.BUCKET_ERROR);
+ }
return runMetadata(dm, recursionLevel+1, key,
metaStrings, metadata, container, thisKey, dontEnterImplicitArchives);
}
Modified: trunk/freenet/src/freenet/client/FetcherContext.java
===================================================================
--- trunk/freenet/src/freenet/client/FetcherContext.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/FetcherContext.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -3,9 +3,10 @@
import freenet.node.SimpleLowLevelClient;
import freenet.support.BucketFactory;
-/** Context for a Fetcher */
+/** Context for a Fetcher. Contains all the settings a Fetcher needs to know
about. */
public class FetcherContext {
-
+
+ /** Low-level client to send low-level requests to. */
final SimpleLowLevelClient client;
final long maxOutputLength;
final long maxTempLength;
Modified: trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
===================================================================
--- trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
2005-10-28 22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
2005-10-29 15:07:27 UTC (rev 7466)
@@ -29,10 +29,13 @@
curMaxTempLength = maxIntermediateLength;
}
+ /**
+ * Fetch a key. Either returns the data, or throws an exception.
+ */
public FetchResult fetch(FreenetURI uri) throws FetchException {
FetcherContext context = new FetcherContext(client,
curMaxLength, curMaxLength,
MAX_RECURSION, MAX_ARCHIVE_RESTARTS,
DONT_ENTER_IMPLICIT_ARCHIVES, archiveManager, bucketFactory);
- Fetcher f = new Fetcher(uri, context, new ArchiveContext());
+ Fetcher f = new Fetcher(uri, context);
return f.run();
}
Modified: trunk/freenet/src/freenet/client/Metadata.java
===================================================================
--- trunk/freenet/src/freenet/client/Metadata.java 2005-10-28 22:54:13 UTC
(rev 7465)
+++ trunk/freenet/src/freenet/client/Metadata.java 2005-10-29 15:07:27 UTC
(rev 7466)
@@ -25,6 +25,10 @@
/** Soft limit, to avoid memory DoS */
static final int MAX_SPLITFILE_BLOCKS = 100*1000;
+ /** Parse a block of bytes into a Metadata structure.
+ * Constructor method because of need to catch impossible exceptions.
+ * @throws MetadataParseException If the metadata is invalid.
+ */
public static Metadata construct(byte[] data) throws
MetadataParseException {
try {
return new Metadata(data);
@@ -35,23 +39,22 @@
}
}
- public static Metadata construct(Bucket data) throws
MetadataParseException {
- try {
- return new Metadata(data);
- } catch (IOException e) {
- MetadataParseException e1 = new
MetadataParseException("Caught "+e);
- e1.initCause(e);
- throw e1;
- }
+ /**
+ * Parse a bucket of data into a Metadata structure.
+ * @throws MetadataParseException If the parsing failed because of
invalid metadata.
+ * @throws IOException If we could not read the metadata from the
bucket.
+ */
+ public static Metadata construct(Bucket data) throws
MetadataParseException, IOException {
+ return new Metadata(data);
}
- /** Parse some metadata from a byte[]
+ /** Parse some metadata from a byte[].
* @throws IOException If the data is incomplete, or something wierd
happens. */
private Metadata(byte[] data) throws IOException {
this(new DataInputStream(new ByteArrayInputStream(data)),
false, data.length);
}
- /** Parse some metadata from a Bucket
+ /** Parse some metadata from a Bucket.
* @throws IOException If the data is incomplete, or something wierd
happens. */
public Metadata(Bucket meta) throws IOException {
this(new DataInputStream(meta.getInputStream()), false,
meta.size());
@@ -257,6 +260,13 @@
manifestEntryCount = count;
}
+ /**
+ * Create a really simple Metadata object.
+ * @param docType The document type. Must be something that takes a
single argument.
+ * At the moment this means ZIP_INTERNAL_REDIRECT.
+ * @param arg The argument; in the case of ZIP_INTERNAL_REDIRECT, the
filename in
+ * the archive to read from.
+ */
public Metadata(byte docType, String arg) {
if(docType == ZIP_INTERNAL_REDIRECT) {
documentType = docType;
@@ -268,6 +278,9 @@
throw new IllegalArgumentException();
}
+ /**
+ * Set the MIME type to a string. Compresses it if possible for transit.
+ */
private void setMIMEType(String type) {
short s = DefaultMIMETypes.byName(type);
if(s >= 0) {
@@ -279,7 +292,10 @@
mimeType = type;
}
- private byte[] writeToByteArray() {
+ /**
+ * Write the data to a byte array.
+ */
+ byte[] writeToByteArray() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
try {
@@ -359,7 +375,7 @@
static final short FLAGS_SPLIT_USE_LENGTHS = 64;
static final short FLAGS_COMPRESSED = 128;
- /** ZIP manifest archive type */
+ /** Container archive type */
short archiveType;
static final short ARCHIVE_ZIP = 0;
static final short ARCHIVE_TAR = 1; // FIXME for future use
@@ -407,7 +423,8 @@
String nameInArchive;
ClientMetadata clientMetadata;
-
+
+ /** Is a manifest? */
public boolean isSimpleManifest() {
return documentType == SIMPLE_MANIFEST;
}
@@ -486,6 +503,7 @@
return splitfile && documentType == SIMPLE_REDIRECT;
}
+ /** Is multi-level/indirect metadata? */
public boolean isMultiLevelMetadata() {
return documentType == MULTI_LEVEL_METADATA;
}
@@ -503,7 +521,7 @@
}
/** Write the metadata as binary.
- * @throws IOException */
+ * @throws IOException If an I/O error occurred while writing the data.
*/
public void writeTo(DataOutputStream dos) throws IOException {
dos.writeLong(FREENET_METADATA_MAGIC);
dos.writeShort(0); // version
Modified: trunk/freenet/src/freenet/client/RealArchiveStoreItem.java
===================================================================
--- trunk/freenet/src/freenet/client/RealArchiveStoreItem.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/client/RealArchiveStoreItem.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -29,18 +29,28 @@
this.finalized = false;
this.bucket = temp.bucket;
this.underBucket = temp.underBucket;
+ underBucket.dontDeleteOnFinalize();
underBucket.setReadOnly();
this.manager.cachedData += spaceUsed();
}
+ /**
+ * Return the data, as a Bucket, in plaintext.
+ */
Bucket dataAsBucket() {
return bucket;
}
+ /**
+ * Return the length of the data.
+ */
long dataSize() {
return bucket.size();
}
-
+
+ /**
+ * Return the estimated space used by the data.
+ */
long spaceUsed() {
return FileUtil.estimateUsage(myFilename, underBucket.size());
}
@@ -53,4 +63,8 @@
finalized = true;
this.manager.cachedData -= sz;
}
+
+ Bucket getDataOrThrow() throws ArchiveFailureException {
+ return dataAsBucket();
+ }
}
\ No newline at end of file
Modified: trunk/freenet/src/freenet/support/io/FileBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/io/FileBucket.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/support/io/FileBucket.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -36,14 +36,14 @@
* @param file The File to read and write to.
* @param readOnly If true, any attempt to write to the bucket will
result in an IOException.
* Can be set later. Irreversible. @see isReadOnly(), setReadOnly()
- * @param deleteOnExit If true, delete the file on finalization.
- *
+ * @param deleteOnFinalize If true, delete the file on finalization.
Reversible.
+ * @param deleteOnExit If true, delete the file on a clean exit of the
JVM. Irreversible - use with care!
*/
- public FileBucket(File file, boolean readOnly, boolean deleteOnExit) {
+ public FileBucket(File file, boolean readOnly, boolean
deleteOnFinalize, boolean deleteOnExit) {
this.readOnly = readOnly;
this.file = file;
- this.newFile = deleteOnExit;
- if(newFile)
+ this.newFile = deleteOnFinalize;
+ if(deleteOnExit)
file.deleteOnExit();
// Useful for finding temp file leaks.
// System.err.println("-- FileBucket.ctr(0) -- " +
@@ -293,4 +293,13 @@
public void setReadOnly() {
readOnly = true;
}
+
+ /**
+ * Turn off "delete file on finalize" flag.
+ * Note that if you have already set delete file on exit, there is
little that you
+ * can do to recover it! Delete file on finalize, on the other hand, is
reversible.
+ */
+ public void dontDeleteOnFinalize() {
+ newFile = false;
+ }
}
Modified: trunk/freenet/src/freenet/support/io/FileBucketFactory.java
===================================================================
--- trunk/freenet/src/freenet/support/io/FileBucketFactory.java 2005-10-28
22:54:13 UTC (rev 7465)
+++ trunk/freenet/src/freenet/support/io/FileBucketFactory.java 2005-10-29
15:07:27 UTC (rev 7466)
@@ -40,7 +40,7 @@
// e.printStackTrace();
// System.err.println("----------------------------------------");
} while (f.exists());
- Bucket b = new FileBucket(f, false, false);
+ Bucket b = new FileBucket(f, false, true, false);
files.addElement(f);
return b;
}
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs