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

com.basho.riak.client.api.commands.kv.FetchValue Maven / Gradle / Ivy

The newest version!
/*
 * 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.commands.kv;

import com.basho.riak.client.api.GenericRiakCommand;
import com.basho.riak.client.api.cap.Quorum;
import com.basho.riak.client.api.cap.VClock;
import com.basho.riak.client.core.FutureOperation;
import com.basho.riak.client.core.RiakCluster;
import com.basho.riak.client.core.operations.FetchOperation;
import com.basho.riak.client.core.RiakFuture;
import com.basho.riak.client.api.commands.RiakOption;
import com.basho.riak.client.core.query.Location;

import java.util.HashMap;
import java.util.Map;

/**
 * Command used to fetch a value from Riak.
 * 
 * 

* Fetching an object from Riak is a simple matter of supplying a {@link com.basho.riak.client.core.query.Location} * and executing the FetchValue operation. *

 * {@code
 * Namespace ns = new Namespace("my_type","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);}
*

*

* All operations can called async as well. *

 * {@code
 * ...
 * RiakFuture future = client.executeAsync(fv);
 * ...
 * future.await();
 * if (future.isSuccess())
 * {
 *     ...
 * }}
*

*

* ORM features are also provided when retrieving the results from the response. * By default, JSON serialization / deserializtion is used. For example, if * the value stored in Riak was JSON and mapped to your class {@code MyPojo}: *

 * {@code
 * ...
 * MyPojo mp = response.getValue(MyPojo.class);
 * ...}
*

* * @author Dave Rusek * @since 2.0 * @see Response */ public final class FetchValue extends GenericRiakCommand.GenericRiakCommandWithSameInfo { private final Location location; private final Map, Object> options = new HashMap<>(); FetchValue(Builder builder) { this.location = builder.location; this.options.putAll(builder.options); } @Override protected final RiakFuture executeAsync(RiakCluster cluster) { return super.executeAsync(cluster); } @Override protected Response convertResponse(FutureOperation request, FetchOperation.Response coreResponse) { return new Response.Builder().withNotFound(coreResponse.isNotFound()) .withUnchanged(coreResponse.isUnchanged()) .withValues(coreResponse.getObjectList()) .withLocation(location) // for ORM .build(); } @Override protected FetchOperation buildCoreOperation() { FetchOperation.Builder builder = new FetchOperation.Builder(location); for (Map.Entry, Object> opPair : options.entrySet()) { RiakOption option = opPair.getKey(); if (option == Option.R) { builder.withR(((Quorum) opPair.getValue()).getIntValue()); } else if (option == Option.DELETED_VCLOCK) { builder.withReturnDeletedVClock((Boolean) opPair.getValue()); } else if (option == Option.TIMEOUT) { builder.withTimeout((Integer) opPair.getValue()); } else if (option == Option.HEAD) { builder.withHeadOnly((Boolean) opPair.getValue()); } else if (option == Option.BASIC_QUORUM) { builder.withBasicQuorum((Boolean) opPair.getValue()); } else if (option == Option.IF_MODIFIED) { VClock clock = (VClock) opPair.getValue(); builder.withIfNotModified(clock.getBytes()); } else if (option == Option.N_VAL) { builder.withNVal((Integer) opPair.getValue()); } else if (option == Option.PR) { builder.withPr(((Quorum) opPair.getValue()).getIntValue()); } else if (option == Option.SLOPPY_QUORUM) { builder.withSloppyQuorum((Boolean) opPair.getValue()); } else if (option == Option.NOTFOUND_OK) { builder.withNotFoundOK((Boolean) opPair.getValue()); } } return builder.build(); } /** * A response from Riak containing results from a FetchValue command. *

* The Response, unless marked not found or unchanged, will contain one or * more objects returned from Riak (all siblings are returned if present). *

*/ public static class Response extends KvResponseBase { private final boolean notFound; private final boolean unchanged; Response(Init builder) { super(builder); this.notFound = builder.notFound; this.unchanged = builder.unchanged; } /** * Determine if there was a value in Riak. *

* If there was no value present at the supplied {@code Location} in * Riak, this will be true. *

* * @return true if there was no value in Riak. */ public boolean isNotFound() { return notFound; } /** * Determine if the value is unchanged. *

* If the fetch request set {@link com.basho.riak.client.api.commands.kv.FetchValue.Option#IF_MODIFIED} * this indicates if the value in Riak has been modified. *

* * @return true if the vector clock for the object in Riak matched the * supplied vector clock, false otherwise. */ public boolean isUnchanged() { return unchanged; } protected static abstract class Init> extends KvResponseBase.Init { private boolean notFound; private boolean unchanged; T withUnchanged(boolean unchanged) { this.unchanged = unchanged; return self(); } T withNotFound(boolean notFound) { this.notFound = notFound; return self(); } } static class Builder extends Init { @Override protected Builder self() { return this; } @Override Response build() { return new Response(this); } } } /** * Options for controlling how Riak performs the fetch operation. *

* These options can be supplied to the {@link FetchValue.Builder} to change * how Riak performs the operation. These override the defaults provided * by the bucket. *

* * @author Dave Rusek * @since 2.0 * @see Replication Properties */ public static final class Option extends RiakOption { /** * Read Quorum. * How many replicas need to agree when fetching the object. */ public static final Option R = new Option<>("R"); /** * Primary Read Quorum. * How many primary replicas need to be available when retrieving the object. */ public static final Option PR = new Option<>("PR"); /** * Basic Quorum. * Whether to return early in some failure cases (eg. when r=1 and you get * 2 errors and a success basic_quorum=true would return an error) */ public static final Option BASIC_QUORUM = new Option<>("BASIC_QUORUM"); /** * Not Found OK. * Whether to treat notfounds as successful reads for the purposes of R */ public static final Option NOTFOUND_OK = new Option<>("NOTFOUND_OK"); /** * If Modified. * When a vector clock is supplied with this option, only return the object * if the vector clocks don't match. */ public static final Option IF_MODIFIED = new Option<>("IF_MODIFIED"); /** * Head. * return the object with the value(s) set as empty. This allows you to get the * meta data without a potentially large value. Analogous to an HTTP HEAD request. */ public static final Option HEAD = new Option<>("HEAD"); /** * Deleted VClock. * By default single tombstones are not returned by a fetch operations. This * will return a Tombstone if it is present. */ public static final Option DELETED_VCLOCK = new Option<>("DELETED_VCLOCK"); /** * Timeout. * Sets the server-side timeout for this operation. The default in Riak is 60 seconds. */ public static final Option TIMEOUT = new Option<>("TIMEOUT"); public static final Option SLOPPY_QUORUM = new Option<>("SLOPPY_QUORUM"); public static final Option N_VAL = new Option<>("N_VAL"); private Option(String name) { super(name); } } /** * Used to construct a FetchValue command. */ public static class Builder extends KvBuilderBase { /** * Constructs a builder for a FetchValue operation using the supplied location. * @param location the location of the object you want to fetch from Riak. */ public Builder(Location location) { super(location); } /** * Add an optional setting for this command. * This will be passed along with the request to Riak to tell it how * to behave when servicing the request. * * @param option the option * @param value the value for the option * @return a reference to this object. */ public Builder withOption(Option option, U value) { addOption(option, value); return this; } /** * Set the Riak-side timeout value. *

* By default, riak has a 60s timeout for operations. Setting * this value will override that default for this operation. *

* @param timeout the timeout in milliseconds to be sent to riak. * @return a reference to this object. */ public Builder withTimeout(int timeout) { withOption(Option.TIMEOUT, timeout); return this; } /** * Build a {@link FetchValue} object * * @return a FetchValue command */ @Override public FetchValue build() { return new FetchValue(this); } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (location != null ? location.hashCode() : 0);; result = prime * result + options.hashCode(); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof FetchValue)) { return false; } final FetchValue other = (FetchValue) obj; if (this.location != other.location && (this.location == null || !this.location.equals(other.location))) { return false; } if (this.options != other.options && (this.options == null || !this.options.equals(other.options))) { return false; } return true; } @Override public String toString() { return String.format("{location: %s, options: %s}", location, options); } }