/**
   * Use the async http client library to download artifacts and metadata.
   *
   * @param artifactDownloads The artifact downloads to perform, may be {@code null} or empty.
   * @param metadataDownloads The metadata downloads to perform, may be {@code null} or empty.
   */
  public void get(
      Collection<? extends ArtifactDownload> artifactDownloads,
      Collection<? extends MetadataDownload> metadataDownloads) {
    if (closed.get()) {
      throw new IllegalStateException("connector closed");
    }

    artifactDownloads = safe(artifactDownloads);
    metadataDownloads = safe(metadataDownloads);

    CountDownLatch latch = new CountDownLatch(artifactDownloads.size() + metadataDownloads.size());

    Collection<GetTask<?>> tasks = new ArrayList<GetTask<?>>();

    for (MetadataDownload download : metadataDownloads) {
      String resource = layout.getPath(download.getMetadata()).getPath();
      GetTask<?> task =
          new GetTask<MetadataTransfer>(
              resource,
              download.getFile(),
              download.getChecksumPolicy(),
              latch,
              download,
              METADATA,
              false);
      tasks.add(task);
      task.run();
    }

    for (ArtifactDownload download : artifactDownloads) {
      String resource = layout.getPath(download.getArtifact()).getPath();
      GetTask<?> task =
          new GetTask<ArtifactTransfer>(
              resource,
              download.isExistenceCheck() ? null : download.getFile(),
              download.getChecksumPolicy(),
              latch,
              download,
              ARTIFACT,
              true);
      tasks.add(task);
      task.run();
    }

    try {
      latch.await();

      for (GetTask<?> task : tasks) {
        task.flush();
      }
    } catch (InterruptedException e) {
      for (GetTask<?> task : tasks) {
        task.flush(e);
      }
    }
  }
  /**
   * Use the async http client library to upload artifacts and metadata.
   *
   * @param artifactUploads The artifact uploads to perform, may be {@code null} or empty.
   * @param metadataUploads The metadata uploads to perform, may be {@code null} or empty.
   */
  public void put(
      Collection<? extends ArtifactUpload> artifactUploads,
      Collection<? extends MetadataUpload> metadataUploads) {
    if (closed.get()) {
      throw new IllegalStateException("connector closed");
    }

    artifactUploads = safe(artifactUploads);
    metadataUploads = safe(metadataUploads);

    CountDownLatch latch = new CountDownLatch(artifactUploads.size() + metadataUploads.size());

    Collection<PutTask<?>> tasks = new ArrayList<PutTask<?>>();

    for (ArtifactUpload upload : artifactUploads) {
      String path = layout.getPath(upload.getArtifact()).getPath();

      PutTask<?> task =
          new PutTask<ArtifactTransfer>(path, upload.getFile(), latch, upload, ARTIFACT);
      tasks.add(task);
      task.run();
    }

    for (MetadataUpload upload : metadataUploads) {
      String path = layout.getPath(upload.getMetadata()).getPath();

      PutTask<?> task =
          new PutTask<MetadataTransfer>(path, upload.getFile(), latch, upload, METADATA);
      tasks.add(task);
      task.run();
    }

    try {
      latch.await();

      for (PutTask<?> task : tasks) {
        task.flush();
      }
    } catch (InterruptedException e) {
      for (PutTask<?> task : tasks) {
        task.flush(e);
      }
    }
  }