private static void extractAndTransfer(
      Session session, String baseDir, ArchiveInput ai, String fileMode, Set<String> existingDirs)
      throws Throwable {

    ArchiveInput.Entry entry = null;
    try {
      while ((entry = ai.next()) != null) {
        String remotePath = PathUtil.join(baseDir, entry.name());
        if (entry.isDirectory()) {
          session.mkdir(remotePath, true, "0755");
          existingDirs.add(remotePath);
        } else {
          transfer(session, entry.stream(), entry.size(), remotePath, fileMode, existingDirs);
        }
      }
    } finally {
      ai.close();
    }
  }
  private static void transfer(
      final Session session,
      InputStream in,
      long length,
      final String remoteFilePath,
      String fileMode,
      Set<String> existingDirs)
      throws Throwable {

    String remoteDirPath = PathUtil.getParentDirectory(remoteFilePath);
    if (existingDirs == null || !existingDirs.contains(remoteDirPath)) {
      session.mkdir(remoteDirPath, true, "0755");
      if (existingDirs != null) {
        existingDirs.add(remoteDirPath);
      }
    }
    if (length < 0 && in instanceof LongInputStream) {
      length = ((LongInputStream) in).length();
    }
    if (length < 0) {
      File tf = PluginTask.createTemporaryFile();
      OutputStream tfos = new BufferedOutputStream(new FileOutputStream(tf));
      try {
        StreamCopy.copy(in, tfos);
      } finally {
        tfos.close();
        in.close();
      }
      in = PluginTask.deleteOnCloseInputStream(tf);
      length = tf.length();
    }

    OutputStream out = null;
    try {
      out = session.scpPut(remoteFilePath, length, fileMode);
      StreamCopy.copy(in, out);
    } finally {
      if (out != null) {
        out.close();
      }
      in.close();
    }
  }
  @Override
  public void consume(
      java.lang.Object multiCtx,
      java.lang.String path,
      java.util.Map<java.lang.String, java.lang.String> parameters,
      XmlDoc.Element userMeta,
      XmlDoc.Element meta,
      LongInputStream in,
      java.lang.String appMimeType,
      java.lang.String streamMimeType,
      long length)
      throws Throwable {

    Connection conn = multiCtx == null ? null : ((MultiTransferContext) multiCtx).connection;
    Session session = multiCtx == null ? null : ((MultiTransferContext) multiCtx).session;
    Params params = Params.parse(parameters);
    if (multiCtx == null) {
      conn = Ssh.get().getConnection(params.serverDetails());
      session = conn.connect(params.userDetails(), true);
    }

    String assetId = meta != null ? meta.value("@id") : null;
    String ext = meta != null ? meta.value("content/type/@ext") : null;

    try {

      String baseDir = params.directory != null ? params.directory : session.getHome();
      StringBuilder sb = new StringBuilder(baseDir);
      if (!baseDir.endsWith("/")) {
        sb.append("/");
      }
      if (path != null) {
        path = path.replace("\\\\", "/").replace("\\", "/");
        while (path.startsWith("/")) {
          path = path.substring(1);
        }
        sb.append(path);
      }

      Set<String> existingDirs =
          multiCtx == null
              ? Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>())
              : ((MultiTransferContext) multiCtx).existingDirectories;
      if (params.decompress
          && streamMimeType != null
          && ArchiveRegistry.isAnArchive(streamMimeType)) {
        // decompress archive
        if (assetId != null) {
          sb.append("/");
          sb.append("asset_");
          sb.append(assetId);
        }
        if (RemoteArchiveExtractor.canExtract(session, streamMimeType)) {
          sb.append("/");
          sb.append(PathUtil.getRandomFileName(8));
          sb.append(".tmp");
          String remotePath = sb.toString();
          transfer(session, in, length, remotePath, params.fileMode, existingDirs);
          RemoteArchiveExtractor.extract(session, remotePath);
        } else {
          extractAndTransfer(
              session,
              sb.toString(),
              ArchiveRegistry.createInput(in, new NamedMimeType(streamMimeType)),
              params.fileMode,
              existingDirs);
        }
      } else {
        // single file
        if (assetId != null) {
          sb.append("/");
          sb.append("asset_");
          sb.append(assetId);
        }
        if (ext != null) {
          sb.append(".");
          sb.append(ext);
        }
        transfer(session, in, length, sb.toString(), params.fileMode, existingDirs);
      }
    } finally {
      if (multiCtx == null) {
        if (session != null) {
          session.close();
        }
        if (conn != null) {
          conn.disconnect();
        }
      }
    }
  }