/*
 * Copyright (c) 2011-2016 The original author or authors
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution.
 *
 *      The Eclipse Public License is available at
 *      http://www.eclipse.org/legal/epl-v10.html
 *
 *      The Apache License v2.0 is available at
 *      http://www.opensource.org/licenses/apache2.0.php
 *
 * You may elect to redistribute this code under either of these licenses.
 */

package io.vertx.servicediscovery;

import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.Nullable;
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.servicediscovery.impl.DiscoveryImpl;
import io.vertx.servicediscovery.spi.ServiceExporter;
import io.vertx.servicediscovery.spi.ServiceImporter;
import io.vertx.servicediscovery.utils.ClassLoaderUtils;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;

Service Discovery main entry point.

The service discovery is an infrastructure that let you publish and find `services`. A `service` is a discoverable functionality. It can be qualified by its type, metadata, and location. So a `service` can be a database, a service proxy, a HTTP endpoint. It does not have to be a vert.x entity, but can be anything. Each service is described by a Record.

The service discovery implements the interactions defined in the service-oriented computing. And to some extend, also provides the dynamic service-oriented computing interaction. So, application can react to arrival and departure of services.

A service provider can:

* publish a service record * un-publish a published record * update the status of a published service (down, out of service...)

A service consumer can:

* lookup for services * bind to a selected service (it gets a ServiceReference) and use it * release the service once the consumer is done with it * listen for arrival, departure and modification of services.

Consumer would 1) lookup for service record matching their need, 2) retrieve the ServiceReference that give access to the service, 3) get a service object to access the service, 4) release the service object once done.

A state above, the central piece of information shared by the providers and consumers are records.

Providers and consumers must create their own ServiceDiscovery instance. These instances are collaborating in background (distributed structure) to keep the set of services in sync.

Author:Clement Escoffier
/** * Service Discovery main entry point. * <p> * The service discovery is an infrastructure that let you publish and find `services`. A `service` is a discoverable * functionality. It can be qualified by its type, metadata, and location. So a `service` can be a database, a * service proxy, a HTTP endpoint. It does not have to be a vert.x entity, but can be anything. Each service is * described by a {@link Record}. * <p> * The service discovery implements the interactions defined in the service-oriented computing. And to some extend, * also provides the dynamic service-oriented computing interaction. So, application can react to arrival and * departure of services. * <p> * A service provider can: * <p> * * publish a service record * * un-publish a published record * * update the status of a published service (down, out of service...) * <p> * A service consumer can: * <p> * * lookup for services * * bind to a selected service (it gets a {@link ServiceReference}) and use it * * release the service once the consumer is done with it * * listen for arrival, departure and modification of services. * <p> * Consumer would 1) lookup for service record matching their need, 2) retrieve the {@link ServiceReference} that give access * to the service, 3) get a service object to access the service, 4) release the service object once done. * <p> * A state above, the central piece of information shared by the providers and consumers are {@link Record records}. * <p> * Providers and consumers must create their own {@link ServiceDiscovery} instance. These instances are collaborating * in background (distributed structure) to keep the set of services in sync. * * @author <a href="http://escoffier.me">Clement Escoffier</a> */
@VertxGen public interface ServiceDiscovery {
Creates an instance of ServiceDiscovery.
Params:
  • vertx – the vert.x instance
  • options – the discovery options
Returns:the created service discovery instance.
/** * Creates an instance of {@link ServiceDiscovery}. * * @param vertx the vert.x instance * @param options the discovery options * @return the created service discovery instance. */
static ServiceDiscovery create(Vertx vertx, ServiceDiscoveryOptions options) { return new DiscoveryImpl(vertx, options); }
Creates a new instance of ServiceDiscovery using the default configuration.
Params:
  • vertx – the vert.x instance
Returns:the created instance
/** * Creates a new instance of {@link ServiceDiscovery} using the default configuration. * * @param vertx the vert.x instance * @return the created instance */
static ServiceDiscovery create(Vertx vertx) { return create(vertx, new ServiceDiscoveryOptions()); }
Gets a service reference from the given record.
Params:
  • record – the chosen record
Returns:the service reference, that allows retrieving the service object. Once called the service reference is cached, and need to be released.
/** * Gets a service reference from the given record. * * @param record the chosen record * @return the service reference, that allows retrieving the service object. Once called the service reference is * cached, and need to be released. */
ServiceReference getReference(Record record);
Gets a service reference from the given record, the reference is configured with the given json object.
Params:
  • record – the chosen record
  • configuration – the configuration
Returns:the service reference, that allows retrieving the service object. Once called the service reference is cached, and need to be released.
/** * Gets a service reference from the given record, the reference is configured with the given json object. * * @param record the chosen record * @param configuration the configuration * @return the service reference, that allows retrieving the service object. Once called the service reference is * cached, and need to be released. */
ServiceReference getReferenceWithConfiguration(Record record, JsonObject configuration);
Releases the service reference.
Params:
  • reference – the reference to release, must not be null
Returns:whether or not the reference has been released.
/** * Releases the service reference. * * @param reference the reference to release, must not be {@code null} * @return whether or not the reference has been released. */
boolean release(ServiceReference reference);
Like registerServiceImporter(ServiceImporter, JsonObject, Handler<AsyncResult<Void>>) but returns a Future of the asynchronous result
/** * Like {@link #registerServiceImporter(ServiceImporter, JsonObject, Handler)} but returns a {@code Future} of the asynchronous result */
Future<Void> registerServiceImporter(ServiceImporter importer, JsonObject configuration);
Registers a discovery service importer. Importers let you integrate other discovery technologies in this service discovery.
Params:
  • importer – the service importer
  • configuration – the optional configuration
  • completionHandler – handler call when the importer has finished its initialization and initial imports
Returns:the current ServiceDiscovery
/** * Registers a discovery service importer. Importers let you integrate other discovery technologies in this service * discovery. * * @param importer the service importer * @param configuration the optional configuration * @param completionHandler handler call when the importer has finished its initialization and * initial imports * @return the current {@link ServiceDiscovery} */
@Fluent ServiceDiscovery registerServiceImporter(ServiceImporter importer, JsonObject configuration, Handler<AsyncResult<Void>> completionHandler);
Like registerServiceExporter(ServiceExporter, JsonObject, Handler<AsyncResult<Void>>) but returns a Future of the asynchronous result
/** * Like {@link #registerServiceExporter(ServiceExporter, JsonObject, Handler)} but returns a {@code Future} of the asynchronous result */
Future<Void> registerServiceExporter(ServiceExporter exporter, JsonObject configuration);
Registers a discovery bridge. Exporters let you integrate other discovery technologies in this service discovery.
Params:
  • exporter – the service exporter
  • configuration – the optional configuration
  • completionHandler – handler notified when the exporter has been correctly initialized.
Returns:the current ServiceDiscovery
/** * Registers a discovery bridge. Exporters let you integrate other discovery technologies in this service * discovery. * * @param exporter the service exporter * @param configuration the optional configuration * @param completionHandler handler notified when the exporter has been correctly initialized. * @return the current {@link ServiceDiscovery} */
@Fluent ServiceDiscovery registerServiceExporter(ServiceExporter exporter, JsonObject configuration, Handler<AsyncResult<Void>> completionHandler);
Closes the service discovery
/** * Closes the service discovery */
void close();
Publishes a record.
Params:
  • record – the record
  • resultHandler – handler called when the operation has completed (successfully or not). In case of success, the passed record has a registration id required to modify and un-register the service.
/** * Publishes a record. * * @param record the record * @param resultHandler handler called when the operation has completed (successfully or not). In case of success, * the passed record has a registration id required to modify and un-register the service. */
void publish(Record record, Handler<AsyncResult<Record>> resultHandler);
Like publish(Record, Handler<AsyncResult<Record>>) but returns a Future of the asynchronous result
/** * Like {@link #publish(Record, Handler)} but returns a {@code Future} of the asynchronous result */
Future<Record> publish(Record record);
Un-publishes a record.
Params:
  • id – the registration id
  • resultHandler – handler called when the operation has completed (successfully or not).
/** * Un-publishes a record. * * @param id the registration id * @param resultHandler handler called when the operation has completed (successfully or not). */
void unpublish(String id, Handler<AsyncResult<Void>> resultHandler);
Like unpublish(String, Handler<AsyncResult<Void>>) but returns a Future of the asynchronous result
/** * Like {@link #unpublish(String, Handler)} but returns a {@code Future} of the asynchronous result */
Future<Void> unpublish(String id);
Lookups for a single record.

Filters are expressed using a Json object. Each entry of the given filter will be checked against the record. All entry must match exactly the record. The entry can use the special "*" value to denotes a requirement on the key, but not on the value.

Let's take some example:

  { "name" = "a" } => matches records with name set fo "a"
  { "color" = "*" } => matches records with "color" set
  { "color" = "red" } => only matches records with "color" set to "red"
  { "color" = "red", "name" = "a"} => only matches records with name set to "a", and color set to "red"

If the filter is not set (null or empty), it accepts all records.

This method returns the first matching record.

Params:
  • filter – the filter.
  • resultHandler – handler called when the lookup has been completed. When there are no matching record, the operation succeeds, but the async result has no result (null).
/** * Lookups for a single record. * <p> * Filters are expressed using a Json object. Each entry of the given filter will be checked against the record. * All entry must match exactly the record. The entry can use the special "*" value to denotes a requirement on the * key, but not on the value. * <p> * Let's take some example: * <pre> * { "name" = "a" } => matches records with name set fo "a" * { "color" = "*" } => matches records with "color" set * { "color" = "red" } => only matches records with "color" set to "red" * { "color" = "red", "name" = "a"} => only matches records with name set to "a", and color set to "red" * </pre> * <p> * If the filter is not set ({@code null} or empty), it accepts all records. * <p> * This method returns the first matching record. * * @param filter the filter. * @param resultHandler handler called when the lookup has been completed. When there are no matching record, the * operation succeeds, but the async result has no result ({@code null}). */
void getRecord(JsonObject filter, Handler<AsyncResult<@Nullable Record>> resultHandler);
Like getRecord(JsonObject, Handler<AsyncResult<Record>>) but returns a Future of the asynchronous result
/** * Like {@link #getRecord(JsonObject, Handler)} but returns a {@code Future} of the asynchronous result */
Future<@Nullable Record> getRecord(JsonObject filter);
Lookups for a single record.

The filter is a Function taking a Record as argument and returning a boolean. You should see it as an accept method of a filter. This method return a record passing the filter.

This method only looks for records with a UP status.

Params:
  • filter – the filter, must not be null. To return all records, use a function accepting all records
  • resultHandler – the result handler called when the lookup has been completed. When there are no matching record, the operation succeed, but the async result has no result.
/** * Lookups for a single record. * <p> * The filter is a {@link Function} taking a {@link Record} as argument and returning a boolean. You should see it * as an {@code accept} method of a filter. This method return a record passing the filter. * <p> * This method only looks for records with a {@code UP} status. * * @param filter the filter, must not be {@code null}. To return all records, use a function accepting all records * @param resultHandler the result handler called when the lookup has been completed. When there are no matching * record, the operation succeed, but the async result has no result. */
void getRecord(Function<Record, Boolean> filter, Handler<AsyncResult<@Nullable Record>> resultHandler);
Like getRecord(Function<Record,Boolean>, Handler<AsyncResult<Record>>) but returns a Future of the asynchronous result
/** * Like {@link #getRecord(Function, Handler)} but returns a {@code Future} of the asynchronous result */
Future<@Nullable Record> getRecord(Function<Record, Boolean> filter);
Lookups for a single record.

The filter is a Function taking a Record as argument and returning a boolean. You should see it as an accept method of a filter. This method return a record passing the filter.

Unlike getRecord(Function<Record,Boolean>, Handler<AsyncResult<Record>>), this method may accept records with a OUT OF SERVICE status, if the includeOutOfService parameter is set to true.

Params:
  • filter – the filter, must not be null. To return all records, use a function accepting all records
  • includeOutOfService – whether or not the filter accepts OUT OF SERVICE records
  • resultHandler – the result handler called when the lookup has been completed. When there are no matching record, the operation succeed, but the async result has no result.
/** * Lookups for a single record. * <p> * The filter is a {@link Function} taking a {@link Record} as argument and returning a boolean. You should see it * as an {@code accept} method of a filter. This method return a record passing the filter. * <p> * Unlike {@link #getRecord(Function, Handler)}, this method may accept records with a {@code OUT OF SERVICE} * status, if the {@code includeOutOfService} parameter is set to {@code true}. * * @param filter the filter, must not be {@code null}. To return all records, use a function accepting all records * @param includeOutOfService whether or not the filter accepts {@code OUT OF SERVICE} records * @param resultHandler the result handler called when the lookup has been completed. When there are no matching * record, the operation succeed, but the async result has no result. */
void getRecord(Function<Record, Boolean> filter, boolean includeOutOfService, Handler<AsyncResult<@Nullable Record>> resultHandler);
Like getRecords(Function<Record,Boolean>, boolean, Handler<AsyncResult<List<Record>>>) but returns a Future of the asynchronous result
/** * Like {@link #getRecords(Function, boolean, Handler)} but returns a {@code Future} of the asynchronous result */
Future<@Nullable Record> getRecord(Function<Record, Boolean> filter, boolean includeOutOfService);
Lookups for a set of records. Unlike getRecord(JsonObject, Handler<AsyncResult<Record>>), this method returns all matching records.
Params:
  • filter – the filter - see getRecord(JsonObject, Handler<AsyncResult<Record>>)
  • resultHandler – handler called when the lookup has been completed. When there are no matching record, the operation succeed, but the async result has an empty list as result.
/** * Lookups for a set of records. Unlike {@link #getRecord(JsonObject, Handler)}, this method returns all matching * records. * * @param filter the filter - see {@link #getRecord(JsonObject, Handler)} * @param resultHandler handler called when the lookup has been completed. When there are no matching record, the * operation succeed, but the async result has an empty list as result. */
void getRecords(JsonObject filter, Handler<AsyncResult<List<Record>>> resultHandler);
Like getRecords(JsonObject, Handler<AsyncResult<List<Record>>>) but returns a Future of the asynchronous result
/** * Like {@link #getRecords(JsonObject, Handler)} but returns a {@code Future} of the asynchronous result */
Future<List<Record>> getRecords(JsonObject filter);
Lookups for a set of records. Unlike getRecord(Function<Record,Boolean>, Handler<AsyncResult<Record>>), this method returns all matching records.

The filter is a Function taking a Record as argument and returning a boolean. You should see it as an accept method of a filter. This method return a record passing the filter.

This method only looks for records with a UP status.

Params:
  • filter – the filter, must not be null. To return all records, use a function accepting all records
  • resultHandler – handler called when the lookup has been completed. When there are no matching record, the operation succeed, but the async result has an empty list as result.
/** * Lookups for a set of records. Unlike {@link #getRecord(Function, Handler)}, this method returns all matching * records. * <p> * The filter is a {@link Function} taking a {@link Record} as argument and returning a boolean. You should see it * as an {@code accept} method of a filter. This method return a record passing the filter. * <p> * This method only looks for records with a {@code UP} status. * * @param filter the filter, must not be {@code null}. To return all records, use a function accepting all records * @param resultHandler handler called when the lookup has been completed. When there are no matching record, the * operation succeed, but the async result has an empty list as result. */
void getRecords(Function<Record, Boolean> filter, Handler<AsyncResult<List<Record>>> resultHandler);
Like getRecords(Function<Record,Boolean>, Handler<AsyncResult<List<Record>>>) but returns a Future of the asynchronous result
/** * Like {@link #getRecords(Function, Handler)} but returns a {@code Future} of the asynchronous result */
Future<List<Record>> getRecords(Function<Record, Boolean> filter);
Lookups for a set of records. Unlike getRecord(Function<Record,Boolean>, Handler<AsyncResult<Record>>), this method returns all matching records.

The filter is a Function taking a Record as argument and returning a boolean. You should see it as an accept method of a filter. This method return a record passing the filter.

Unlike getRecords(Function<Record,Boolean>, Handler<AsyncResult<List<Record>>>), this method may accept records with a OUT OF SERVICE status, if the includeOutOfService parameter is set to true.

Params:
  • filter – the filter, must not be null. To return all records, use a function accepting all records
  • includeOutOfService – whether or not the filter accepts OUT OF SERVICE records
  • resultHandler – handler called when the lookup has been completed. When there are no matching record, the operation succeed, but the async result has an empty list as result.
/** * Lookups for a set of records. Unlike {@link #getRecord(Function, Handler)}, this method returns all matching * records. * <p> * The filter is a {@link Function} taking a {@link Record} as argument and returning a boolean. You should see it * as an {@code accept} method of a filter. This method return a record passing the filter. * <p> * Unlike {@link #getRecords(Function, Handler)}, this method may accept records with a {@code OUT OF SERVICE} * status, if the {@code includeOutOfService} parameter is set to {@code true}. * * @param filter the filter, must not be {@code null}. To return all records, use a function accepting all records * @param includeOutOfService whether or not the filter accepts {@code OUT OF SERVICE} records * @param resultHandler handler called when the lookup has been completed. When there are no matching record, the * operation succeed, but the async result has an empty list as result. */
void getRecords(Function<Record, Boolean> filter, boolean includeOutOfService, Handler<AsyncResult<List<Record>>> resultHandler);
Like getRecords(Function<Record,Boolean>, boolean, Handler<AsyncResult<List<Record>>>) but returns a Future of the asynchronous result
/** * Like {@link #getRecords(Function, boolean, Handler)} but returns a {@code Future} of the asynchronous result */
Future<List<Record>> getRecords(Function<Record, Boolean> filter, boolean includeOutOfService);
Updates the given record. The record must has been published, and has it's registration id set.
Params:
  • record – the updated record
  • resultHandler – handler called when the lookup has been completed.
/** * Updates the given record. The record must has been published, and has it's registration id set. * * @param record the updated record * @param resultHandler handler called when the lookup has been completed. */
void update(Record record, Handler<AsyncResult<Record>> resultHandler);
Like update(Record, Handler<AsyncResult<Record>>) but returns a Future of the asynchronous result
/** * Like {@link #update(Record, Handler)} but returns a {@code Future} of the asynchronous result */
Future<Record> update(Record record);
Returns:the set of service references retrieved by this service discovery.
/** * @return the set of service references retrieved by this service discovery. */
Set<ServiceReference> bindings();
Returns:the discovery options. Modifying the returned object would not update the discovery service configuration. This object should be considered as read-only.
/** * @return the discovery options. Modifying the returned object would not update the discovery service * configuration. This object should be considered as read-only. */
ServiceDiscoveryOptions options();
Release the service object retrieved using get methods from the service type interface. It searches for the reference associated with the given object and release it.
Params:
  • discovery – the service discovery
  • svcObject – the service object
/** * Release the service object retrieved using {@code get} methods from the service type interface. * It searches for the reference associated with the given object and release it. * * @param discovery the service discovery * @param svcObject the service object */
static void releaseServiceObject(ServiceDiscovery discovery, Object svcObject) { Objects.requireNonNull(discovery); Objects.requireNonNull(svcObject); Object svc = ClassLoaderUtils.extractDelegate(svcObject); if (svc == null) { svc = svcObject; } Collection<ServiceReference> references = discovery.bindings(); Object finalSvc = svc; references.stream().filter(ref -> ref.isHolding(finalSvc)).forEach(ServiceReference::release); } }