com.basho.riak.client.api.RiakClient Maven / Gradle / Ivy
Show all versions of riak-client Show documentation
/*
* Copyright 2013 Basho Technologies Inc
*
* 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 com.basho.riak.client.api;
import com.basho.riak.client.core.RiakCluster;
import com.basho.riak.client.core.RiakFuture;
import com.basho.riak.client.core.RiakNode;
import com.basho.riak.client.core.util.HostAndPort;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
*
* The client used to perform operations on Riak.
*
* The core of the Java client models a Riak cluster:
*
*
*
*
* The easiest way to get started with the client API is using one of the static
* methods provided to instantiate and start the client:
*
*
* {@code
* RiakClient client =
* RiakClient.newClient("192.168.1.1","192.168.1.2","192.168.1.3"); }
*
* Note that the Riak Java client uses the Riak Protocol Buffers API exclusively.
*
* For more complex configurations you will instantiate one or more {@link com.basho.riak.client.core.RiakNode}s
* and build a {@link com.basho.riak.client.core.RiakCluster} to supply to the
* RiakClient constructor.
*
*
* {@code
* RiakNode.Builder builder = new RiakNode.Builder();
* builder.withMinConnections(10);
* builder.withMaxConnections(50);
*
* List addresses = new LinkedList();
* addresses.add("192.168.1.1");
* addresses.add("192.168.1.2");
* addresses.add("192.168.1.3");
*
* List nodes = RiakNode.Builder.buildNodes(builder, addresses);
* RiakCluster cluster = new RiakCluster.Builder(nodes).build();
* cluster.start();
* RiakClient client = new RiakClient(cluster); }
*
* Once you have a client, {@literal RiakCommand}s from the {@literal com.basho.riak.client.api.commands.*}
* packages are built then executed by the client:
*
* {@code
* Namespace ns = new Namespace("default","my_bucket");
* Location loc = new Location(ns, "my_key");
* FetchValue fv = new FetchValue.Builder(loc).build();
* FetchValue.Response response = client.execute(fv);
* RiakObject obj = response.getValue(RiakObject.class);}
*
*
* You can also execute all {@literal RiakCommand}s asynchronously. A
* {@link RiakFuture} for the operation is immediately returned:
*
* {@code
* Namespace ns = new Namespace("default","my_bucket");
* Location loc = new Location(ns, "my_key");
* FetchValue fv = new FetchValue.Builder(loc).build();
* RiakFuture future = client.executeAsync(fv);
* future.await();
* if (future.isSuccess())
* {
* FetchValue.Response response = future.getNow();
* RiakObject obj = response.getValue(RiakObject.class);
* ...
* }
* else
* {
* Throwable error = future.cause();
* ...
* }}
*
*
*
RiakCommand subclasses
* Fetching, storing and deleting objects
*
* - {@link com.basho.riak.client.api.commands.kv.FetchValue}
* - {@link com.basho.riak.client.api.commands.kv.MultiFetch}
* - {@link com.basho.riak.client.api.commands.kv.StoreValue}
* - {@link com.basho.riak.client.api.commands.kv.UpdateValue}
* - {@link com.basho.riak.client.api.commands.kv.DeleteValue}
*
* Listing keys in a namespace
* - {@link com.basho.riak.client.api.commands.kv.ListKeys}
* Secondary index (2i) commands
*
* - {@link com.basho.riak.client.api.commands.indexes.RawIndexQuery}
* - {@link com.basho.riak.client.api.commands.indexes.BinIndexQuery}
* - {@link com.basho.riak.client.api.commands.indexes.IntIndexQuery}
* - {@link com.basho.riak.client.api.commands.indexes.BigIntIndexQuery}
*
* Fetching and storing datatypes (CRDTs)
*
* - {@link com.basho.riak.client.api.commands.datatypes.FetchCounter}
* - {@link com.basho.riak.client.api.commands.datatypes.FetchSet}
* - {@link com.basho.riak.client.api.commands.datatypes.FetchMap}
* - {@link com.basho.riak.client.api.commands.datatypes.UpdateCounter}
* - {@link com.basho.riak.client.api.commands.datatypes.UpdateSet}
* - {@link com.basho.riak.client.api.commands.datatypes.UpdateMap}
*
* Querying and modifying buckets
*
* - {@link com.basho.riak.client.api.commands.buckets.FetchBucketProperties}
* - {@link com.basho.riak.client.api.commands.buckets.StoreBucketProperties}
* - {@link com.basho.riak.client.api.commands.buckets.ListBuckets}
*
* Search commands
*
* - {@link com.basho.riak.client.api.commands.search.Search}
* - {@link com.basho.riak.client.api.commands.search.FetchIndex}
* - {@link com.basho.riak.client.api.commands.search.StoreIndex}
* - {@link com.basho.riak.client.api.commands.search.DeleteIndex}
* - {@link com.basho.riak.client.api.commands.search.FetchSchema}
* - {@link com.basho.riak.client.api.commands.search.StoreSchema}
*
* Map-Reduce
*
* - {@link com.basho.riak.client.api.commands.mapreduce.BucketMapReduce}
* - {@link com.basho.riak.client.api.commands.mapreduce.BucketKeyMapReduce}
* - {@link com.basho.riak.client.api.commands.mapreduce.IndexMapReduce}
* - {@link com.basho.riak.client.api.commands.mapreduce.SearchMapReduce}
*
* @author Dave Rusek
* @author Brian Roach
* @author Alex Moore
* @author Sergey Galkin
* @since 2.0
*/
public class RiakClient
{
private final RiakCluster cluster;
/**
* Create a new RiakClient to perform operations on the given cluster.
*
* The RiakClient provides a user API on top of the client core. Once
* instantiated, commands are submitted to it for execution on Riak.
*
* @param cluster the started RiakCluster to use.
*/
public RiakClient(RiakCluster cluster)
{
this.cluster = cluster;
}
/**
* Static factory method to create a new client instance.
* This method produces a client that connects to 127.0.0.1 on the default
* protocol buffers port (8087).
*
* @return a new client instance.
* @throws UnknownHostException
*/
public static RiakClient newClient() throws UnknownHostException
{
RiakNode.Builder builder = new RiakNode.Builder()
.withMinConnections(10);
RiakCluster cluster = new RiakCluster.Builder(builder.build()).build();
cluster.start();
return new RiakClient(cluster);
}
/**
* Static factory method to create a new client instance.
* This method produces a client connected to the supplied addresses on
* the supplied port.
* @param remoteAddresses a list of IP addresses or hostnames
* @param port the (protocol buffers) port to connect to on the supplied hosts.
* @return a new client instance
* @throws UnknownHostException if a supplied hostname cannot be resolved.
*/
public static RiakClient newClient(int port, String... remoteAddresses) throws UnknownHostException
{
return newClient(port, Arrays.asList(remoteAddresses));
}
/**
* Static factory method to create a new client instance.
* This method produces a client connected to the supplied addresses on
* the default (protocol buffers) port (8087).
* @param remoteAddresses a list of IP addresses or hostnames
* @return a new client instance
* @throws UnknownHostException if a supplied hostname cannot be resolved.
*/
public static RiakClient newClient(List remoteAddresses) throws UnknownHostException
{
return newClient(RiakNode.Builder.DEFAULT_REMOTE_PORT, remoteAddresses);
}
/**
* Static factory method to create a new client instance.
* This method produces a client connected to the supplied addresses on
* the default (protocol buffers) port (8087).
* @param remoteAddresses a list of IP addresses or hostnames
* @return a new client instance
* @throws UnknownHostException if a supplied hostname cannot be resolved.
*/
public static RiakClient newClient(String... remoteAddresses) throws UnknownHostException
{
return newClient(RiakNode.Builder.DEFAULT_REMOTE_PORT, Arrays.asList(remoteAddresses));
}
/**
* Static factory method to create a new client instance.
* This method produces a client connected to the supplied addresses on
* the supplied port.
* @param remoteAddresses a list of IP addresses or hostnames
* @param port the (protocol buffers) port to connect to on the supplied hosts.
* @return a new client instance
* @throws UnknownHostException if a supplied hostname cannot be resolved.
*/
public static RiakClient newClient(int port, List remoteAddresses) throws UnknownHostException
{
RiakNode.Builder builder = createDefaultNodeBuilder()
.withRemotePort(port);
return newClient(builder, remoteAddresses);
}
/**
* Static factory method to create a new client instance.
* This method produces a client connected to the supplied addresses.
* @param addresses one or more addresses to connect to.
* @return a new RiakClient instance.
* @throws java.net.UnknownHostException if a supplied hostname cannot be resolved.
*/
public static RiakClient newClient(InetSocketAddress... addresses) throws UnknownHostException
{
final List remoteAddresses = new ArrayList<>(addresses.length);
for (InetSocketAddress addy : addresses)
{
remoteAddresses.add(
String.format("%s:%s", addy.getHostName(), addy.getPort())
);
}
return newClient(createDefaultNodeBuilder(), remoteAddresses);
}
/**
* Static factory method to create a new client instance.
* This method produces a client connected to the supplied addresses and containing the {@link RiakNode}s
* that will be build by using provided builder.
* @param addresses one or more addresses to connect to.
* @return a new RiakClient instance.
* @throws java.net.UnknownHostException if a supplied hostname cannot be resolved.
* @since 2.0.3
* @see com.basho.riak.client.core.RiakCluster.Builder#RiakCluster.Builder(RiakNode.Builder, List)
*/
// NB: IntelliJ will see the above @see statement as invalid, but it's correct: https://bugs.openjdk.java.net/browse/JDK-8031625
public static RiakClient newClient(RiakNode.Builder nodeBuilder, List addresses) throws UnknownHostException
{
final RiakCluster cluster = new RiakCluster.Builder(nodeBuilder, addresses).build();
cluster.start();
return new RiakClient(cluster);
}
/**
* Static factory method to create a new client instance.
*
* @since 2.0.3
* @see #newClient(RiakNode.Builder, List)
*/
public static RiakClient newClient(RiakNode.Builder nodeBuilder, String... addresses) throws UnknownHostException
{
return newClient(nodeBuilder, Arrays.asList(addresses));
}
/**
* Static factory method to create a new client instance.
*
* @since 2.0.6
*/
public static RiakClient newClient(Collection hosts) throws UnknownHostException
{
return newClient(hosts, createDefaultNodeBuilder());
}
/**
* Static factory method to create a new client instance.
*
* @since 2.0.6
*/
public static RiakClient newClient(Collection hosts, RiakNode.Builder nodeBuilder) throws UnknownHostException
{
final RiakCluster cluster = new RiakCluster.Builder(hosts, nodeBuilder).build();
cluster.start();
return new RiakClient(cluster);
}
/**
*
* @since 2.0.3
*/
public static RiakNode.Builder createDefaultNodeBuilder()
{
return new RiakNode.Builder()
.withMinConnections(10);
}
/**
* Execute a RiakCommand synchronously.
*
* Calling this method causes the client to execute the provided RiakCommand synchronously.
* It will block until the operation completes then either return the response
* on success or throw an exception on failure.
*
*
* @param command
* The RiakCommand to execute.
* @param
* The RiakCommand's return type.
* @param The RiakCommand's query info type.
* @return a response from Riak.
* @throws ExecutionException if the command fails for any reason.
* @throws InterruptedException
*/
public T execute(RiakCommand command) throws ExecutionException, InterruptedException
{
return command.execute(cluster);
}
/**
* Execute a RiakCommand synchronously with a specified client timeout.
*
* Calling this method causes the client to execute the provided RiakCommand synchronously.
* It will block until the operation completes or up to the given timeout.
* It will either return the response on success or throw an
* exception on failure.
* Note: Using this timeout is different that setting a timeout on the command
* itself using the timeout() method of the command's associated builder.
* The command timeout is a Riak-side timeout value. This timeout is client-side.
*
*
* @param command
* The RiakCommand to execute.
* @param timeout the amount of time to wait before returning an exception
* @param unit the unit of time.
* @param
* The RiakCommand's return type.
* @param
* The RiakCommand's query info type.
* @return a response from Riak.
* @throws ExecutionException
* if the command fails for any reason.
* @throws InterruptedException
* @throws TimeoutException
* if the call to execute the command did not finish within the time limit
*/
public T execute(RiakCommand command, long timeout, TimeUnit unit) throws ExecutionException,
InterruptedException, TimeoutException {
return command.execute(cluster, timeout, unit);
}
/**
* Execute a RiakCommand asynchronously.
*
* Calling this method causes the client to execute the provided RiakCommand
* asynchronously. It will immediately return a RiakFuture that contains the
* running operation.
* @param RiakCommand's return type.
* @param The RiakCommand's query info type.
* @param command The RiakCommand to execute.
* @return a RiakFuture for the operation.
* @see RiakFuture
*/
public RiakFuture executeAsync(RiakCommand command)
{
return command.executeAsync(cluster);
}
/**
* Execute a StreamableRiakCommand asynchronously, and stream the results back before
* the command {@link RiakFuture#isDone() is done}.
*
* Calling this method causes the client to execute the provided
* StreamableRiakCommand asynchronously.
* It will immediately return a RiakFuture that contains an
* immediately available result (via {@link RiakFuture#get()}) that
* data will be streamed to.
* The RiakFuture will also keep track of the overall operation's progress
* with the {@link RiakFuture#isDone}, etc methods.
*
*
* Because the consumer thread will poll for new results, it is advisable to check the
* consumer thread's interrupted status via
* {@link Thread#isInterrupted() Thread.currentThread().isInterrupted() }, as the result
* iterator will not propagate an InterruptedException, but it will set the Thread's
* interrupted flag.
*
* @param StreamableRiakCommand's immediate return type, available before the command/operation is complete.
* @param The RiakCommand's query info type.
* @param command The RiakCommand to execute.
* @param timeoutMS The polling timeout in milliseconds for each result chunk.
* If the timeout is reached it will try again, instead of blocking indefinitely.
* If the value is too small (less than the average chunk arrival time), the
* result iterator will essentially busy wait.
* If the timeout is too large (much greater than the average chunk arrival time),
* the result iterator can block the consuming thread from seeing the done()
* status until the timeout is reached.
* @return a RiakFuture for the operation
* @since 2.1.0
* @see RiakFuture
*/
public RiakFuture executeAsyncStreaming(StreamableRiakCommand command, int timeoutMS)
{
return command.executeAsyncStreaming(cluster, timeoutMS);
}
/**
* Shut down the client and the underlying RiakCluster.
*
* The underlying client core (RiakCluster) uses a number of threads as
* does Netty. Calling this method will shut down all those threads cleanly.
* Failure to do so may prevent your application from exiting.
*
* @return a future that will complete when shutdown
*/
public Future shutdown()
{
return cluster.shutdown();
}
/**
* Get the RiakCluster being used by this client.
*
* Allows for adding/removing nodes, etc.
*
* @return The RiakCluster instance being used by this client.
*/
public RiakCluster getRiakCluster()
{
return cluster;
}
/**
* Cleans up any Thread-Local variables after shutdown.
* This operation is useful when you are in a container environment, and you
* do not want to leave the thread local variables in the threads you do not manage.
* Call this method when your application is being unloaded from the container, after
* all {@link RiakNode}, {@link RiakCluster}, and {@link com.basho.riak.client.api.RiakClient}
* objects are in the shutdown state.
*/
public void cleanup()
{
cluster.cleanup();
}
}