public void asyncDownload() {
    try {
      this_mon.enter();

      if (current_index == max_to_try || cancelled) {

        done_sem.release();

        informFailed((ResourceDownloaderException) result);

      } else {

        current_downloader = ((ResourceDownloaderBaseImpl) delegates[current_index]).getClone(this);

        informActivity(getLogIndent() + "Downloading: " + getName());

        current_index++;

        current_downloader.addListener(this);

        current_downloader.asyncDownload();
      }
    } finally {

      this_mon.exit();
    }
  }
  public boolean completed(ResourceDownloader downloader, InputStream data) {
    if (informComplete(data)) {

      result = data;

      done_sem.release();

      return (true);
    }

    return (false);
  }
  public void cancel() {
    setCancelled();

    try {
      this_mon.enter();

      result = new ResourceDownloaderCancelledException(this);

      cancelled = true;

      informFailed((ResourceDownloaderException) result);

      done_sem.release();

      if (current_downloader != null) {

        current_downloader.cancel();
      }
    } finally {

      this_mon.exit();
    }
  }
  public InputStream download() throws ResourceDownloaderException {

    if (delegates.length == 0) {

      ResourceDownloaderException error =
          new ResourceDownloaderException(this, "Alternate download fails - 0 alteratives");

      informFailed(error);

      throw (error);
    }

    asyncDownload();

    done_sem.reserve();

    if (result instanceof InputStream) {

      return ((InputStream) result);
    }

    throw ((ResourceDownloaderException) result);
  }