/**
   * Creates the serialized value of the object and stores this in ZooKeeper under the path. It
   * updates the lastStatusVersion. It does not set a watcher for the path.
   */
  private void updateCoordinateData() throws CoordinateMissingException, CloudnameException {
    if (!started.get()) {
      throw new IllegalStateException("Not started.");
    }

    if (!zkClient.isConnected()) {
      throw new CloudnameException("No proper connection with zookeeper.");
    }

    synchronized (lastStatusVersionMonitor) {
      try {
        Stat stat =
            zkClient
                .getZookeeper()
                .setData(
                    path,
                    zkCoordinateData.snapshot().serialize().getBytes(Util.CHARSET_NAME),
                    lastStatusVersion);
        LOG.fine("Updated coordinate, latest version is " + stat.getVersion());
        lastStatusVersion = stat.getVersion();
      } catch (KeeperException.NoNodeException e) {
        throw new CoordinateMissingException("Coordinate does not exist " + path);
      } catch (KeeperException e) {
        throw new CloudnameException(
            "ZooKeeper errror in updateCoordinateData: " + e.getMessage(), e);
      } catch (UnsupportedEncodingException e) {
        throw new CloudnameException(e);
      } catch (InterruptedException e) {
        throw new CloudnameException(e);
      } catch (IOException e) {
        throw new CloudnameException(e);
      }
    }
  }
    @Override
    public void run() {
      if (isSynchronizedWithZooKeeper.get() || !zkClient.isConnected() || !started.get()) {

        return;
      }
      if (checkVersion.getAndSet(false)) {
        try {
          synchronized (lastStatusVersionMonitor) {
            final Stat stat = zkClient.getZookeeper().exists(path, null);
            if (stat != null
                && zkClient.getZookeeper().getSessionId() == stat.getEphemeralOwner()) {
              zkClient.getZookeeper().delete(path, lastStatusVersion);
            }
          }
        } catch (InterruptedException e) {
          LOG.info("Interrupted");
          checkVersion.set(true);
        } catch (KeeperException e) {
          LOG.info("exception " + e.getMessage());
          checkVersion.set(true);
        }
      }
      LOG.info(
          "We are out-of-sync, have a zookeeper connection, and are started, trying reclaim: "
              + path
              + this);
      tryClaim();
    }
  /**
   * Handles event from ZooKeeper for this coordinate.
   *
   * @param event
   */
  @Override
  public void process(WatchedEvent event) {
    LOG.info("Got an event from ZooKeeper " + event.toString());
    synchronized (lastStatusVersionMonitor) {
      switch (event.getType()) {
        case None:
          switch (event.getState()) {
            case SyncConnected:
              break;
            case Disconnected:
            case AuthFailed:
            case Expired:
            default:
              // If we lost connection, we don't attempt to register another watcher as
              // this might be blocking forever. Parent will try to reconnect (reclaim)
              // later.
              isSynchronizedWithZooKeeper.set(false);
              sendEventToCoordinateListener(
                  CoordinateListener.Event.NO_CONNECTION_TO_STORAGE, event.toString());

              return;
          }
          return;

        case NodeDeleted:
          // If node is deleted, we have no node to place a new watcher so we stop watching.
          isSynchronizedWithZooKeeper.set(false);
          sendEventToCoordinateListener(CoordinateListener.Event.NOT_OWNER, event.toString());
          return;

        case NodeDataChanged:
          LOG.fine("Node data changed, check versions.");
          boolean verifiedSynchronized = false;
          try {
            final Stat stat = zkClient.getZookeeper().exists(path, this);
            if (stat == null) {
              LOG.info("Could not stat path, setting out of synch, will retry claim");
            } else {
              LOG.fine("Previous version is " + lastStatusVersion + " now is " + stat.getVersion());
              if (stat.getVersion() != lastStatusVersion) {
                LOG.fine("Version mismatch, sending out of sync.");
              } else {
                verifiedSynchronized = true;
              }
            }
          } catch (KeeperException e) {
            LOG.fine(
                "Problems with zookeeper, sending consistencyState out of sync: " + e.getMessage());
          } catch (InterruptedException e) {
            LOG.fine("Got interrupted: " + e.getMessage());
            return;
          } finally {
            isSynchronizedWithZooKeeper.set(verifiedSynchronized);
          }

          if (verifiedSynchronized) {
            sendEventToCoordinateListener(
                CoordinateListener.Event.COORDINATE_OUT_OF_SYNC, event.toString());
          }
          return;

        case NodeChildrenChanged:
        case NodeCreated:
          // This should not happen..
          isSynchronizedWithZooKeeper.set(false);
          sendEventToCoordinateListener(
              CoordinateListener.Event.COORDINATE_OUT_OF_SYNC, event.toString());
          return;
      }
    }
  }