Search code examples
javariak

Determine Location of RiakObject during conflict resolution


I am in the process of migrating my Java code from Riak Client 1.4 to Riak Client 2.0.

I'm storing a BinaryValue in Riak 2.0, encapsulated in a RiakObject. I need to provide my own ConflictResolver to deal with siblings, but in order to do that I need to pull in other data. This data is derived from the key of the stored object.

In Riak 1.4, I used IRiakObject, which exposed getKey(). RiakObject of Riak 2.0 does not offer this.

How is it possible to determine the Location (specifically the key) of the object during ConflictResolver.resolve(List<RiakObject> siblings)?


Solution

  • Not sure if this is the best approach, but it seems to work:

    1. Create a POJO as a container for the binary data. Annotate a String field with @RiakKey:

      public class Chunk {
      
          @RiakKey
          public String   chunkId;
      
          public byte[]   data;
      }
      
    2. Create a custom converter:

      import com.basho.riak.client.api.convert.ConversionException;
      import com.basho.riak.client.api.convert.Converter;
      import com.basho.riak.client.core.util.BinaryValue;
      public class ChunkConverter extends Converter<Chunk> {
      
          public ChunkConverter() {
              super(Chunk.class);
          }
      
          public Chunk toDomain(BinaryValue val, String contentType) throws ConversionException {
              Chunk chunk = newDomainInstance();
              chunk.data = val.getValue();
          }
      
          public ContentAndType fromDomain(Chunk chunk) throws ConversionException {
              return new ContentAndType(BinaryValue.unsafeCreate(chunk.data), "application/octet-stream");
          }
      }
      
    3. Register the converter from #2 for the class from #1:

      ConverterFactory.getInstance().registerConverterForClass(Chunk.class, new ChunkConverter());
      
    4. Create a conflict resolver for the class from #1:

      public class ChunkConflictResolver implements ConflictResolver<Chunk> {
      
          public Chunk resolve(List<Chunk> siblings) throws UnresolvedConflictException {
              if (siblings == null) {
                  return null;
              }
              Chunk oneChunk = siblings.get(0);
              // finally, the key!
              String key = oneChunk.chunkId;
              ...
          }
      }
      
    5. Register the new conflict resolver from #4 for the class from #1:

      ConflictResolverFactory.getInstance().registerConflictResolver(Chunk.class, new ChunkResolver());
      
    6. When fetching the object from Riak, specify the class from #1 as type of value:

      Location loc = new Location(...);
      FetchValue op = new FetchValue.Builder(loc).build();
      Chunk chunk = riakClient.execute(op).getValue(Chunk.class);
      

    During the conversion, the context of the object is transferred, observing the annotations. The custom converter only needs to transfer the value-part of the data.