Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.basho.riak.client.api.commands.kv.StoreValue Maven / Gradle / Ivy
/*
* 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.api.convert.Converter;
import com.basho.riak.client.api.convert.Converter.OrmExtracted;
import com.basho.riak.client.api.convert.ConverterFactory;
import com.basho.riak.client.core.FutureOperation;
import com.basho.riak.client.core.RiakCluster;
import com.basho.riak.client.core.operations.StoreOperation;
import com.basho.riak.client.core.RiakFuture;
import com.basho.riak.client.api.commands.RiakOption;
import com.basho.riak.client.core.util.BinaryValue;
import java.util.HashMap;
import java.util.Map;
import com.basho.riak.client.core.query.Location;
import com.basho.riak.client.core.query.Namespace;
import com.fasterxml.jackson.core.type.TypeReference;
/**
* Command used to store a value in Riak.
*
*
* To store a value in Riak you supply a {@link com.basho.riak.client.core.query.Location}
* and an object to store. The object may be an instance of {@link com.basho.riak.client.core.query.RiakObject}
* or your own POJO. In the case of a POJO the default serialization uses the Jackson JSON library
* to store your object as JSON in Riak.
*
* {@code
* Namespace ns = new Namespace("my_type","my_bucket");
* Location loc = new Location(ns, "my_key");
* RiakObject ro = new RiakObject();
* ro.setValue(BinaryValue.create("This is my value"));
* StoreValue sv =
* new StoreValue.Builder(ro).withLocation(loc).build();
* StoreValue.Response response = client.execute(sv);}
*
*
* All operations can called async as well.
*
* {@code
* ...
* RiakFuture future = client.executeAsync(sv);
* ...
* future.await();
* if (future.isSuccess())
* {
* ...
* }}
*
* @author Dave Rusek
* @since 2.0
*/
public final class StoreValue extends GenericRiakCommand.GenericRiakCommandWithSameInfo
{
private final Namespace namespace;
private final BinaryValue key;
private final Map, Object> options = new HashMap<>();
private final Object value;
private final TypeReference> typeReference;
private final VClock vclock;
StoreValue(Builder builder)
{
this.options.putAll(builder.options);
this.namespace = builder.namespace;
this.key = builder.key;
this.value = builder.value;
this.typeReference = builder.typeReference;
this.vclock = builder.vclock;
}
@Override
protected Response convertResponse(FutureOperation request,
StoreOperation.Response coreResponse)
{
Location loc = request.getQueryInfo();
if (coreResponse.hasGeneratedKey())
{
loc = new Location(loc.getNamespace(), coreResponse.getGeneratedKey());
}
return new Response.Builder()
.withValues(coreResponse.getObjectList())
.withGeneratedKey(loc.getKey())
.withLocation(loc) // for ORM
.build();
}
@Override
protected RiakFuture executeAsync(RiakCluster cluster)
{
return super.executeAsync(cluster);
}
@SuppressWarnings("unchecked")
@Override
protected StoreOperation buildCoreOperation()
{
Converter converter;
if (typeReference == null)
{
converter = ConverterFactory.getInstance().getConverter(value.getClass());
}
else
{
converter = ConverterFactory.getInstance().getConverter(typeReference);
}
final OrmExtracted orm = converter.fromDomain(value, namespace, key);
// If there's no vector clock in the object, use one possibly given via
// the builder.
if (orm.getRiakObject().getVClock() == null)
{
orm.getRiakObject().setVClock(vclock);
}
StoreOperation.Builder builder;
if (orm.hasKey())
{
Location loc = new Location(orm.getNamespace(), orm.getKey());
builder = new StoreOperation.Builder(loc);
}
else
{
builder = new StoreOperation.Builder(orm.getNamespace());
}
builder.withContent(orm.getRiakObject());
for (Map.Entry, Object> opPair : options.entrySet())
{
RiakOption> option = opPair.getKey();
if (option == Option.TIMEOUT)
{
builder.withTimeout((Integer) opPair.getValue());
}
else if (option == Option.RETURN_HEAD)
{
builder.withReturnHead((Boolean) opPair.getValue());
}
else if (option == Option.ASIS)
{
builder.withAsis((Boolean) opPair.getValue());
}
else if (option == Option.DW)
{
builder.withDw(((Quorum) opPair.getValue()).getIntValue());
}
else if (option == Option.IF_NONE_MATCH)
{
builder.withIfNoneMatch((Boolean) opPair.getValue());
}
else if (option == Option.IF_NOT_MODIFIED)
{
builder.withIfNotModified((Boolean) opPair.getValue());
}
else if (option == Option.N_VAL)
{
builder.withNVal((Integer) opPair.getValue());
}
else if (option == Option.PW)
{
builder.withPw(((Quorum) opPair.getValue()).getIntValue());
}
else if (option == Option.SLOPPY_QUORUM)
{
builder.withSloppyQuorum((Boolean) opPair.getValue());
}
else if (option == Option.W)
{
builder.withW(((Quorum) opPair.getValue()).getIntValue());
}
else if (option == Option.RETURN_BODY)
{
builder.withReturnBody((Boolean) opPair.getValue());
}
}
return builder.build();
}
/**
* Options For controlling how Riak performs the store operation.
*
* These options can be supplied to the {@link StoreValue.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 final static class Option extends RiakOption
{
/**
* Write Quorum.
* How many replicas to write to before returning a successful response.
*/
public static final Option W = new Option<>("W");
/**
* Durable Write Quorum.
* How many replicas to commit to durable storage before returning a successful response.
*/
public static final Option DW = new Option<>("DW");
/**
* Primary Write Quorum.
* How many primary nodes must be up when the write is attempted.
*/
public static final Option PW = new Option<>("PW");
/**
* If Not Modified.
* Update the value only if the vclock in the supplied object matches the one in the database.
*/
public static final Option IF_NOT_MODIFIED = new Option<>("IF_NOT_MODIFIED");
/**
* If None Match.
* Store the value only if this bucket/key combination are not already defined.
*/
public static final Option IF_NONE_MATCH = new Option<>("IF_NONE_MATCH");
/**
* Return Body.
* Return the object stored in Riak. Note this will return all siblings.
*/
public static final Option RETURN_BODY = new Option<>("RETURN_BODY");
/**
* Return Head.
* Like {@link #RETURN_BODY} except that the value(s) in the object are blank to
* avoid returning potentially large value(s).
*/
public static final Option RETURN_HEAD = new Option<>("RETURN_HEAD");
/**
* 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 ASIS = new Option<>("ASIS");
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);
}
}
public static class Response extends KvResponseBase
{
private final BinaryValue generatedKey;
Response(Init> builder)
{
super(builder);
this.generatedKey = builder.generatedKey;
}
public boolean hasGeneratedKey()
{
return generatedKey != null;
}
public BinaryValue getGeneratedKey()
{
return generatedKey;
}
protected static abstract class Init> extends KvResponseBase.Init
{
private BinaryValue generatedKey;
T withGeneratedKey(BinaryValue generatedKey)
{
this.generatedKey = generatedKey;
return self();
}
}
static class Builder extends Init
{
@Override
protected Builder self()
{
return this;
}
@Override
Response build()
{
return new Response(this);
}
}
}
/**
* Used to construct a StoreValue command.
*/
public static class Builder
{
private final Map, Object> options = new HashMap<>();
private final Object value;
private Namespace namespace;
private BinaryValue key;
private TypeReference> typeReference;
private VClock vclock;
/**
* Construct a Builder for a StoreValue command.
*
* Prior to storing the object, it's raw type (class) will
* be used to retrieve a converter from the {@link com.basho.riak.client.api.convert.ConverterFactory}.
* For anything other than a RiakObject this is the {@link com.basho.riak.client.api.convert.JSONConverter}
* by default.
*
* @param value The object to be stored in Riak.
*/
public Builder(Object value)
{
this.value = value;
}
/**
* Construct a Builder for a StoreValue command.
*
* Prior to storing the object, the supplied TypeReference will
* be used to retrieve a converter from the {@link com.basho.riak.client.api.convert.ConverterFactory}.
* For anything other than a RiakObject this is the {@link com.basho.riak.client.api.convert.JSONConverter}
* by default.
*
* @param value The object to be stored in Riak.
* @param typeReference the TypeReference for the object.
*/
public Builder(Object value, TypeReference> typeReference)
{
this.value = value;
this.typeReference = typeReference;
}
/**
* Set the location to store the object.
*
* When storing a RiakObject or a POJO that does not have annotations for
* the bucket and key, a {@link com.basho.riak.client.core.query.Location}
* must be provided.
*
* @param location the location to store the object in Riak.
* @return a reference to this object.
*/
public Builder withLocation(Location location)
{
this.namespace = location.getNamespace();
this.key = location.getKey();
return this;
}
/**
* Set the namespace to store the object.
*
* When storing a POJO that does not have an annotation for the
* bucket type and bucket, a {@link com.basho.riak.client.core.query.Namespace}
* must be supplied.
*
* @param namespace The namespaec to store the object.
* @return a reference to this object.
*/
public Builder withNamespace(Namespace namespace)
{
this.namespace = namespace;
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;
}
/**
* 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, T value)
{
options.put(option, value);
return this;
}
/**
* Set the vector clock.
*
* When storing core Java types ({@code HashMap},
* {@code ArrayList},{@code String}, etc) or non-annotated POJOs this
* method allows you to specify the vector clock retrieved from a
* prior fetch operation.
*
* @param vclock The vector clock to send to Riak.
* @return a reference to this object.
*/
public Builder withVectorClock(VClock vclock)
{
this.vclock = vclock;
return this;
}
/**
* Construct the StoreValue command.
* @return the new StoreValue command.
*/
public StoreValue build()
{
return new StoreValue(this);
}
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + (namespace != null ? namespace.hashCode() : 0);
result = prime * result + (key != null ? key.hashCode() : 0);
result = prime * result + options.hashCode();
result = prime * result + (value != null ? value.hashCode() : 0);
result = prime * result + (typeReference != null ? typeReference.hashCode() : 0);
result = prime * result + (vclock != null ? vclock.hashCode() : 0);
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof StoreValue))
{
return false;
}
final StoreValue other = (StoreValue) obj;
if (this.namespace != other.namespace && (this.namespace == null || !this.namespace.equals(other.namespace)))
{
return false;
}
if (this.key != other.key && (this.key == null || !this.key.equals(other.key)))
{
return false;
}
if (this.options != other.options && (this.options == null || !this.options.equals(other.options)))
{
return false;
}
if (this.value != other.value && (this.value == null || !this.value.equals(other.value)))
{
return false;
}
if (this.typeReference != other.typeReference && (this.typeReference == null || !this.typeReference.equals(other.typeReference)))
{
return false;
}
if (this.vclock != other.vclock && (this.vclock == null || !this.vclock.equals(other.vclock)))
{
return false;
}
return true;
}
@Override
public String toString()
{
return String.format("{namespace: %s, key: %s, options: %s, value: %s,"
+ " typeReference: %s, vclock: %s}", namespace, key, options,
value, typeReference, vclock);
}
}