/**
   * 標準入力を読み込んでDFSにファイルを書き出す。 {@link FileList}形式で受け取ったTSV形式のファイルをModelオブジェクトに変換して、テンポラリ入力データとして配置する。
   * 出力先はプロトコルの形式によって異なる。 利用可能なプロトコルは以下のとおり。
   *
   * <ul>
   *   <li>{@link com.asakusafw.bulkloader.transfer.FileProtocol.Kind#CONTENT}
   *   <li>{@link com.asakusafw.bulkloader.transfer.FileProtocol.Kind#CREATE_CACHE}
   *   <li>{@link com.asakusafw.bulkloader.transfer.FileProtocol.Kind#UPDATE_CACHE}
   * </ul>
   *
   * @param bean パラメータを保持するBean
   * @param user OSのユーザー名
   * @return 出力結果(true:正常終了、false:異常終了)
   */
  public boolean importFile(ImportBean bean, String user) {
    // 標準入力を取得
    FileList.Reader reader;
    try {
      reader = FileList.createReader(getInputStream());
    } catch (IOException e) {
      LOG.error(e, "TG-EXTRACTOR-02001", "標準入力からFileListの取得に失敗");
      return false;
    }
    try {
      // FileListの終端まで繰り返す
      List<Future<?>> running = new ArrayList<>();
      while (reader.next()) {
        FileProtocol protocol = reader.getCurrentProtocol();
        try (InputStream content = reader.openContent()) {
          switch (protocol.getKind()) {
            case CONTENT:
              importContent(protocol, content, bean, user);
              break;

            case CREATE_CACHE:
            case UPDATE_CACHE:
              long recordCount = putCachePatch(protocol, content, bean, user);
              Callable<?> builder = createCacheBuilder(protocol, bean, user, recordCount);
              if (builder != null) {
                LOG.debugMessage(
                    "Submitting cache builder: {0} {1}",
                    protocol.getKind(), protocol.getInfo().getTableName());
                running.add(executor.submit(builder));
              }
              break;

            default:
              throw new AssertionError(protocol.getKind());
          }
        }
      }

      waitForCompleteTasks(bean, running);
      // 正常終了
      return true;

    } catch (BulkLoaderSystemException e) {
      LOG.log(e);
    } catch (IOException e) {
      // FileListの展開に失敗
      LOG.error(e, "TG-EXTRACTOR-02001", "標準入力からFileListの取得に失敗");
    } finally {
      try {
        reader.close();
      } catch (IOException e) {
        // ここで例外が発生した場合は握りつぶす
        e.printStackTrace();
      }
    }
    return false;
  }
  private void waitForCompleteTasks(ImportBean bean, List<Future<?>> running)
      throws BulkLoaderSystemException {
    assert bean != null;
    assert running != null;
    if (running.isEmpty()) {
      return;
    }
    LOG.info(
        "TG-EXTRACTOR-12006",
        bean.getTargetName(),
        bean.getBatchId(),
        bean.getJobflowId(),
        bean.getExecutionId());

    boolean sawError = false;
    LinkedList<Future<?>> rest = new LinkedList<>(running);
    while (rest.isEmpty() == false) {
      Future<?> future = rest.removeFirst();
      try {
        future.get(1, TimeUnit.SECONDS);
      } catch (TimeoutException e) {
        // continue...
        rest.addLast(future);
      } catch (InterruptedException e) {
        cancel(rest);
        throw new BulkLoaderSystemException(
            e,
            getClass(),
            "TG-EXTRACTOR-12007",
            bean.getTargetName(),
            bean.getBatchId(),
            bean.getJobflowId(),
            bean.getExecutionId());
      } catch (ExecutionException e) {
        cancel(rest);
        Throwable cause = e.getCause();
        if (cause instanceof RuntimeException) {
          throw (RuntimeException) cause;
        } else if (cause instanceof Error) {
          throw (Error) cause;
        } else if (cause instanceof BulkLoaderSystemException) {
          LOG.log((BulkLoaderSystemException) cause);
          sawError = true;
        } else {
          LOG.error(
              e,
              "TG-EXTRACTOR-12008",
              bean.getTargetName(),
              bean.getBatchId(),
              bean.getJobflowId(),
              bean.getExecutionId());
          sawError = true;
        }
      }
    }
    if (sawError) {
      throw new BulkLoaderSystemException(
          getClass(),
          "TG-EXTRACTOR-12008",
          bean.getTargetName(),
          bean.getBatchId(),
          bean.getJobflowId(),
          bean.getExecutionId());
    } else {
      LOG.info(
          "TG-EXTRACTOR-12009",
          bean.getTargetName(),
          bean.getBatchId(),
          bean.getJobflowId(),
          bean.getExecutionId());
    }
  }