All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atomix.AtomixClient Maven / Gradle / Ivy

There is a newer version: 3.0.5
Show newest version
/*
 * Copyright 2016 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;

import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.transport.Address;
import io.atomix.catalyst.transport.Transport;
import io.atomix.catalyst.util.Assert;
import io.atomix.catalyst.util.PropertiesReader;
import io.atomix.copycat.client.ConnectionStrategy;
import io.atomix.manager.ResourceClient;
import io.atomix.manager.ResourceServer;
import io.atomix.manager.options.ClientOptions;
import io.atomix.resource.Resource;
import io.atomix.resource.ResourceType;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * Provides an interface for creating and operating on {@link io.atomix.resource.Resource}s remotely.
 * 

* This {@link ResourceClient} implementation facilitates working with {@link io.atomix.resource.Resource}s remotely as * a client of the Atomix cluster. To create a client, construct a client builder via {@link #builder()}. * The builder requires a list of {@link Address}es to which to connect. *

 *   {@code
 *   List
servers = Arrays.asList( * new Address("123.456.789.0", 5000), * new Address("123.456.789.1", 5000) * ); * Atomix atomix = AtomixClient.builder(servers) * .withTransport(new NettyTransport()) * .build(); * } *
* The {@link Address} list does not have to include all servers in the cluster, but must include at least one live * server in order for the client to connect. Once the client connects to the cluster and opens a session, the client * will receive an updated list of servers to which to connect. *

* Clients communicate with the cluster via a {@link Transport}. By default, the {@code NettyTransport} is used if * no transport is explicitly configured. Thus, if no transport is configured then the Netty transport is expected * to be available on the classpath. *

Client lifecycle

* When a client is {@link #connect() started}, the client will attempt to contact random servers in the provided * {@link Address} list to open a new session. Opening a client session requires only that the client be able to * communicate with at least one server which can communicate with the leader. Once a session has been opened, * the client will periodically send keep-alive requests to the cluster to maintain its session. In the event * that the client crashes or otherwise becomes disconnected from the cluster, the client's session will expire * after a configured session timeout and the client will have to open a new session to reconnect. *

* Clients may connect to and communicate with any server in the cluster. Typically, once a client connects to a * server, the client will attempt to remain connected to that server until some exceptional case occurs. Exceptional * cases may include a failure of the server, a network partition, or the server falling too far out of sync with * the rest of the cluster. When a failure in the cluster occurs and the client becomes disconnected from the cluster, * it will transparently reconnect to random servers until it finds a reachable server. *

* During certain cluster events such as leadership changes, the client may not be able to communicate with the * cluster for some arbitrary (but typically short) period of time. During that time, Atomix guarantees that the * client's session will not expire even if its timeout elapses. Once a new leader is elected, the client's session * timeout is reset. * * @author Jordan Halterman */ public class AtomixClient extends Atomix { /** * Returns a new Atomix replica builder from the given configuration file. * * @param properties The properties file from which to load the replica builder. * @return The replica builder. */ public static Builder builder(String properties) { return builder(PropertiesReader.load(properties).properties()); } /** * Returns a new Atomix replica builder from the given properties. * * @param properties The properties from which to load the replica builder. * @return The replica builder. */ public static Builder builder(Properties properties) { ClientOptions clientProperties = new ClientOptions(properties); return builder() .withTransport(clientProperties.transport()) .withSerializer(clientProperties.serializer()); } /** * Returns a new Atomix client builder. *

* The provided set of members will be used to connect to the Raft cluster. The members list does not have to represent * the complete list of servers in the cluster, but it must have at least one reachable member. * * @return The client builder. */ public static Builder builder() { return new Builder(ResourceClient.builder()); } /** * Builds the underlying resource client from the given properties. */ private static ResourceClient buildClient(Properties properties) { ClientOptions clientProperties = new ClientOptions(properties); return ResourceClient.builder() .withTransport(clientProperties.transport()) .build(); } /** * Constructs a client from the given properties. * * @param properties The properties from which to construct the client. */ public AtomixClient(Properties properties) { this(buildClient(properties)); } /** * Constructs a client for the given resource client. * * @param client The resource client. */ public AtomixClient(ResourceClient client) { super(client); } /** * Connects the client to the cluster. * * @return A completable future to be completed once the client has been connected. */ public CompletableFuture connect(Address... cluster) { return connect(Arrays.asList(Assert.notNull(cluster, "cluster"))); } /** * Connects the client to the cluster. * * @return A completable future to be completed once the client has been connected. */ public CompletableFuture connect(Collection

cluster) { return client.connect(cluster).thenApply(v -> this); } /** * Closes the client. * * @return A completable future to be completed once the client is closed. */ public CompletableFuture close() { return client.close(); } /** * Builder for programmatically constructing an {@link AtomixClient}. *

* The client builder configures an {@link AtomixClient} to connect to a cluster of {@link ResourceServer}s. * To create a client builder, use the {@link #builder()} method. *

   *   {@code
   *   Atomix client = AtomixClient.builder(servers)
   *     .withTransport(new NettyTransport())
   *     .build();
   *   }
   * 
*/ public static class Builder implements io.atomix.catalyst.util.Builder { private final ResourceClient.Builder builder; private Builder(ResourceClient.Builder builder) { this.builder = Assert.notNull(builder, "builder").withResourceTypes(RESOURCES); } /** * Sets the Atomix transport. *

* The configured transport should be the same transport as all other nodes in the cluster. * If no transport is explicitly provided, the instance will default to the {@code NettyTransport} * if available on the classpath. * * @param transport The Atomix transport. * @return The Atomix builder. * @throws NullPointerException if {@code transport} is {@code null} */ public Builder withTransport(Transport transport) { builder.withTransport(transport); return this; } /** * Sets the Atomix connection strategy. * * @param connectionStrategy The Atomix connection strategy. * @return The Atomix builder. * @throws NullPointerException If the {@code connection strategy} is {@code null} */ public Builder withConnectionStrategy(ConnectionStrategy connectionStrategy) { builder.withConnectionStrategy(connectionStrategy); return this; } /** * Sets the Atomix serializer. *

* The serializer will be used to serialize and deserialize operations that are sent over the wire. * * @param serializer The Atomix serializer. * @return The Atomix builder. */ public Builder withSerializer(Serializer serializer) { builder.withSerializer(serializer); return this; } /** * Sets the client session timeout. * * @param sessionTimeout The client session timeout. * @return The client builder. */ public Builder withSessionTimeout(Duration sessionTimeout) { builder.withSessionTimeout(sessionTimeout); return this; } /** * Sets the available resource types. * * @param types The available resource types. * @return The client builder. */ public Builder withResourceTypes(Class>... types) { if (types != null) { return withResourceTypes(Arrays.asList(types).stream().map(ResourceType::new).collect(Collectors.toList())); } return this; } /** * Sets the available resource types. * * @param types The available resource types. * @return The client builder. */ public Builder withResourceTypes(ResourceType... types) { if (types != null) { return withResourceTypes(Arrays.asList(types)); } return this; } /** * Sets the available resource types. * * @param types The available resource types. * @return The client builder. */ public Builder withResourceTypes(Collection types) { builder.withResourceTypes(types); return this; } /** * Adds a resource type to the client. * * @param type The resource type. * @return The client builder. */ public Builder addResourceType(Class> type) { return addResourceType(new ResourceType(type)); } /** * Adds a resource type to the client. * * @param type The resource type. * @return The client builder. */ public Builder addResourceType(ResourceType type) { builder.addResourceType(type); return this; } @Override public AtomixClient build() { return new AtomixClient(builder.build()); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy