/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.atomix.manager;
import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.concurrent.ThreadContext;
import io.atomix.resource.Resource;
import io.atomix.resource.ResourceType;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
* Provides an interface for creating and operating on {@link io.atomix.resource.Resource}s remotely.
*
* @param <T> resource type
* @author <a href="http://github.com/kuujo">Jordan Halterman</a>
*/
public interface ResourceManager<T extends ResourceManager<T>> {
/**
* Returns the Atomix thread context.
* <p>
* This context is representative of the thread on which asynchronous callbacks will be executed for this
* Atomix instance. Atomix guarantees that all {@link CompletableFuture}s supplied by this instance will
* be executed via the returned context. Users can use the context to access the thread-local
* {@link Serializer}.
*
* @return The Atomix thread context.
*/
ThreadContext context();
/**
* Returns the resource manager serializer.
* <p>
* The serializer applies to all resources controlled by this instance. Serializable types registered
* on the serializer will be reflected at the {@link io.atomix.catalyst.transport.Transport} layer.
* Types registered on the client must also be registered on the server for deserialization.
*
* @return The resource manager serializer.
*/
Serializer serializer();
/**
* Returns the resource type for the given resource class.
*
* @param type The resource class.
* @return The resource type for the given resource class.
* @throws IllegalArgumentException if {@code type} is unregistered
*/
ResourceType type(Class<? extends Resource<?>> type);
/**
* Checks whether a resource exists with the given key.
* <p>
* If no resource with the given {@code key} exists in the cluster, the returned {@link CompletableFuture} will
* be completed {@code false}. Note, however, that users should not significantly rely upon the existence or
* non-existence of a resource due to race conditions. While a resource may not exist when the returned future is
* completed, it may be created by another node shortly thereafter.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* if (!atomix.exists("lock").get()) {
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.exists("lock").thenAccept(exists -> {
* if (!exists) {
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* });
* }
* </pre>
*
* @param key The key to check.
* @return A completable future indicating whether the given key exists.
* @throws NullPointerException if {@code key} is null
*/
CompletableFuture<Boolean> exists(String key);
/**
* Returns keys of all existing resources.
*
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* Collection<String> resourceKeys = atomix.keys().get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<Collection<String>>keys().thenAccept(resourceKeys -> {
* ...
* });
* }
* </pre>
*
* @return A completable future to be completed with the keys of all existing resources.
*/
CompletableFuture<Set<String>> keys();
/**
* Returns the keys of existing resources belonging to a resource type.
*
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* Set<String> resourceKeys = atomix.keys(DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<Set<String>>keys().thenAccept(resourceKeys -> {
* ...
* });
* }
* </pre>
*
* @param type The resource type by which to filter resources.
* @param <T> The resource type.
* @return A completable future to be completed with the set of resource keys.
* @throws NullPointerException if {@code type} is null
*/
<T extends Resource> CompletableFuture<Set<String>> keys(Class<? super T> type);
/**
* Returns the keys of existing resources belonging to a resource type.
*
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* Set<String> resourceKeys = atomix.keys(DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<Set<String>>keys().thenAccept(resourceKeys -> {
* ...
* });
* }
* </pre>
*
* @param type The resource type by which to filter resources.
* @return A completable future to be completed with the set of resource keys.
*/
CompletableFuture<Set<String>> keys(ResourceType type);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, Class<? super T> type);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param config The cluster-wide resource configuration.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, Class<? super T> type, Resource.Config config);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param options The local resource options.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, Class<? super T> type, Resource.Options options);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param config The cluster-wide resource configuration.
* @param options The local resource options.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, Class<? super T> type, Resource.Config config, Resource.Options options);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, ResourceType type);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param config The cluster-wide resource configuration.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, ResourceType type, Resource.Config config);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param options The local resource options.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, ResourceType type, Resource.Options options);
/**
* Gets or creates the given resource and acquires a singleton reference to it.
* <p>
* If a resource at the given key already exists, the resource will be validated to verify that its type
* matches the given type. If no resource yet exists, a new resource will be created in the cluster. Once
* the session for the resource has been opened, a resource instance will be returned.
* <p>
* The returned {@link Resource} instance will be a singleton reference to an global instance for this node.
* That is, multiple calls to this method for the same resource will result in the same {@link Resource}
* instance being returned.
* <p>
* This method returns a {@link CompletableFuture} which can be used to block until the operation completes
* or to be notified in a separate thread once the operation completes. To block until the operation completes,
* use the {@link CompletableFuture#get()} method:
* <pre>
* {@code
* DistributedLock lock = atomix.getResource("lock", DistributedLock.class).get();
* }
* </pre>
* Alternatively, to execute the operation asynchronous and be notified once the result is received in a different
* thread, use one of the many completable future callbacks:
* <pre>
* {@code
* atomix.<DistributedLock>getResource("lock", DistributedLock.class).thenAccept(lock -> {
* ...
* });
* }
* </pre>
*
* @param key The key at which to get the resource.
* @param type The expected resource type.
* @param config The cluster-wide resource configuration.
* @param options The local resource options.
* @param <T> The resource type.
* @return A completable future to be completed once the resource has been loaded.
* @throws NullPointerException if {@code key} or {@code type} are null
* @throws IllegalArgumentException if {@code type} is inconsistent with a previously created type
*/
<T extends Resource> CompletableFuture<T> getResource(String key, ResourceType type, Resource.Config config, Resource.Options options);
}