r27121 - trunk/freenet/src/freenet/client/async

[email protected] Mon, 20 Apr 2009 21:21:12 +0000
Newsgroups gmane.network.freenet.cvs
Message-ID <[email protected]>
Author: saces
Date: 2009-04-20 21:21:11 +0000 (Mon, 20 Apr 2009)
New Revision: 27121

Modified:
   trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
Log:
teach the SFI how to fetch the new metadata format (ARCHIVE_METADATA_REDIRECT)
needs review

Modified: trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleFileFetcher.java	2009-04-20 21:16:19 UTC (rev 27120)
+++ trunk/freenet/src/freenet/client/async/SingleFileFetcher.java	2009-04-20 21:21:11 UTC (rev 27121)
@@ -114,7 +114,7 @@
 	/** Copy constructor, modifies a few given fields, don't call schedule().
 	 * Used for things like slave fetchers for MultiLevelMetadata, therefore does not remember returnBucket,
 	 * metaStrings etc. */
-	public SingleFileFetcher(SingleFileFetcher fetcher, boolean persistent, boolean deleteFetchContext, Metadata newMeta, GetCompletionCallback callback, FetchContext ctx2, ObjectContainer container, ClientContext context) throws FetchException {
+	public SingleFileFetcher(SingleFileFetcher fetcher, boolean persistent, boolean deleteFetchContext, Metadata newMeta, ArrayList<String> metaStrings2, GetCompletionCallback callback, FetchContext ctx2, ObjectContainer container, ClientContext context) throws FetchException {
 		// Don't add a block, we have already fetched the data, we are just handling the metadata in a different fetcher.
 		super(persistent ? fetcher.key.cloneKey() : fetcher.key, fetcher.maxRetries, ctx2, fetcher.parent, callback, false, true, fetcher.token, container, context, deleteFetchContext);
 		if(logMINOR) Logger.minor(this, "Creating SingleFileFetcher for "+fetcher.key+" meta="+fetcher.metaStrings.toString(), new Exception("debug"));
@@ -128,7 +128,7 @@
 		this.archiveMetadata = null;
 		this.clientMetadata = (fetcher.clientMetadata != null ? fetcher.clientMetadata.clone() : new ClientMetadata());
 		this.metadata = newMeta;
-		this.metaStrings = new ArrayList<String>();
+		this.metaStrings = metaStrings2;
 		this.addedMetaStrings = 0;
 		this.recursionLevel = fetcher.recursionLevel + 1;
 		if(recursionLevel > ctx.maxRecursionLevel)
@@ -471,6 +471,83 @@
 				}
 				metadataBucket.free();
 				continue;
+			} else if(metadata.isArchiveMetadataRedirect()) {
+				if(logMINOR) Logger.minor(this, "Is archive-metadata");
+				// Fetch it from the archive
+				if(ah == null)
+					throw new FetchException(FetchException.UNKNOWN_METADATA, "Archive redirect not in an archive manifest");
+				String filename = metadata.getArchiveInternalName();
+				if(logMINOR) Logger.minor(this, "Fetching "+filename);
+				Bucket dataBucket = ah.get(filename, actx, context.archiveManager);
+				if(dataBucket != null) {
+					if(logMINOR) Logger.minor(this, "Returning data");
+					final Metadata newMetadata;
+					try {
+						
+						newMetadata = Metadata.construct(dataBucket);
+						dataBucket.free();
+					} catch (IOException e) {
+						throw new FetchException(FetchException.BUCKET_ERROR);
+					}
+					continueWithNewMetadata(newMetadata, this.rcb, container, context);
+					return;
+				} else {
+					if(logMINOR) Logger.minor(this, "Fetching archive (thisKey="+thisKey+ ')');
+					// Metadata cannot contain pointers to files which don't exist.
+					// We enforce this in ArchiveHandler.
+					// Therefore, the archive needs to be fetched.
+					final boolean persistent = this.persistent;
+					fetchArchive(true, archiveMetadata, filename, new ArchiveExtractCallback() {
+						public void gotBucket(Bucket data, ObjectContainer container, ClientContext context) {
+							if(persistent)
+								container.activate(SingleFileFetcher.this, 1);
+							if(logMINOR) Logger.minor(this, "Returning data");
+							final Metadata newMetadata;
+							try {
+								
+								newMetadata = Metadata.construct(data);
+								continueWithNewMetadata(newMetadata, SingleFileFetcher.this.rcb, container, context);
+							} catch (IOException e) {
+								onFailure(new FetchException(FetchException.BUCKET_ERROR), false, container, context);
+							} catch (MetadataParseException e) {
+								onFailure(new FetchException(FetchException.INVALID_METADATA), false, container, context);
+							} catch (FetchException e) {
+								onFailure(e, false, container, context);
+							} finally {
+								data.free();
+							}
+							if(persistent)
+								container.deactivate(SingleFileFetcher.this, 1);
+						}
+						public void notInArchive(ObjectContainer container, ClientContext context) {
+							if(persistent)
+								container.activate(SingleFileFetcher.this, 1);
+							onFailure(new FetchException(FetchException.NOT_IN_ARCHIVE), false, container, context);
+							if(persistent)
+								container.deactivate(SingleFileFetcher.this, 1);
+						}
+						public void onFailed(ArchiveRestartException e, ObjectContainer container, ClientContext context) {
+							if(persistent)
+								container.activate(SingleFileFetcher.this, 1);
+							SingleFileFetcher.this.onFailure(new FetchException(e), false, container, context);
+							if(persistent)
+								container.deactivate(SingleFileFetcher.this, 1);
+						}
+						public void onFailed(ArchiveFailureException e, ObjectContainer container, ClientContext context) {
+							if(persistent)
+								container.activate(SingleFileFetcher.this, 1);
+							SingleFileFetcher.this.onFailure(new FetchException(e), false, container, context);
+							if(persistent)
+								container.deactivate(SingleFileFetcher.this, 1);
+						}
+						public void removeFrom(ObjectContainer container) {
+							container.delete(this);
+						}
+					}, container, context);
+					removeMetadata(container);
+					// Will call back into this function when it has been fetched.
+					return;
+				}
 			} else if(metadata.isArchiveInternalRedirect()) {
 				if(logMINOR) Logger.minor(this, "Is archive-internal redirect");
 				clientMetadata.mergeNoOverwrite(metadata.getClientMetadata());
@@ -576,18 +653,7 @@
 				if(logMINOR) Logger.minor(this, "Is multi-level metadata");
 				// Fetch on a second SingleFileFetcher, like with archives.
 				metadata.setSimpleRedirect();
-				final SingleFileFetcher f = new SingleFileFetcher(this, persistent, false, metadata, new MultiLevelMetadataCallback(), ctx, container, context);
-				// Clear our own metadata so it can be garbage collected, it will be replaced by whatever is fetched.
-				// The new fetcher has our metadata so we don't need to removeMetadata().
-				this.metadata = null;
-				if(persistent) container.store(this);
-				if(persistent) container.store(f);
-				
-				// We must transition to the sub-fetcher so that if the request is cancelled, it will get deleted.
-				parent.onTransition(this, f, container);
-				
-				f.wrapHandleMetadata(true, container, context);
-				if(persistent) container.deactivate(f, 1);
+				continueWithNewMetadata(metadata, new MultiLevelMetadataCallback(), container, context);
 				return;
 			} else if(metadata.isSingleFileRedirect()) {
 				if(logMINOR) Logger.minor(this, "Is single-file redirect");
@@ -768,6 +834,22 @@
 			}
 		}
 	}
+	
+	private void continueWithNewMetadata(Metadata newMetadata, GetCompletionCallback callback, ObjectContainer container, ClientContext context) throws FetchException {
+		final SingleFileFetcher f = new SingleFileFetcher(this, persistent, false, newMetadata, metaStrings, callback, ctx, container, context);
+		// Clear our own metadata so it can be garbage collected, it will be replaced by whatever is fetched.
+		// The new fetcher has our metadata so we don't need to removeMetadata().
+		metadata = null;
+		if(persistent) container.store(this);
+		if(persistent) container.store(f);
+		
+		// We must transition to the sub-fetcher so that if the request is cancelled, it will get deleted.
+		parent.onTransition(this, f, container);
+		
+		f.wrapHandleMetadata(true, container, context);
+		if(persistent) container.deactivate(f, 1);
+		return;
+	}
 
 	private String removeMetaString() {
 		String name = metaStrings.remove(0);
@@ -792,7 +874,7 @@
 		Metadata newMeta = (Metadata) meta.clone();
 		newMeta.setSimpleRedirect();
 		final SingleFileFetcher f;
-		f = new SingleFileFetcher(this, persistent, true, newMeta, new ArchiveFetcherCallback(forData, element, callback), new FetchContext(ctx, FetchContext.SET_RETURN_ARCHIVES, true, null), container, context);
+		f = new SingleFileFetcher(this, persistent, true, newMeta, new ArrayList<String>(), new ArchiveFetcherCallback(forData, element, callback), new FetchContext(ctx, FetchContext.SET_RETURN_ARCHIVES, true, null), container, context);
 		if(persistent) container.store(f);
 		if(logMINOR) Logger.minor(this, "fetchArchive(): "+f);
 		// Fetch the archive. The archive fetcher callback will unpack it, and either call the element