private NodeCache makeNodeCache(final ServiceInstance<T> instance) {
    if (!watchInstances) {
      return null;
    }

    final NodeCache nodeCache =
        new NodeCache(client, pathForInstance(instance.getName(), instance.getId()));
    try {
      nodeCache.start(true);
    } catch (Exception e) {
      log.error("Could not start node cache for: " + instance, e);
    }
    NodeCacheListener listener =
        new NodeCacheListener() {
          @Override
          public void nodeChanged() throws Exception {
            if (nodeCache.getCurrentData() != null) {
              ServiceInstance<T> newInstance =
                  serializer.deserialize(nodeCache.getCurrentData().getData());
              Entry<T> entry = services.get(newInstance.getId());
              if (entry != null) {
                synchronized (entry) {
                  entry.service = newInstance;
                }
              }
            } else {
              log.warn("Instance data has been deleted for: " + instance);
            }
          }
        };
    nodeCache.getListenable().addListener(listener);
    return nodeCache;
  }
 @Override
 public void updateService(final ServiceInstance<T> service) throws Exception {
   Entry<T> entry = services.get(service.getId());
   if (entry == null) {
     throw new Exception("Service not registered: " + service);
   }
   synchronized (entry) {
     entry.service = service;
     byte[] bytes = serializer.serialize(service);
     String path = pathForInstance(service.getName(), service.getId());
     client.setData().forPath(path, bytes);
   }
 }
  @VisibleForTesting
  protected void internalRegisterService(ServiceInstance<T> service) throws Exception {
    byte[] bytes = serializer.serialize(service);
    String path = pathForInstance(service.getName(), service.getId());

    final int MAX_TRIES = 2;
    boolean isDone = false;
    for (int i = 0; !isDone && (i < MAX_TRIES); ++i) {
      try {
        CreateMode mode =
            (service.getServiceType() == ServiceType.DYNAMIC)
                ? CreateMode.EPHEMERAL
                : CreateMode.PERSISTENT;
        client.create().creatingParentsIfNeeded().withMode(mode).forPath(path, bytes);
        isDone = true;
      } catch (KeeperException.NodeExistsException e) {
        client.delete().forPath(path); // must delete then re-create so that watchers fire
      }
    }
  }
 /**
  * Register/re-register/update a service instance
  *
  * @param service service to add
  * @throws Exception errors
  */
 @Override
 public void registerService(ServiceInstance<T> service) throws Exception {
   Entry<T> newEntry = new Entry<T>(service);
   Entry<T> oldEntry = services.putIfAbsent(service.getId(), newEntry);
   Entry<T> useEntry = (oldEntry != null) ? oldEntry : newEntry;
   synchronized (useEntry) {
     if (useEntry == newEntry) // i.e. is new
     {
       useEntry.cache = makeNodeCache(service);
     }
     internalRegisterService(service);
   }
 }
 /**
  * @param client the client
  * @param basePath base path to store data
  * @param serializer serializer for instances (e.g. {@link JsonInstanceSerializer})
  * @param thisInstance instance that represents the service that is running. The instance will get
  *     auto-registered
  * @param watchInstances if true, watches for changes to locally registered instances
  */
 public ServiceDiscoveryImpl(
     CuratorFramework client,
     String basePath,
     InstanceSerializer<T> serializer,
     ServiceInstance<T> thisInstance,
     boolean watchInstances) {
   this.watchInstances = watchInstances;
   this.client = Preconditions.checkNotNull(client, "client cannot be null");
   this.basePath = Preconditions.checkNotNull(basePath, "basePath cannot be null");
   this.serializer = Preconditions.checkNotNull(serializer, "serializer cannot be null");
   if (thisInstance != null) {
     Entry<T> entry = new Entry<T>(thisInstance);
     entry.cache = makeNodeCache(thisInstance);
     services.put(thisInstance.getId(), entry);
   }
 }
 public ExampleServer(CuratorFramework client, String path, String serviceName, String description)
     throws Exception {
   // in a real application, you'd have a convention of some kind for the
   // URI layout
   UriSpec uriSpec = new UriSpec("{scheme}://foo.com:{port}");
   thisInstance =
       ServiceInstance.<InstanceDetails>builder()
           .name(serviceName)
           .payload(new InstanceDetails(description))
           .port((int) (65535 * Math.random())) // in a real application you'd use a common port
           .uriSpec(uriSpec)
           .build();
   // if you mark your payload class with @JsonRootName the provided
   // JsonInstanceSerializer will work
   JsonInstanceSerializer<InstanceDetails> serializer =
       new JsonInstanceSerializer<InstanceDetails>(InstanceDetails.class);
   serviceDiscovery =
       ServiceDiscoveryBuilder.builder(InstanceDetails.class)
           .client(client)
           .basePath(path)
           .serializer(serializer)
           .thisInstance(thisInstance)
           .build();
 }
 /**
  * Unregister/remove a service instance
  *
  * @param service the service
  * @throws Exception errors
  */
 @Override
 public void unregisterService(ServiceInstance<T> service) throws Exception {
   Entry<T> entry = services.remove(service.getId());
   internalUnregisterService(entry);
 }