@Override
  public void getData(final String path, final boolean watch, final AsyncCallback.DataCallback cb, final Object ctx)
  {
    if (!SymlinkUtil.containsSymlink(path))
    {
      _zk.getData(path, watch, cb, ctx);
    }
    else
    {
      SymlinkDataCallback compositeCallback = new SymlinkDataCallback(path, _defaultWatcher, cb);
      getData0(path, watch ? compositeCallback : null, compositeCallback, ctx);
    }
  }
@Test
  public void testSymlinkGetData() throws InterruptedException
  {
    final CountDownLatch latch = new CountDownLatch(1);
    AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback()
    {
      @Override
      public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat)
      {
        String value = null;
        try
        {
          value = new String(data, "UTF-8");
        }
        catch (UnsupportedEncodingException e)
        {
          Assert.fail(e.getMessage());
        }
        finally
        {
          KeeperException.Code result = KeeperException.Code.get(rc);
          Assert.assertEquals(result, KeeperException.Code.OK);
          Assert.assertEquals(value, (String)ctx);
          Assert.assertNotNull(stat);
          latch.countDown();
        }
      }
    };
    // symlink: /foo/$link/1 -> /foo/bar/1
    _zkClient.getZooKeeper().getData("/foo/$link/1", null, callback, "1");
    latch.await(30, TimeUnit.SECONDS);
  }