public synchronized void run() {
      try {
        while (waitingOnSubindex.size() > 0) {
          if (fetchStatus == FetchStatus.UNFETCHED || fetchStatus == FetchStatus.FAILED) {
            try {
              fetchStatus = FetchStatus.FETCHING;
              // TODO tidy the fetch stuff
              bucket = Util.fetchBucket(indexuri + filename, hlsc);
              fetchStatus = FetchStatus.FETCHED;

            } catch (Exception e) { // TODO tidy the exceptions
              // java.net.MalformedURLException
              // freenet.client.FetchException
              String msg = indexuri + filename + " could not be opened: " + e.toString();
              Logger.error(this, msg, e);
              throw new TaskAbortException(msg, e);
            }
          } else if (fetchStatus == FetchStatus.FETCHED) {
            parseSubIndex();
          } else {
            break;
          }
        }
      } catch (TaskAbortException e) {
        fetchStatus = FetchStatus.FAILED;
        this.error = e;
        Logger.error(this, "Dropping from subindex run loop", e);
        for (FindRequest r : parsingSubindex) r.setError(e);
        for (FindRequest r : waitingOnSubindex) r.setError(e);
      }
    }
 /** Called on failed/canceled fetch */
 public void onFailure(FetchException e, ClientGetter state, ObjectContainer container) {
   fetchFailures++;
   if (fetchFailures < 20 && e.newURI != null) {
     try {
       if (logMINOR) Logger.minor(this, "Trying new URI: " + e.newURI);
       indexuri = e.newURI.setMetaString(new String[] {""}).toString();
       if (origEdition != -1 && e.newURI.getEdition() < origEdition) {
         Logger.error(
             this,
             "Redirect to earlier edition?!?!?!?: "
                 + e.newURI.getEdition()
                 + " from "
                 + origEdition);
       } else {
         if (logMINOR) Logger.minor(this, "Trying new URI: " + e.newURI + " : " + indexuri);
         startFetch(true);
         if (updateHook != null) updateHook.update(updateContext, indexuri);
         return;
       }
     } catch (FetchException ex) {
       e = ex;
     } catch (MalformedURLException ex) {
       Logger.error(this, "what?", ex);
     }
   }
   fetchStatus = FetchStatus.FAILED;
   for (FindRequest findRequest : waitingOnMainIndex) {
     findRequest.setError(
         new TaskAbortException("Failure fetching rootindex of " + toString(), e));
   }
   Logger.error(this, "Fetch failed on " + toString() + " -- state = " + state, e);
 }
 /**
  * process the bucket containing the main index file
  *
  * @param bucket
  */
 private void processRequests(Bucket bucket) {
   try {
     InputStream is = bucket.getInputStream();
     parse(is);
     is.close();
     fetchStatus = FetchStatus.FETCHED;
     for (FindRequest req : waitingOnMainIndex) setdependencies(req);
     waitingOnMainIndex.clear();
   } catch (Exception e) {
     fetchStatus = FetchStatus.FAILED;
     for (FindRequest findRequest : waitingOnMainIndex) {
       findRequest.setError(new TaskAbortException("Failure parsing " + toString(), e));
     }
     Logger.error(this, indexuri, e);
   } finally {
     bucket.free();
   }
 }