@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); } }
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; }
/** * 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); } }
@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 } } }
/** * 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); }