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

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

There is a newer version: 2.1.1
Show 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.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.RiakCluster;
import com.basho.riak.client.core.operations.StoreOperation;
import com.basho.riak.client.api.RiakCommand;
import com.basho.riak.client.core.RiakFuture;
import com.basho.riak.client.api.commands.CoreFutureAdapter;
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;

 /*
 * @author Dave Rusek 
 * @since 2.0
 */
public final class StoreValue extends RiakCommand
{
    private final Namespace namespace;
    private final BinaryValue key;
    private final Map, Object> options =
	    new HashMap, Object>();
    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;
    }

    
    @SuppressWarnings("unchecked")
    @Override
    protected RiakFuture executeAsync(RiakCluster cluster)
    {
        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);
        }
        
        RiakFuture coreFuture =
            cluster.execute(buildCoreOperation(orm));
        
        CoreFutureAdapter future = 
            new CoreFutureAdapter(coreFuture)
            {
                @Override
                protected Response convertResponse(StoreOperation.Response coreResponse)
                {
                    Namespace ns = orm.getNamespace();
                    BinaryValue key = orm.getKey();
                    if (coreResponse.hasGeneratedKey())
                    {
                        key = coreResponse.getGeneratedKey();
                    }
                    
                    Location loc = new Location(ns, key);
                    
                    return new Response.Builder()
                        .withValues(coreResponse.getObjectList())
                        .withGeneratedKey(coreResponse.getGeneratedKey())
                        .withLocation(loc) // for ORM
                        .build();
                }

                @Override
                protected Location convertQueryInfo(Location coreQueryInfo)
                {
                    return coreQueryInfo;
                }
                
            };
        coreFuture.addListener(future);
        return future;
    }
    
    private StoreOperation buildCoreOperation(OrmExtracted orm)
    {
        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; } /** * @ExcludeFromJavadoc */ 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); } } } public static class Builder { private final Map, Object> options = new HashMap, Object>(); private final Object value; private Namespace namespace; private BinaryValue key; private TypeReference typeReference; private VClock vclock; public Builder(Object value) { this.value = value; } public Builder(Object value, TypeReference typeReference) { this.value = value; this.typeReference = typeReference; } public Builder withLocation(Location location) { this.namespace = location.getNamespace(); this.key = location.getKey(); return this; } 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; } 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; } public StoreValue build() { return new StoreValue(this); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy