@Override
  public void getChildren(final String path, final boolean watch, final AsyncCallback.ChildrenCallback cb, final Object ctx)
  {
    if (!SymlinkUtil.containsSymlink(path))
    {
      _zk.getChildren(path, watch, cb, ctx);
    }
    else
    {
      SymlinkChildrenCallback compositeCallback = new SymlinkChildrenCallback(path, _defaultWatcher, cb);
      getChildren0(path, watch ? compositeCallback : null, compositeCallback, ctx);
    }
  }
@Test
  public void testSymlinkWithChildrenWatcher2() throws ExecutionException, InterruptedException
  {
    final CountDownLatch latch1 = new CountDownLatch(1);
    final CountDownLatch latch2 = new CountDownLatch(1);
    final AsyncCallback.ChildrenCallback callback2 = new AsyncCallback.ChildrenCallback()
    {
      @Override
      public void processResult(int rc, String path, Object ctx, List<String> children)
      {
        Assert.assertEquals(path, "/foo/$link");
        Assert.assertEquals(children.size(), 5);
        latch2.countDown();
      }
    };
    Watcher watcher = new Watcher()
    {
      @Override
      public void process(WatchedEvent event)
      {
        Assert.assertEquals(event.getType(), Event.EventType.NodeChildrenChanged);
        _zkClient.getZooKeeper().getChildren(event.getPath(), null, callback2, null);
      }
    };
    AsyncCallback.ChildrenCallback callback = new AsyncCallback.ChildrenCallback()
    {
      @Override
      public void processResult(int rc, String path, Object ctx, List<String> children)
      {
        latch1.countDown();
      }
    };
    // set watcher to /foo/$link
    _zkClient.getZooKeeper().getChildren("/foo/$link", watcher, callback, null);
    latch1.await(30, TimeUnit.SECONDS);
    // update symlink
    _zkClient.setSymlinkData("/foo/$link", "/bar/foo", new FutureCallback<>());
    latch2.await(30, TimeUnit.SECONDS);
    FutureCallback<None> fcb = new FutureCallback<>();
    // restore symlink
    _zkClient.setSymlinkData("/foo/$link", "/foo/bar", fcb);
    fcb.get();
  }