private <C extends Command<R>, R extends Serializable> void registerExecutor(
      final NodeContext nodeContext, final CommandExecutor<C, R> executor, ZNode node) {
    final ZNode executorNode =
        node.createChild(znode().withPath(nodeNameOf(executor.getQualifier())));
    final ZNode queueNode = executorNode.createChild(znode().withPath("queue"));
    executorNode.createChild(znode().withPath("result"));

    log.debug("Created znodes for executor {}", executorNode.getPath());

    queueNode.addChildrenWatcher(
        new Watcher() {
          @Override
          public void process(WatchedEvent event) {
            if (event.getType() != Event.EventType.NodeChildrenChanged) {
              return;
            }

            synchronized (lock) {
              if (log.isDebugEnabled()) {
                log.debug(
                    "Children changed {} event type {}", queueNode.getPath(), event.getType());
              }

              List<QueueEntry<C, R>> entries = getEntries(queueNode, this);

              for (final QueueEntry<C, R> entry : entries) {
                Runnable run =
                    new Runnable() {

                      @Override
                      public void run() {
                        executeCommand(executor, executorNode, entry, nodeContext);
                      }
                    };

                ZookeeperCoordinator.this.executor.execute(run);
              }
            }
          }
        });
  }
  private static <C extends Command<R>, R extends Serializable> void executeCommand(
      CommandExecutor<C, R> executor,
      ZNode executorNode,
      final QueueEntry<C, R> entry,
      final NodeContext nodeContext) {
    String relativePath = entry.getResultPath().substring(executorNode.getPath().length() + 1);
    final ZNode output = executorNode.child(relativePath);
    final NodeCommandExecutionListener<C> listener = entry.getListener();

    try {
      C command = entry.getCommand();
      listener.onCommandExecutionStarted(command, nodeContext);
      R result = executor.execute(command, nodeContext);
      log.debug("Command {} executed", command);
      listener.onCommandExecuted(command);
      output.setObject(CommandExecutionResult.success(result));
    } catch (Throwable throwable) {
      // todo add fail event
      log.error("error during task execution", throwable);
      output.setObject(CommandExecutionResult.fail(throwable));
    }
  }