/** Parse a row event. */
  private void parseRowEvent(OneRowChange oneRowChange, boolean isKeySpec, int cols)
      throws SQLException {

    ArrayList<ColumnSpec> specs =
        (isKeySpec ? oneRowChange.getKeySpec() : oneRowChange.getColumnSpec());
    if (specs.isEmpty()) {
      if (logger.isDebugEnabled()) logger.debug("Adding column or key specs (not defined so far)");

      for (int i = 1; i <= cols; i++) {
        ColumnSpec colSpec = oneRowChange.new ColumnSpec();
        colSpec.setIndex(i);
        colSpec.setType(resultset.getMetaData().getColumnType(i));
        colSpec.setName(resultset.getMetaData().getColumnLabel(i));
        specs.add(colSpec);
      }
    }
    ArrayList<ArrayList<OneRowChange.ColumnVal>> rows =
        (isKeySpec ? oneRowChange.getKeyValues() : oneRowChange.getColumnValues());
    ArrayList<OneRowChange.ColumnVal> columns = new ArrayList<ColumnVal>();
    rows.add(columns);

    for (int i = 1; i <= cols; i++) {
      ColumnVal value = oneRowChange.new ColumnVal();
      value.setValue((Serializable) resultset.getObject(i));
      if (resultset.wasNull()) value.setValueNull();
      columns.add(value);
    }
  }
 // Generate values.
 private ArrayList<ArrayList<ColumnVal>> generateValues(
     OneRowChange oneRowChange, int v1, String v2) {
   ArrayList<ArrayList<ColumnVal>> list = new ArrayList<ArrayList<ColumnVal>>(1);
   ArrayList<ColumnVal> values = new ArrayList<ColumnVal>(2);
   ColumnVal cv1 = oneRowChange.new ColumnVal();
   cv1.setValue(new Integer(v1));
   values.add(cv1);
   ColumnVal cv2 = oneRowChange.new ColumnVal();
   cv2.setValue(v2);
   values.add(cv2);
   list.add(values);
   return list;
 }
  /**
   * {@inheritDoc}
   *
   * @see
   *     com.continuent.tungsten.replicator.filter.Filter#filter(com.continuent.tungsten.replicator.event.ReplDBMSEvent)
   */
  public ReplDBMSEvent filter(ReplDBMSEvent event) throws ReplicatorException {
    ArrayList<DBMSData> data = event.getData();
    for (Iterator<DBMSData> iterator = data.iterator(); iterator.hasNext(); ) {
      DBMSData dataElem = iterator.next();
      if (dataElem instanceof RowChangeData) {
        RowChangeData rdata = (RowChangeData) dataElem;
        for (Iterator<OneRowChange> iterator2 = rdata.getRowChanges().iterator();
            iterator2.hasNext(); ) {
          OneRowChange orc = iterator2.next();

          // Don't analyze tables from Tungsten schema.
          if (orc.getSchemaName().compareToIgnoreCase(tungstenSchema) == 0) {
            if (logger.isDebugEnabled()) logger.debug("Ignoring " + tungstenSchema + " schema");
            continue;
          }

          // Loop through defined transformations (usually one).
          Iterator<String> it = definitions.keySet().iterator();
          while (it.hasNext()) {
            String transformation = it.next();

            JSONArray array = definitions.get(transformation);

            // Not using any hash, because simple loop should be
            // fast enough for a few expected entries.
            for (Object o : array) {
              JSONObject jo = (JSONObject) o;
              String defSchema = (String) jo.get("schema");
              String defTable = (String) jo.get("table");

              // Found a filter request for this schema & table?
              if ((defSchema.equals("*") || defSchema.equals(orc.getSchemaName()))
                  && (defTable.equals("*") || defTable.equals(orc.getTableName()))) {
                // Defined columns to filter.
                JSONArray defColumns = (JSONArray) jo.get("columns");

                // Filter column values.
                ArrayList<ColumnSpec> colSpecs = orc.getColumnSpec();
                ArrayList<ArrayList<OneRowChange.ColumnVal>> colValues = orc.getColumnValues();
                for (int c = 0; c < colSpecs.size(); c++) {
                  ColumnSpec colSpec = colSpecs.get(c);
                  if (colSpec.getName() != null) {
                    // Have this column in definitions?
                    if (defColumns.contains(colSpec.getName())) {
                      // Iterate through all rows in the
                      // column.
                      for (int row = 0; row < colValues.size(); row++) {
                        ColumnVal colValue = colValues.get(row).get(c);
                        if (colValue.getValue() != null) {
                          if (logger.isDebugEnabled())
                            logger.debug("Sending value: " + colValue.getValue());

                          // Send to server.
                          Object newValue =
                              sendToFilter(
                                  transformation,
                                  event.getSeqno(),
                                  row,
                                  orc.getSchemaName(),
                                  orc.getTableName(),
                                  colSpec.getName(),
                                  colValue.getValue());
                          colValue.setValue((Serializable) newValue);

                          if (logger.isDebugEnabled()) logger.debug("Received value: " + newValue);
                        }
                      }
                    }
                  } else {
                    if (logger.isDebugEnabled()) {
                      logger.debug(
                          "Expected to filter column, but column name is undefined: "
                              + orc.getSchemaName()
                              + "."
                              + orc.getTableName()
                              + "["
                              + colSpec.getIndex()
                              + "]");
                    }
                  }
                }

                // Filter key values.
                ArrayList<ColumnSpec> keySpecs = orc.getKeySpec();
                ArrayList<ArrayList<OneRowChange.ColumnVal>> keyValues = orc.getKeyValues();
                for (int k = 0; k < keySpecs.size(); k++) {
                  ColumnSpec keySpec = keySpecs.get(k);
                  if (keySpec.getName() != null) {
                    if (defColumns.contains(keySpec.getName())) {
                      // Iterate through all rows in the
                      // key.
                      for (int row = 0; row < keyValues.size(); row++) {
                        ColumnVal keyValue = keyValues.get(row).get(k);
                        if (keyValue.getValue() != null) {
                          if (logger.isDebugEnabled())
                            logger.debug("Sending value: " + keyValue.getValue());

                          // Send to server.
                          Object newValue =
                              sendToFilter(
                                  transformation,
                                  event.getSeqno(),
                                  row,
                                  orc.getSchemaName(),
                                  orc.getTableName(),
                                  keySpec.getName(),
                                  keyValue.getValue());
                          keyValue.setValue((Serializable) newValue);

                          if (logger.isDebugEnabled()) logger.debug("Received value: " + newValue);
                        }
                      }
                    }
                  } else {
                    if (logger.isDebugEnabled()) {
                      logger.debug(
                          "Expected to filter key, but column name is undefined: "
                              + orc.getSchemaName()
                              + "."
                              + orc.getTableName()
                              + "["
                              + keySpec.getIndex()
                              + "]");
                    }
                  }
                }
              }
            }
          }
        }
      } else if (dataElem instanceof StatementData) {
        // Not supported.
      }
    }
    return event;
  }