@Override
  public void transaction(ConfigSource config, Schema inputSchema, FilterPlugin.Control control) {
    PluginTask task = config.loadConfig(PluginTask.class);

    try {
      task.setJsonTable(buildJsonTable(task, loadJsonFile(task.getJsonFilePath())));
    } catch (IOException e) {
      logger.error(e.getMessage());
      throw new RuntimeException(e);
    }

    Schema outputSchema = buildOutputSchema(task, inputSchema, task.getJsonColumns());

    control.run(task.dump(), outputSchema);
  }
  @Override
  public PageOutput open(
      TaskSource taskSource,
      final Schema inputSchema,
      final Schema outputSchema,
      final PageOutput output) {
    final PluginTask task = taskSource.loadTask(PluginTask.class);

    // create jsonColumns/baseColumn
    final List<Column> outputColumns = outputSchema.getColumns();
    final List<Column> inputColumns = inputSchema.getColumns();

    Map<String, Column> inputColumnMap = Maps.newHashMap();
    final List<Column> jsonColumns = new ArrayList<>();
    for (Column column : outputColumns) {
      if (!inputColumns.contains(column)) {
        jsonColumns.add(column);
      } else {
        inputColumnMap.put(column.getName(), column);
      }
    }

    final Column baseColumn = inputColumnMap.get(task.getBaseColumn().getName());

    // create timestampParserMap
    final HashMap<String, TimestampParser> timestampParserMap = Maps.newHashMap();
    for (ColumnConfig jsonColumnConfig : task.getJsonColumns()) {
      if (Types.TIMESTAMP.equals(jsonColumnConfig.getType())) {
        String format = jsonColumnConfig.getOption().get(String.class, "format");
        DateTimeZone timezone = DateTimeZone.forID(task.getTimeZone());
        TimestampParser parser = new TimestampParser(task.getJRuby(), format, timezone);
        timestampParserMap.put(task.getJoinedColumnsPrefix() + jsonColumnConfig.getName(), parser);
      }
    }

    // get jsonTable
    final HashMap<String, HashMap<String, String>> jsonTable = task.getJsonTable();

    return new LeftOuterJoinJsonTableFilterFilteredPageOutput(
        inputSchema, outputSchema, baseColumn, jsonTable, jsonColumns, timestampParserMap, output);
  }
  private HashMap<String, HashMap<String, String>> buildJsonTable(
      final PluginTask task, List<HashMap<String, String>> jsonData) {
    HashMap<String, HashMap<String, String>> jsonTable = Maps.newHashMap();

    for (HashMap<String, String> json : jsonData) {

      HashMap<String, String> record = Maps.newHashMap();

      for (ColumnConfig columnConfig : task.getJsonColumns()) {
        String columnKey = task.getJoinedColumnsPrefix() + columnConfig.getName();
        String value = json.get(columnConfig.getName());

        record.put(columnKey, value);
      }

      String rowKey = json.get(task.getCounterColumn().getName());
      jsonTable.put(rowKey, record);
    }

    return jsonTable;
  }