@Test(timeout = 300000)
  public void testReplicationWithCellTags() throws Exception {
    LOG.info("testSimplePutDelete");
    Put put = new Put(ROW);
    put.setAttribute("visibility", Bytes.toBytes("myTag3"));
    put.add(FAMILY, ROW, ROW);

    htable1 = utility1.getConnection().getTable(TABLE_NAME);
    htable1.put(put);

    Get get = new Get(ROW);
    try {
      for (int i = 0; i < NB_RETRIES; i++) {
        if (i == NB_RETRIES - 1) {
          fail("Waited too much time for put replication");
        }
        Result res = htable2.get(get);
        if (res.size() == 0) {
          LOG.info("Row not available");
          Thread.sleep(SLEEP_TIME);
        } else {
          assertArrayEquals(res.value(), ROW);
          assertEquals(1, TestCoprocessorForTagsAtSink.tags.size());
          Tag tag = TestCoprocessorForTagsAtSink.tags.get(0);
          assertEquals(TAG_TYPE, tag.getType());
          break;
        }
      }
    } finally {
      TestCoprocessorForTagsAtSink.tags = null;
    }
  }
  private void putAndWait(byte[] row, byte[] fam, HTable source, HTable... targets)
      throws Exception {
    Put put = new Put(row);
    put.add(fam, row, row);
    source.put(put);

    Get get = new Get(row);
    for (int i = 0; i < NB_RETRIES; i++) {
      if (i == NB_RETRIES - 1) {
        fail("Waited too much time for put replication");
      }
      boolean replicatedToAll = true;
      for (HTable target : targets) {
        Result res = target.get(get);
        if (res.size() == 0) {
          LOG.info("Row not available");
          replicatedToAll = false;
          break;
        } else {
          assertArrayEquals(res.value(), row);
        }
      }
      if (replicatedToAll) {
        break;
      } else {
        Thread.sleep(SLEEP_TIME);
      }
    }
  }
 private void wait(byte[] row, HTable target, boolean isDeleted) throws Exception {
   Get get = new Get(row);
   for (int i = 0; i < NB_RETRIES; i++) {
     if (i == NB_RETRIES - 1) {
       fail(
           "Waited too much time for replication. Row:"
               + Bytes.toString(row)
               + ". IsDeleteReplication:"
               + isDeleted);
     }
     Result res = target.get(get);
     boolean sleep = isDeleted ? res.size() > 0 : res.size() == 0;
     if (sleep) {
       LOG.info(
           "Waiting for more time for replication. Row:"
               + Bytes.toString(row)
               + ". IsDeleteReplication:"
               + isDeleted);
       Thread.sleep(SLEEP_TIME);
     } else {
       if (!isDeleted) {
         assertArrayEquals(res.value(), row);
       }
       LOG.info("Obtained row:" + Bytes.toString(row) + ". IsDeleteReplication:" + isDeleted);
       break;
     }
   }
 }
  public static void readDocumentMetadataHBase(
      String remoteHost, int remotePort, String remoteTable) throws IOException {

    RemoteHTable table =
        new RemoteHTable(new Client(new Cluster().add(remoteHost, remotePort)), remoteTable);

    Person john =
        Person.newBuilder()
            .setId(1234)
            .setName("John Doe")
            .setEmail("*****@*****.**")
            .addPhone(
                Person.PhoneNumber.newBuilder()
                    .setNumber("555-4321")
                    .setType(Person.PhoneType.HOME))
            .build();

    System.out.println("============ inside code ============");
    byte[] value = john.toByteArray();
    Person p = Person.parseFrom(value);
    System.out.println(p);
    System.out.println("============ from hbase ============");
    Scan scan = new Scan();
    ResultScanner scanner = table.getScanner(scan);

    try {
      for (Result scannerResult : scanner) {
        if (scannerResult.getValue(Bytes.toBytes("data"), Bytes.toBytes("3")) != null) {
          System.out.println("Scan: " + Person.parseFrom(scannerResult.value()));
          System.out.println(
              "!!!! Is it equals?: " + john.equals(Person.parseFrom(scannerResult.value())));
        } else {
          System.out.println("Scan: " + Bytes.toString(scannerResult.value()));
        }
      }
    } finally {
      scanner.close();
    }
  }