public final Runnable watch(final GroupChangeListener groupChangeListener)
      throws WatchException, InterruptedException {
    Objects.requireNonNull(groupChangeListener);

    try {
      ensurePersistentGroupPath();
    } catch (JoinException e) {
      throw new WatchException("Failed to create group path: " + path, e);
    }

    final GroupMonitor groupMonitor = new GroupMonitor(groupChangeListener);
    backoffHelper.doUntilSuccess(new ExceptionalSupplier<Boolean, WatchException>() {
      @Override public Boolean get() throws WatchException {
        try {
          groupMonitor.watchGroup();
          return true;
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
          throw new WatchException("Interrupted trying to watch group at path: " + path, e);
        } catch (ZooKeeperConnectionException e) {
          LOG.log(Level.WARNING, "Temporary error trying to watch group at path: " + path, e);
          return null;
        } catch (KeeperException e) {
          if (zkClient.shouldRetry(e)) {
            LOG.log(Level.WARNING, "Temporary error trying to watch group at path: " + path, e);
            return null;
          } else {
            throw new WatchException("Problem trying to watch group at path: " + path, e);
          }
        }
      }
    });
    return new Runnable() {
      @Override public void run() {
        groupMonitor.stopWatching();
      }
    };
  }
public final Runnable watch ( final GroupChangeListener groupChangeListener ) throws WatchException , InterruptedException { Objects . requireNonNull ( groupChangeListener ) ; try { ensurePersistentGroupPath ( ) ; } catch ( JoinException e ) { throw new WatchException ( "Failed to create group path: " + path , e ) ; } final GroupMonitor groupMonitor = new GroupMonitor ( groupChangeListener ) ; backoffHelper . doUntilSuccess ( new ExceptionalSupplier < Boolean , WatchException > ( ) { @ Override public Boolean get ( ) throws WatchException { try { groupMonitor . watchGroup ( ) ; return true ; } catch ( InterruptedException e ) { Thread . currentThread ( ) . interrupt ( ) ; throw new WatchException ( "Interrupted trying to watch group at path: " + path , e ) ; } catch ( ZooKeeperConnectionException e ) { LOG . log ( Level . WARNING , "Temporary error trying to watch group at path: " + path , e ) ; return null ; } catch ( KeeperException e ) { if ( zkClient . shouldRetry ( e ) ) { LOG . log ( Level . WARNING , "Temporary error trying to watch group at path: " + path , e ) ; return null ; } else { throw new WatchException ( "Problem trying to watch group at path: " + path , e ) ; } } } } ) ; return new Runnable ( ) { @ Override public void run ( ) { groupMonitor . stopWatching ( ) ; } } ; }
Watches this group for the lifetime of this jvm process.  This method will block until the
current group members are available, notify the {@code groupChangeListener} and then return.
All further changes to the group membership will cause notifications on a background thread.

@param groupChangeListener the listener to notify of group membership change events
@return A command which, when executed, will stop watching the group.
@throws WatchException if there is a problem generating the 1st group membership list
@throws InterruptedException if interrupted waiting to gather the 1st group membership list