Java client API

Russell Brown russell.brown at mac.com
Wed Mar 23 18:08:44 EDT 2011


Thanks for the reply and thoughts, mine below inline.

On 23 Mar 2011, at 20:21, Kresten Krab Thorup wrote:

> From the client side, the moniker RiakObject is actually not too good.  In technical terms, it is of cause a riak_object  - but to a Java programmer, it doesn't feel right for it to have that name.  It's more like a KeyValueHolder, a RiakEntry (makes you think of Map.Entry), or something like that.  I'll vote for calling it RiakEntry, or just plain Entry (we have name spaces in Java, you know...)

Agree, agree, agree. Originally I had Riak, Bucket and Entry, honest I did. I even considered implementing Map and Map.Entry for Bucket and RiakObject but that was a step too far. I don't know why I toned it down. That'll teach me to have some faith, eh? Nice to be validated, but I prefer RiakEntry, I know we have name spaces but you don't see that half way down a page of code so a little verbosity in naming helps readability.

> It is hard to convey that it is important to get one of these "riak objects", update it, and stash it back in there.  I.e. the fact that a RiakEntry has the "optimistic concurrency state" (in popular speek) needed to later do the update.  

I  had a crack at implementing RiakEntry/Object today. Only the value, content type (which go hand in hand) and (Riak)Links were mutable, which fits with this quite well. 

> One naturally just want to create a new one and put into the store; and that aspect should perhaps be hinted in the name of this core class, and in the flow of the API.
> 
> Perhaps, for this very reason, store() should be an operation *directly on the RiakEntry*; and then guide people by the way these are obtained.
> 
> I like the idea of modeling buckets explicitly, but then why not have store method on the RiakEntry?

The only thing that worries me here is the tendency towards an ORM and all the conceptual weight/horror with (eg. Hibernate's) sessions and detachment. It might be mixing metaphors. Is it not better to be upfront that an entry is a thing and a bucket is the thing you put it in?


> Anyway, here is some sample code we can discuss from
> 
>     Riak c = ...;  // probably some ugly factory pattern to create a RiakClient here //

So far I have just been coding with constructors for the 2 adapters (HTTP/PBC) but when there is to an SPI for adding new clients then there will be a factory, sorry.

> 
>     Bucket b = c.get("people");
> 
>     // example 1
>     Entry e = b.get("russelb");   // does GET /riak/people/russeldb
>     e.set("application/json", "{ name: \"Russel Brown\" }" );
>     e.store();
> 
> Then, have a special method to create new entries:
> 
>     // example 2
>     Entry e2 = b.create("krab");     // does not issue GET /riak/people/krab
>     b.set("Kresten Krab Thorup"); // implies text/plain;charset=utf-8
>     b.store();
> 
> The latter (example 2) would issue a "PUT" w/no vector clock; whereas the former (example 1) automatically grabs the vector clock from the GET.  If you sure Bucket.get("no-such-key") then the only "harm done" is that you spent an extra round trip to the server trying to find the VC for no-such-key.

The idea of a separate get/create on the bucket is great and encodes all that complexity about vclocks without exposing it. Awesome. Leads nicely into the next set of problems too (conflict resolution.)

I think that idea alone solves a bunch of problems I was having with riak object creation. I hope that I can take this (and Jon's ideas (just read them, too)) and quickly push some code incorporating them.

I need to add an example of using this (unimplemented) API as part of the repo and I'll get on with that.

Thank you.

> 
> In fluent style, this would be
> 
>     c.getBucket("people").get("krab").set("Kresten Crap Throwup").store();
> 
>     // and/or
> 
>     c.get("people", "krab").set("XXX").store();
> 
> Which captures the flow that the vector clock needs to be there for the store.
> 
> Likewise, this will make it much more sound to delete things, because you also need the entry (includin gth VC) to delete an object properly
> 
> 	bucket.get("krab").delete()
> 
> makes a lot more sense than
> 
>        bucket.create("krab").delete()
> 
> WHICH IS GREAT!  Because we want people to pass in VC to delete operations ... those should really also be replayable, which I am sure they will be one day :-)
> 
> 
> Kresten
> 
> 
> 
> On Mar 23, 2011, at 11:05 , Russell Brown wrote:
> 
>> Hi,
>> I'm trying to make the Java client easier to use and less tied to underlying implementation so I've started designing a new API. 
>> 
>> I've put some interfaces up at https://github.com/russelldb/riak-java-client-api
>> 
>> I'd really appreciate any comments you may have.
>> 
>> My intention is to adapt the existing client(s) to these interfaces and deprecate the old client API gradually (so there will be backward compatibility for a few releases.) I'll also be reusing the existing client implementations underneath the API, this isn't a wholesale re-write. 
>> 
>> I hope you can take some time to let me know what you think. I'll put my thickest skin on.
>> 
>> Many thanks
>> 
>> Russell
>> 
>> PS It is all maven'd up so just clone and mvn eclipse:eclipse if you want to get a good look.
>> <ATT00001..txt>
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.basho.com/pipermail/riak-users_lists.basho.com/attachments/20110323/5cfc25d5/attachment.html>


More information about the riak-users mailing list