synchronized void addDownload(DownloadRequestStatus status) {
   RequestStatus old = requestsByIdentifier.put(status.getIdentifier(), status);
   if (logMINOR) Logger.minor(this, "Starting download " + status.getIdentifier());
   if (old == status) return;
   if (old != null) downloads.remove(old);
   downloads.add(status);
   downloadsByURI.put(status.getURI(), status);
 }
 /**
  * Restart a download. Caller should call ,false first, at which point we setStarted, and ,true
  * when it has actually started (a race condition means we don't setStarted at that point since
  * it's possible the success/failure callback might happen first).
  *
  * @param redirect If non-null, the request followed a redirect.
  */
 public synchronized void updateStarted(String identifier, FreenetURI redirect) {
   DownloadRequestStatus status = (DownloadRequestStatus) requestsByIdentifier.get(identifier);
   if (status == null) return; // Can happen during cancel etc.
   status.restart(false);
   if (redirect != null) {
     downloadsByURI.remove(status.getURI());
     status.redirect(redirect);
     downloadsByURI.put(redirect, status);
   }
 }
 synchronized void updateDetectedCompatModes(
     String identifier,
     InsertContext.CompatibilityMode[] compatModes,
     byte[] splitfileKey,
     boolean dontCompress) {
   DownloadRequestStatus status = (DownloadRequestStatus) requestsByIdentifier.get(identifier);
   if (status == null) return; // Can happen during cancel etc.
   status.updateDetectedCompatModes(compatModes, dontCompress);
   status.updateDetectedSplitfileKey(splitfileKey);
 }
 public synchronized CacheFetchResult getShadowBucket(FreenetURI key, boolean noFilter) {
   Object[] downloads = downloadsByURI.getArray(key);
   if (downloads == null) return null;
   for (Object o : downloads) {
     DownloadRequestStatus download = (DownloadRequestStatus) o;
     Bucket data = download.getDataShadow();
     if (data == null) continue;
     if (data.size() == 0) continue;
     if (noFilter && download.filterData) continue;
     // FIXME it probably *is* worth the effort to allow this when it is overridden on the fetcher,
     // since the user changed the type???
     if (download.overriddenDataType) continue;
     return new CacheFetchResult(
         new ClientMetadata(download.getMIMEType()), new NoFreeBucket(data), download.filterData);
   }
   return null;
 }
 synchronized void finishedDownload(
     String identifier,
     boolean success,
     long dataSize,
     String mimeType,
     FetchExceptionMode failureCode,
     String failureReasonLong,
     String failureReasonShort,
     Bucket dataShadow,
     boolean filtered) {
   DownloadRequestStatus status = (DownloadRequestStatus) requestsByIdentifier.get(identifier);
   if (status == null) return; // Can happen during cancel etc.
   status.setFinished(
       success,
       dataSize,
       mimeType,
       failureCode,
       failureReasonLong,
       failureReasonShort,
       dataShadow,
       filtered);
 }
 public synchronized void updateExpectedDataLength(String identifier, long expectedDataLength) {
   DownloadRequestStatus status = (DownloadRequestStatus) requestsByIdentifier.get(identifier);
   if (status == null) return; // Can happen during cancel etc.
   status.updateExpectedDataLength(expectedDataLength);
 }
 public synchronized void updateExpectedMIME(String identifier, String foundDataMimeType) {
   DownloadRequestStatus status = (DownloadRequestStatus) requestsByIdentifier.get(identifier);
   if (status == null) return; // Can happen during cancel etc.
   status.updateExpectedMIME(foundDataMimeType);
 }