public double getProgress() {
    int totalContentLength = 0;
    int totalBytesRead = 0;

    for (RetrievalTask task : this.activeTasks) {
      if (task.isDone()) continue;

      Retriever retriever = task.getRetriever();
      try {
        double tcl = retriever.getContentLength();
        if (tcl > 0) {
          totalContentLength += tcl;
          totalBytesRead += retriever.getContentLengthRead();
        }
      } catch (Exception e) {
        Logging.logger()
            .log(
                Level.FINE,
                Logging.getMessage(
                    "BasicRetrievalService.ExceptionRetrievingContentSizes",
                    retriever.getName() != null ? retriever.getName() : ""),
                e);
      }
    }

    for (Runnable runnable : this.executor.getQueue()) {
      RetrievalTask task = (RetrievalTask) runnable;

      Retriever retriever = task.getRetriever();
      try {
        double tcl = retriever.getContentLength();
        if (tcl > 0) {
          totalContentLength += tcl;
          totalBytesRead += retriever.getContentLengthRead();
        }
      } catch (Exception e) {
        String message =
            Logging.getMessage("BasicRetrievalService.ExceptionRetrievingContentSizes")
                + (retriever.getName() != null ? retriever.getName() : "");
        Logging.logger().log(Level.FINE, message, e);
      }
    }

    // Compute an aggregated progress notification.

    double progress;

    if (totalContentLength < 1) progress = 0;
    else progress = Math.min(100.0, 100.0 * totalBytesRead / totalContentLength);

    return progress;
  }
    public ByteBuffer run(Retriever retriever) {
      if (!retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL)) return null;

      HTTPRetriever htr = (HTTPRetriever) retriever;
      if (htr.getResponseCode() == HttpURLConnection.HTTP_NO_CONTENT) {
        // Mark tile as missing to avoid excessive attempts
        MercatorTiledImageLayer.this.levels.markResourceAbsent(tile);
        return null;
      }

      if (htr.getResponseCode() != HttpURLConnection.HTTP_OK) return null;

      URLRetriever r = (URLRetriever) retriever;
      ByteBuffer buffer = r.getBuffer();

      String suffix = WWIO.makeSuffixForMimeType(htr.getContentType());
      if (suffix == null) {
        return null; // TODO: log error
      }

      String path = tile.getPath().substring(0, tile.getPath().lastIndexOf("."));
      path += suffix;

      final File outFile = WorldWind.getDataFileStore().newFile(path);
      if (outFile == null) return null;

      try {
        WWIO.saveBuffer(buffer, outFile);
        return buffer;
      } catch (IOException e) {
        e.printStackTrace(); // TODO: log error
        return null;
      }
    }
  private void downloadImage(final MercatorTextureTile tile, String mimeType) throws Exception {
    //        System.out.println(tile.getPath());
    final URL resourceURL = tile.getResourceURL(mimeType);
    Retriever retriever;

    String protocol = resourceURL.getProtocol();

    if ("http".equalsIgnoreCase(protocol)) {
      retriever = new HTTPRetriever(resourceURL, new HttpRetrievalPostProcessor(tile));
    } else {
      String message =
          Logging.getMessage("layers.TextureLayer.UnknownRetrievalProtocol", resourceURL);
      throw new RuntimeException(message);
    }

    retriever.setConnectTimeout(10000);
    retriever.setReadTimeout(20000);
    retriever.call();
  }
  protected void downloadTile(final Tile tile, DownloadPostProcessor postProcessor) {
    if (!this.isNetworkRetrievalEnabled()) return;

    if (!WorldWind.getRetrievalService().isAvailable()) return;

    java.net.URL url;
    try {
      url = tile.getRequestURL();
      if (WorldWind.getNetworkStatus().isHostUnavailable(url)) return;
    } catch (java.net.MalformedURLException e) {
      Logging.logger()
          .log(
              java.util.logging.Level.SEVERE,
              Logging.getMessage("layers.PlaceNameLayer.ExceptionCreatingUrl", tile),
              e);
      return;
    }

    Retriever retriever;

    if ("http".equalsIgnoreCase(url.getProtocol()) || "https".equalsIgnoreCase(url.getProtocol())) {
      if (postProcessor == null) postProcessor = new DownloadPostProcessor(this, tile);
      retriever = new HTTPRetriever(url, postProcessor);
    } else {
      Logging.logger()
          .severe(
              Logging.getMessage("layers.PlaceNameLayer.UnknownRetrievalProtocol", url.toString()));
      return;
    }

    // Apply any overridden timeouts.
    Integer cto = AVListImpl.getIntegerValue(this, AVKey.URL_CONNECT_TIMEOUT);
    if (cto != null && cto > 0) retriever.setConnectTimeout(cto);
    Integer cro = AVListImpl.getIntegerValue(this, AVKey.URL_READ_TIMEOUT);
    if (cro != null && cro > 0) retriever.setReadTimeout(cro);
    Integer srl = AVListImpl.getIntegerValue(this, AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT);
    if (srl != null && srl > 0) retriever.setStaleRequestLimit(srl);

    WorldWind.getRetrievalService().runRetriever(retriever, tile.getPriority());
  }
  /**
   * @param retriever the retriever to run
   * @param priority the secondary priority of the retriever, or negative if it is to be the primary
   *     priority
   * @return a future object that can be used to query the request status of cancel the request.
   * @throws IllegalArgumentException if <code>retriever</code> is null or has no name
   */
  @Override
  public synchronized RetrievalFuture runRetriever(Retriever retriever, double priority) {
    if (retriever == null) {
      String message = Logging.getMessage("nullValue.RetrieverIsNull");
      Logging.logger().fine(message);
      throw new IllegalArgumentException(message);
    }

    if (retriever.getName() == null) {
      String message = Logging.getMessage("nullValue.RetrieverNameIsNull");
      Logging.logger().fine(message);
      throw new IllegalArgumentException(message);
    }

    RetrievalTask task = new RetrievalTask(retriever, priority);
    retriever.setSubmitTime(System.currentTimeMillis());

    // Do not queue duplicates.
    if (this.activeTasks.contains(task) || this.executor.getQueue().contains(task)) return null;

    this.executor.execute(task);

    return task;
  }
  /**
   * @param retriever the retriever to run
   * @return a future object that can be used to query the request status of cancel the request.
   * @throws IllegalArgumentException if <code>retrieer</code> is null or has no name
   */
  @Override
  public RetrievalFuture runRetriever(Retriever retriever) {
    if (retriever == null) {
      String msg = Logging.getMessage("nullValue.RetrieverIsNull");
      Logging.logger().fine(msg);
      throw new IllegalArgumentException(msg);
    }
    if (retriever.getName() == null) {
      String message = Logging.getMessage("nullValue.RetrieverNameIsNull");
      Logging.logger().fine(message);
      throw new IllegalArgumentException(message);
    }

    // Add with secondary priority that removes most recently added requests first.
    return this.runRetriever(retriever, Long.MAX_VALUE - System.currentTimeMillis());
  }