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

Reply via email to