/** * Build a new service discovery with the currently set values. If not set, the builder will be * defaulted with a {@link JsonInstanceSerializer}. * * @return new service discovery */ public ServiceDiscovery<T> build() { if ( serializer == null ) { serializer(new JsonInstanceSerializer<T>(payloadClass)); } return new ServiceDiscoveryImpl<T>(client, basePath, serializer, thisInstance, watchInstances); }
@Override public void start() throws Exception { Preconditions.checkState(state.compareAndSet(State.LATENT, State.STARTED), "Cannot be started more than once"); cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE); for (ChildData childData : cache.getCurrentData()) { addInstance(childData, true); } discovery.cacheOpened(this); }
List<ServiceInstance<T>> queryForInstances(String name, Watcher watcher) throws Exception { ImmutableList.Builder<ServiceInstance<T>> builder = ImmutableList.builder(); String path = pathForName(name); List<String> instanceIds; if ( watcher != null ) { instanceIds = getChildrenWatched(path, watcher, true); } else { try { instanceIds = client.getChildren().forPath(path); } catch ( KeeperException.NoNodeException e ) { instanceIds = Lists.newArrayList(); } } for ( String id : instanceIds ) { ServiceInstance<T> instance = queryForInstance(name, id); if ( instance != null ) { builder.add(instance); } } return builder.build(); }
ServiceCacheImplExt(ServiceDiscoveryImpl<T> discovery, String name, CloseableExecutorService executorService) { super(discovery, name, executorService); nodeCache = new NodeCache(discovery.getClient(), discovery.pathForName(name)); }
/** * 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); } }
/** * Return a service instance POJO * * @param name name of the service * @param id ID of the instance * @return the instance or <code>null</code> if not found * @throws Exception errors */ @Override public ServiceInstance<T> queryForInstance(String name, String id) throws Exception { String path = pathForInstance(name, id); try { byte[] bytes = client.getData().forPath(path); return serializer.deserialize(bytes); } catch ( KeeperException.NoNodeException ignore ) { // ignore } return null; }
@Override public Void apply(ServiceCacheListener listener) { discovery.getClient().getConnectionStateListenable().removeListener(listener); return null; } }
String path = pathForInstance(service.getName(), service.getId()); client.setData().forPath(pathForName(service.getName()), serviceDefinitionSerializer.serialize(service.getPayload())); isDone = true;
/** * Unregister/remove a group instance * * @param service the group * @throws Exception errors */ @Override public void unregisterService(ServiceInstance<T> service) throws Exception { Entry<T> entry = services.remove(service.getId()); internalUnregisterService(entry); }
private void reRegisterServices() throws Exception { for ( final Entry<T> entry : services.values() ) { synchronized(entry) { internalRegisterService(entry.service); } } }
private ServiceInstance<T> addInstance(ChildData childData, boolean onlyIfAbsent) throws Exception { String instanceId = instanceIdFromData(childData); ServiceInstance<T> serviceInstance = discovery.getSerializer().deserialize(childData.getData()); if (onlyIfAbsent) { instances.putIfAbsent(instanceId, serviceInstance); } else { instances.put(instanceId, serviceInstance); } cache.clearDataBytes(childData.getPath(), childData.getStat().getVersion()); return serviceInstance; } }
@Override public void close() throws IOException { Preconditions.checkState(state.compareAndSet(State.STARTED, State.STOPPED), "Already closed or has not been started"); listenerContainer.forEach( new Function<ServiceCacheListener<T>, Void>() { @Override public Void apply(ServiceCacheListener<T> listener) { discovery.getClient().getConnectionStateListenable().removeListener(listener); return null; } } ); listenerContainer.clear(); CloseableUtils.closeQuietly(cache); discovery.cacheClosed(this); }
/** * @param client the client * @param basePath base path to store data * @param serializer serializer for instances (e.g. {@link JsonInstanceSerializer}) * @param serviceDefinitionSerializer serializer for group newestDefinition. * @param thisInstance instance that represents the group 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,ServiceDefinitionSerializer<T> serviceDefinitionSerializer, 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"); this.serviceDefinitionSerializer = Preconditions.checkNotNull(serviceDefinitionSerializer,"serviceDefinitionSerializer cannot be null"); if ( thisInstance != null ) { Entry<T> entry = new Entry<T>(thisInstance); entry.cache = makeNodeCache(thisInstance); services.put(thisInstance.getId(), entry); } }
private List<String> getChildrenWatched(String path, Watcher watcher, boolean recurse) throws Exception { List<String> instanceIds; try { instanceIds = client.getChildren().usingWatcher(watcher).forPath(path); } catch ( KeeperException.NoNodeException e ) { if ( recurse ) { try { client.create().creatingParentContainersIfNeeded().forPath(path); } catch ( KeeperException.NodeExistsException ignore ) { // ignore } instanceIds = getChildrenWatched(path, watcher, false); } else { throw e; } } return instanceIds; }
ServiceCacheImpl(ServiceDiscoveryImpl<T> discovery, String name, CloseableExecutorService executorService) { Preconditions.checkNotNull(discovery, "discovery cannot be null"); Preconditions.checkNotNull(name, "name cannot be null"); Preconditions.checkNotNull(executorService, "executorService cannot be null"); this.discovery = discovery; cache = new PathChildrenCache(discovery.getClient(), discovery.pathForName(name), true, false, executorService); cache.getListenable().addListener(this); }
/** * Return a group instance POJO * * @param name name of the group * @param id ID of the instance * @return the instance or <code>null</code> if not found * @throws Exception errors */ @Override public ServiceInstance<T> queryForInstance(String name, String id) throws Exception { String path = pathForInstance(name, id); try { byte[] bytes = client.getData().forPath(path); return serializer.deserialize(bytes); } catch ( KeeperException.NoNodeException ignore ) { // ignore } return null; }
@Override public Void apply(ServiceCacheListener<T> listener) { discovery.getClient().getConnectionStateListenable().removeListener(listener); return null; } }
/** * Register/re-register/update a group instance * * @param service group 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); } }
/** * 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); }
private void reRegisterServices() throws Exception { for ( final Entry<T> entry : services.values() ) { synchronized(entry) { internalRegisterService(entry.service); } } }