Fixes to RAMCloud Java bindings

- Fix FindBugs warnings
- Change RejectRule to be a static class
- Change nested Exception classes to be static classes
- Changed RejectRules methods to clarify its roll, and allow chaining
- Represent RejectRules flags as bits in int to decrease number of JNI crossing
- multiWrite value size parameter needs to be int to match C++ decl.
- Add conditional read, write, remove
- Deprecate writeRule method
- Fixed RejectRules related Exception class inheritance
- Declare throws on conditional operations

Change-Id: I07c3a2111d06ca051a29415224d59b9bfa7a4ddb
diff --git a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java
index ad519c8..5b5cea0 100644
--- a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java
+++ b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudGraph.java
@@ -25,7 +25,6 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -57,6 +56,7 @@
 
 import edu.stanford.ramcloud.JRamCloud;
 import edu.stanford.ramcloud.JRamCloud.MultiWriteObject;
+import edu.stanford.ramcloud.JRamCloud.RejectRules;
 
 public class RamCloudGraph implements IndexableGraph, KeyIndexableGraph, TransactionalGraph, Serializable {
     private final static Logger log = LoggerFactory.getLogger(RamCloudGraph.class);
@@ -247,9 +247,9 @@
 	    }
 	    vertices.add(v);
 	}
-	
+
 	MultiWriteObject mwo = new MultiWriteObject(vertices.size()*2);
-		
+
 	for (int i=0; i < vertices.size(); i++) {
 	    RamCloudVertex v = vertices.get(i);
 	    mwo.setObject(i*2, vertTableId, v.rcKey, ByteBuffer.allocate(0).array(), null);
@@ -320,8 +320,8 @@
 		    log.error("Got an exception while serializing element's property map", e);
 		    return;
 		}
-		JRamCloud.RejectRules rules = rcClient.new RejectRules();
-		rules.setNeVersion(instanceEntry.version);
+		JRamCloud.RejectRules rules = new RejectRules();
+		rules.rejectIfNeVersion(instanceEntry.version);
 		try {
 		    rcClient.writeRule(instanceTableId, "nextInstanceId".getBytes(), rcValue, rules);
 		    instanceId = curInstanceId;
diff --git a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudIndex.java b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudIndex.java
index 634df25..e62b2d4 100644
--- a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudIndex.java
+++ b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudIndex.java
@@ -38,6 +38,7 @@
 import com.tinkerpop.blueprints.impls.ramcloud.RamCloudGraphProtos.IndexBlob.Builder;
 
 import edu.stanford.ramcloud.JRamCloud;
+import edu.stanford.ramcloud.JRamCloud.RejectRules;
 
 // FIXME Index instance should be representing an Index table, not a IndexTable K-V pair
 public class RamCloudIndex<T extends Element> implements Index<T>, Serializable {
@@ -91,8 +92,8 @@
 	    PerfMon pm = PerfMon.getInstance();
 	    try {
 		JRamCloud rcClient = graph.getRcClient();
-		JRamCloud.RejectRules rules = rcClient.new RejectRules();
-		rules.setExists();
+		JRamCloud.RejectRules rules = new RejectRules();
+		rules.rejectIfExists();
 
 		pm.indexwrite_start("RamCloudIndex create()");
 		rcClient.writeRule(tableId, rcKey, ByteBuffer.allocate(0).array(), rules);
diff --git a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudVertex.java b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudVertex.java
index 03c4ba3..a6a5320 100644
--- a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudVertex.java
+++ b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudVertex.java
@@ -256,11 +256,11 @@
 				}
 
 				EdgeListProtoBuf edgeList = buildProtoBufFromEdgeSet(edges);
-				JRamCloud.RejectRules rules = rcClient.new RejectRules();
+				JRamCloud.RejectRules rules = new RejectRules();
 				if ( expected_version == 0L ) {
-					rules.setExists();
+					rules.rejectIfExists();
 				} else {
-					rules.setNeVersion(expected_version);
+					rules.rejectIfNeVersion(expected_version);
 				}
 				pm.write_start("RAMCloudVertex updateEdgeAdjList()");
 				long updated_version = rcClient.writeRule(graph.vertTableId, rcKey, edgeList.toByteArray(), rules);
@@ -490,7 +490,7 @@
 		// TODO: Existence check costs extra (presently 2 reads), could use option to turn on/off
 		if (!exists()) {
 			PerfMon pm = PerfMon.getInstance();
-			JRamCloud vertTable = graph.getRcClient();			
+			JRamCloud vertTable = graph.getRcClient();
 			MultiWriteObject mwo = new MultiWriteObject(2);
 			mwo.setObject(1, graph.vertTableId, rcKey, ByteBuffer.allocate(0).array(), null);
 			mwo.setObject(2, graph.vertPropTableId, rcKey, ByteBuffer.allocate(0).array(), null);
diff --git a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudWrite.java b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudWrite.java
index 69eed7f..030d088 100644
--- a/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudWrite.java
+++ b/src/main/java/com/tinkerpop/blueprints/impls/ramcloud/RamCloudWrite.java
@@ -1,6 +1,8 @@
 package com.tinkerpop.blueprints.impls.ramcloud;
 
 import edu.stanford.ramcloud.JRamCloud;
+import edu.stanford.ramcloud.JRamCloud.RejectRules;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -10,14 +12,14 @@
 	INDEXWRITE
     }
     private final static Logger log = LoggerFactory.getLogger(RamCloudGraph.class);
-    
+
     public static boolean writeWithRules(long tableId, byte[] rcKey, byte[] rcValue, long expectedVersion, RamCloudGraph graph, PerfMonEnum perfMonKind) {
-	JRamCloud.RejectRules rules = graph.getRcClient().new RejectRules();
+	JRamCloud.RejectRules rules = new RejectRules();
 
 	if (expectedVersion == 0) {
-	    rules.setExists();
+	    rules.rejectIfExists();
 	} else {
-	    rules.setNeVersion(expectedVersion);
+	    rules.rejectIfNeVersion(expectedVersion);
 	}
 
 	PerfMon pm = PerfMon.getInstance();
diff --git a/src/main/java/edu/stanford/ramcloud/JRamCloud.java b/src/main/java/edu/stanford/ramcloud/JRamCloud.java
index 63b0748..83fdd44 100644
--- a/src/main/java/edu/stanford/ramcloud/JRamCloud.java
+++ b/src/main/java/edu/stanford/ramcloud/JRamCloud.java
@@ -14,6 +14,7 @@
  */
 
 package edu.stanford.ramcloud;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.LinkedList;
 
@@ -35,6 +36,8 @@
         System.loadLibrary("edu_stanford_ramcloud_JRamCloud");
     }
 
+    public static final long VERSION_NONEXISTENT = 0L;
+
     /// Pointer to the underlying C++ RAMCloud object associated with this
     /// object.
     private long ramcloudObjectPointer = 0;
@@ -42,85 +45,106 @@
     /**
      * See src/RejectRules.h.
      */
-    public class RejectRules {
-	private long givenVersion;
-        private boolean doesntExist;
-        private boolean exists;
-        private boolean versionLeGiven;
-        private boolean versionNeGiven;
+    public static class RejectRules {
+        // these needs to be in sync with JNI code;
+        public static final int DoesntExist = 1;
+        public static final int Exists = 1 << 1;
+        public static final int VersionLeGiven = 1 << 2;
+        public static final int VersionNeGiven = 1 << 3;
+
+        protected long givenVersion;
+        protected int flags;
 
         public RejectRules() {
-            this.givenVersion = -1;
-            this.exists = this.doesntExist = this.versionLeGiven = this.versionNeGiven = false;
+            clear();
         }
 
-        public void setLeVersion(long version) {
+        public void clear() {
+            this.givenVersion = VERSION_NONEXISTENT;
+            this.flags = 0x0;
+        }
+
+        public RejectRules set(int flags, long version) {
+            this.flags = flags;
+            this.givenVersion = version;
+            return this;
+        }
+
+        public RejectRules set(int flags) {
+            return set(flags,VERSION_NONEXISTENT);
+        }
+
+        public RejectRules rejectIfLeVersion(long version) {
             setVersion(version);
-            this.versionLeGiven = true;
+            this.flags |= VersionLeGiven;
+            return this;
         }
 
-        public void setExists() {
-            this.exists = true;
+        public RejectRules rejectIfExists() {
+            this.flags |= Exists;
+            return this;
         }
 
-        public void setDoesntExists() {
-            this.doesntExist = true;
+        public RejectRules rejectIfDoesntExists() {
+            this.flags |= DoesntExist;
+            return this;
         }
 
-        public void setNeVersion(long version) {
+        public RejectRules rejectIfNeVersion(long version) {
             setVersion(version);
-            this.versionNeGiven = true;
+            this.flags |= VersionNeGiven;
+            return this;
         }
 
         private void setVersion(long version) {
             this.givenVersion = version;
-        }	
+        }
     }
-    
+
     public static class MultiReadObject {
         public long[] tableId;
         public byte[] key[];
-	public short[] keyLength;
-        
+        public short[] keyLength;
+
         public MultiReadObject(int size){
             this.tableId = new long[size];
             this.key = new byte[size][];
-	    this.keyLength = new short[size];
+            this.keyLength = new short[size];
         }
-	
+
 	public void setObject(int num, long tableId, byte key[]){
             this.tableId[num] = tableId;
             this.key[num] = key;
-	    this.keyLength[num] = (short) this.key[num].length;
+            this.keyLength[num] = (short) this.key[num].length;
 	}
     }
-    
+
     public static class MultiWriteObject {
         public long[] tableId;
         public byte[] key[];
-	public short[] keyLength;
+        public short[] keyLength;
         public byte[] value[];
-	public short[] valueLength;
+        public int[] valueLength;
         public RejectRules[] rules;
 
         public MultiWriteObject(int size) {
             this.tableId = new long[size];
             this.key = new byte[size][];
-	    this.keyLength = new short[size];
+            this.keyLength = new short[size];
             this.value = new byte[size][];
-	    this.valueLength = new short[size];
+            this.valueLength = new int[size];
             this.rules = new RejectRules[size];
         }
-	
+
 	public void setObject(int num, long tableId, byte key[], byte value[], RejectRules rules){
 	    this.tableId[num] = tableId;
 	    this.key[num] = key;
 	    this.keyLength[num] = (short) key.length;
 	    this.value[num] = value;
-	    this.valueLength[num] = (short) value.length;
+	    this.valueLength[num] = value.length;
 	    this.rules[num] = rules;
 	}
-	
+
     }
 
     public static class MultiWriteRspObject {
@@ -159,27 +183,27 @@
         public String
         getKey()
         {
-            return new String(key);
+            return new String(key,StandardCharsets.UTF_8);
         }
 
         public String
         getValue()
         {
-            return new String(value);
+            return new String(value,StandardCharsets.UTF_8);
         }
 
         final public byte[] key;
         final public byte[] value;
         final public long version;
     }
-    
+
     public static class TableEnumeratorObject {
 	TableEnumeratorObject(Object[] _object, long _nextHash)
-        {
+	{
 	    object = _object;
 	    nextHash = _nextHash;
 	}
-	
+
 	final public Object[] object;
 	final public long nextHash;
     }
@@ -187,32 +211,32 @@
     public class TableEnumerator {
         private long tableEnumeratorObjectPointer = 0;
         private long ramCloudObjectPointer = 0;
-        
+
         public TableEnumerator(long tableId)
         {
             ramCloudObjectPointer = ramcloudObjectPointer;
             tableEnumeratorObjectPointer = init(tableId);
         }
-        
+
         private native long init(long tableId);
         public native boolean hasNext();
         public native Object next();
     }
 
     public class TableEnumerator2 {
-        
+
 	protected long tableId;
 	protected LinkedList<JRamCloud.Object> rcobjs = null;
 	protected long nextHash = 0;
 	protected boolean done = false;
-	
+
         public TableEnumerator2(long tableId)
         {
 	    this.tableId = tableId;
 	    rcobjs = new LinkedList<>();
         }
         public boolean hasNext() {
-	    if (rcobjs.isEmpty()) 
+	    if (rcobjs.isEmpty())
 	    {
 		if (done) {
 		    return false;
@@ -229,13 +253,13 @@
 	    }
 	    return true;
 	}
-	
-	public Object next() 
+
+	public Object next()
 	{
 	    return rcobjs.pop();
 	}
     }
-    
+
     /**
      * Connect to the RAMCloud cluster specified by the given coordinator's
      * service locator string. This causes the JNI code to instantiate the
@@ -265,7 +289,8 @@
      * object. The user really should have called disconnect, but in case
      * they did not, be sure to clean up after them.
      */
-    public void
+    @Override
+    protected void
     finalize()
     {
         System.err.println("warning: JRamCloud::disconnect() was not called " +
@@ -280,34 +305,36 @@
     public Object
     read(long tableId, String key)
     {
-        return read(tableId, key.getBytes());
+        return read(tableId, key.getBytes(StandardCharsets.UTF_8));
     }
 
     /**
      * Convenience read() wrapper that take a String key argument.
+     * @throws RejectRulesException
      */
     public Object
-    read(long tableId, String key, RejectRules rules)
+    read(long tableId, String key, RejectRules rules) throws RejectRulesException
     {
-        return read(tableId, key.getBytes(), rules);
+        return read(tableId, key.getBytes(StandardCharsets.UTF_8), rules);
     }
-    
+
     /**
      * Convenience remove() wrapper that take a String key argument.
      */
     public long
     remove(long tableId, String key)
     {
-        return remove(tableId, key.getBytes());
+        return remove(tableId, key.getBytes(StandardCharsets.UTF_8));
     }
 
     /**
      * Convenience remove() wrapper that take a String key argument.
+     * @throws RejectRulesException
      */
     public long
-    remove(long tableId, String key, RejectRules rules)
+    remove(long tableId, String key, RejectRules rules) throws RejectRulesException
     {
-        return remove(tableId, key.getBytes(), rules);
+        return remove(tableId, key.getBytes(StandardCharsets.UTF_8), rules);
     }
 
     /**
@@ -316,16 +343,17 @@
     public long
     write(long tableId, String key, String value)
     {
-        return write(tableId, key.getBytes(), value.getBytes());
+        return write(tableId, key.getBytes(StandardCharsets.UTF_8), value.getBytes(StandardCharsets.UTF_8));
     }
 
     /**
      * Convenience write() wrapper that take String key and value arguments.
+     * @throws RejectRulesException
      */
     public long
-    write(long tableId, String key, String value, RejectRules rules)
+    write(long tableId, String key, String value, RejectRules rules) throws RejectRulesException
     {
-        return write(tableId, key.getBytes(), value.getBytes(), rules);
+        return write(tableId, key.getBytes(StandardCharsets.UTF_8), value.getBytes(StandardCharsets.UTF_8), rules);
     }
 
     /**
@@ -335,19 +363,20 @@
     public long
     write(long tableId, String key, byte[] value)
     {
-        return write(tableId, key.getBytes(), value);
+        return write(tableId, key.getBytes(StandardCharsets.UTF_8), value);
     }
 
     /**
      * Convenience write() wrapper that takes a String key and a byte[] value
      * argument.
+     * @throws RejectRulesException
      */
     public long
-    write(long tableId, String key, byte[] value, RejectRules rules)
+    write(long tableId, String key, byte[] value, RejectRules rules) throws RejectRulesException
     {
-        return write(tableId, key.getBytes(), value, rules);
+        return write(tableId, key.getBytes(StandardCharsets.UTF_8), value, rules);
     }
-    
+
     private static native long connect(String coordinatorLocator);
     private static native void disconnect(long ramcloudObjectPointer);
 
@@ -356,79 +385,79 @@
     public native void dropTable(String name);
     public native long getTableId(String name);
     public native Object read(long tableId, byte[] key);
-    public native Object read(long tableId, byte[] key, RejectRules rules);
+    public native Object read(long tableId, byte[] key, RejectRules rules) throws RejectRulesException;
     public native Object[] multiRead(long[] tableId, byte[] keydata[], short[] keyDataSize, int requestNum);
     public native long remove(long tableId, byte[] key);
-    public native long remove(long tableId, byte[] key, RejectRules rules);
+    public native long remove(long tableId, byte[] key, RejectRules rules) throws RejectRulesException;
     public native long write(long tableId, byte[] key, byte[] value);
-    public native long write(long tableId, byte[] key, byte[] value, RejectRules rules);
+    public native long write(long tableId, byte[] key, byte[] value, RejectRules rules) throws RejectRulesException;
+    @Deprecated
     public native long writeRule(long tableId, byte[] key, byte[] value, RejectRules rules);
-    public native MultiWriteRspObject[] multiWrite(long[] tableId, byte[] key[], short[] keyDataSize, byte[] value[], short[] valueDataSize, int requestNum, RejectRules[] rules);
+    public native MultiWriteRspObject[] multiWrite(long[] tableId, byte[] key[], short[] keyDataSize, byte[] value[], int[] valueDataSize, int requestNum, RejectRules[] rules);
     public native TableEnumeratorObject getTableObjects(long tableId, long nextHash);
 
     /*
      * The following exceptions may be thrown by the JNI functions:
      */
 
-    public class TableDoesntExistException extends Exception {
+    public static class TableDoesntExistException extends RuntimeException {
         public TableDoesntExistException(String message)
         {
             super(message);
         }
     }
 
-    public class ObjectDoesntExistException extends Exception {
+    public static class ObjectDoesntExistException extends RejectRulesException {
         public ObjectDoesntExistException(String message)
         {
             super(message);
         }
     }
 
-    public class ObjectExistsException extends Exception {
+    public static class ObjectExistsException extends RejectRulesException {
         public ObjectExistsException(String message)
         {
             super(message);
         }
     }
 
-    public class WrongVersionException extends Exception {
+    public static class WrongVersionException extends RejectRulesException {
         public WrongVersionException(String message)
         {
             super(message);
         }
     }
-    
-    public class InvalidObjectException extends Exception {
+
+    public static class InvalidObjectException extends RuntimeException {
         public InvalidObjectException(String message) {
             super(message);
         }
     }
-    
-    public class RejectRulesException extends Exception {
+
+    public static class RejectRulesException extends Exception {
         public RejectRulesException(String message) {
             super(message);
         }
     }
-    
+
     public static void tableEnumeratorTest(JRamCloud ramcloud) {
         long startTime = 0;
         for (int x = 0 ; x < 2 ; x ++){
         for(int N = 1000; N < 10000; N += 1000) {
             long EnumerateTesttable = ramcloud.createTable("EnumerateTest");
             for(int i = 0 ; i < N ; ++i) {
-                String key = new Integer(i).toString();
-                ramcloud.write(EnumerateTesttable, key.getBytes(), "Hello, World!".getBytes());
+                String key = String.valueOf(i);
+                ramcloud.write(EnumerateTesttable, key.getBytes(StandardCharsets.UTF_8), "Hello, World!".getBytes(StandardCharsets.UTF_8));
             }
 
-            MultiReadObject mread[] = new MultiReadObject[N];
             long tableIdList[] = new long[N];
             byte[] keydata[] = new byte[N][];
             short keydataSize[] = new short[N];
-	    startTime = System.nanoTime();
+            startTime = System.nanoTime();
             for (int j = 0 ; j < N ; ++j) {
                 tableIdList[j] = EnumerateTesttable;
-                String key = new Integer(j).toString();
-                keydata[j] = key.getBytes();
+                String key = String.valueOf(j);
+                keydata[j] = key.getBytes(StandardCharsets.UTF_8);
                 keydataSize[j] = (short) keydata[j].length;
             }
             JRamCloud.Object out[] = ramcloud.multiRead(tableIdList, keydata, keydataSize, N);
@@ -448,13 +477,13 @@
                     System.out.println("tableEnumerator object: key = [" + tableEntry.getKey() + "], value = [" + tableEntry.getValue() + "]");
                 }
             }
-	    System.out.println("old TableEnumerator : " + N + " Time : " + (System.nanoTime()-startTime));
+            System.out.println("old TableEnumerator : " + N + " Time : " + (System.nanoTime()-startTime));
 
             startTime = System.nanoTime();
             JRamCloud.TableEnumerator2 tableEnum2 = ramcloud.new TableEnumerator2(EnumerateTesttable);
-	    while (tableEnum2.hasNext()) {
-		Object tableEntry2 = tableEnum2.next();
-		if (tableEntry2 != null) {
+            while (tableEnum2.hasNext()) {
+                Object tableEntry2 = tableEnum2.next();
+                if (tableEntry2 != null) {
                     System.out.println("tableEnumerator2 object: key = [" + tableEntry2.getKey() + "], value = [" + tableEntry2.getValue() + "]");
                 }
             }
@@ -492,15 +521,16 @@
         }
 
         ramcloud.write(tableId, "thisIsTheKey", "thisIsTheValue");
-        
+
         long before = System.nanoTime();
         for (int i = 0; i < 1000; i++) {
+            @SuppressWarnings("unused")
             JRamCloud.Object unused = ramcloud.read(tableId, "thisIsTheKey");
         }
         long after = System.nanoTime();
         System.out.println("Avg read latency: " +
             ((double)(after - before) / 1000 / 1000) + " usec");
-        
+
         // multiRead test
         long tableId4 = ramcloud.createTable("table4");
         System.out.println("table4 id " + tableId4);
@@ -516,9 +546,9 @@
 
 	MultiReadObject mr = new MultiReadObject(2);
 	MultiWriteObject mw = new MultiWriteObject(2);
-	
-	mr.setObject(0, tableId4, "object1-1".getBytes());
-	mr.setObject(1, tableId5, "object2-1".getBytes());
+
+	mr.setObject(0, tableId4, "object1-1".getBytes(StandardCharsets.UTF_8));
+	mr.setObject(1, tableId5, "object2-1".getBytes(StandardCharsets.UTF_8));
 
         JRamCloud.Object out[] = ramcloud.multiRead(mr.tableId, mr.key, mr.keyLength, 2);
         for (int i = 0 ; i < 2 ; i++){
@@ -527,12 +557,12 @@
         }
 
         for (int i = 0; i < 1000; i++) {
-            String key1 = "key1" + new Integer(i).toString();
-            String key2 = "key2" + new Integer(i).toString();
-	    
-	    mw.setObject(0, tableId4, key1.getBytes(), "v0-value".getBytes(), null);
-	    mw.setObject(1, tableId5, key2.getBytes(), "v1".getBytes(), null);
-      	    
+            String key1 = "key1" + String.valueOf(i);
+            String key2 = "key2" + String.valueOf(i);
+
+            mw.setObject(0, tableId4, key1.getBytes(StandardCharsets.UTF_8), "v0-value".getBytes(StandardCharsets.UTF_8), null);
+            mw.setObject(1, tableId5, key2.getBytes(StandardCharsets.UTF_8), "v1".getBytes(StandardCharsets.UTF_8), null);
+
             MultiWriteRspObject[] rsp = ramcloud.multiWrite(mw.tableId, mw.key, mw.keyLength, mw.value, mw.valueLength, 2, mw.rules);
             if (rsp != null) {
                 for (int j = 0; j < rsp.length; j++) {
@@ -541,20 +571,20 @@
             }
         }
         for (int i = 0; i < 1000; i++) {
-            String key1 = "key1" + new Integer(i).toString();
-            String key2 = "key2" + new Integer(i).toString();
+            String key1 = "key1" + String.valueOf(i);
+            String key2 = "key2" + String.valueOf(i);
 
-	    mr.setObject(0, tableId4, key1.getBytes());
-	    mr.setObject(1, tableId5, key2.getBytes());
-	    
+            mr.setObject(0, tableId4, key1.getBytes(StandardCharsets.UTF_8));
+            mr.setObject(1, tableId5, key2.getBytes(StandardCharsets.UTF_8));
+
             out = ramcloud.multiRead(mr.tableId, mr.key, mr.keyLength, 2);
             for (int j = 0; j < 2; j++) {
                 System.out.println("multi read object: key = [" + out[j].getKey() + "], value = [" + out[j].getValue() + "]");
             }
         }
 
-	tableEnumeratorTest(ramcloud);
-	
+        tableEnumeratorTest(ramcloud);
+
         ramcloud.dropTable("table4");
         ramcloud.dropTable("table5");
         ramcloud.dropTable("table6");
diff --git a/src/main/java/net/onrc/onos/datastore/RCObject.java b/src/main/java/net/onrc/onos/datastore/RCObject.java
index 77f5d15..009b584 100644
--- a/src/main/java/net/onrc/onos/datastore/RCObject.java
+++ b/src/main/java/net/onrc/onos/datastore/RCObject.java
@@ -24,7 +24,6 @@
 import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
 import edu.stanford.ramcloud.JRamCloud.ObjectExistsException;
 import edu.stanford.ramcloud.JRamCloud.RejectRules;
-import edu.stanford.ramcloud.JRamCloud.TableEnumerator;
 import edu.stanford.ramcloud.JRamCloud.TableEnumerator2;
 import edu.stanford.ramcloud.JRamCloud.WrongVersionException;
 
@@ -150,7 +149,7 @@
 
     protected void serializeAndSetValue(Kryo kryo,
 	    Map<Object, Object> javaObject) {
-	
+
 
 	// value
 	byte[] rcTemp = new byte[1024 * 1024];
@@ -176,7 +175,7 @@
 	    Class<T> type) {
 	if (this.value == null)
 	    return null;
-	
+
 	Input input = new Input(this.value);
 	T map = kryo.readObject(input, type);
 	this.propertyMap = map;
@@ -307,7 +306,7 @@
 	JRamCloud rcClient = RCClient.getClient();
 
 	final int reqs = req.size();
-	
+
 	MultiReadObject multiReadObjects = new MultiReadObject(req.size());
 
 	// setup multi-read operation
@@ -426,19 +425,18 @@
 	    WriteOp op = ops.get(i);
 	    RCObject obj = op.getObject();
 
-	    // FIXME JRamCloud.RejectRules definition is messed up
-	    RejectRules rules = rcClient.new RejectRules();
+	    RejectRules rules = new RejectRules();
 
 	    switch (op.getOp()) {
 	    case CREATE:
-		rules.setExists();
+		rules.rejectIfExists();
 		break;
 	    case FORCE_CREATE:
 		// no reject rule
 		break;
 	    case UPDATE:
-		rules.setDoesntExists();
-		rules.setNeVersion(obj.getVersion());
+		rules.rejectIfDoesntExists();
+		rules.rejectIfNeVersion(obj.getVersion());
 		break;
 	    }
 	    multiWriteObjects.setObject(i, obj.getTableId(), obj.getKey(), obj.getValue(), rules);
@@ -465,7 +463,7 @@
 
 	return fail_exists;
     }
-   
+
     public static abstract class ObjectIterator<E extends RCObject> implements
 	    Iterator<E> {
 
@@ -491,7 +489,7 @@
 //	    obj.setValueAndDeserialize(o.value, o.version);
 //	    return obj;
 //	}
-	
+
 	@Deprecated
 	@Override
 	public void remove() {
diff --git a/src/main/java/net/onrc/onos/datastore/RCTable.java b/src/main/java/net/onrc/onos/datastore/RCTable.java
index e74a5a4..0617bf7 100644
--- a/src/main/java/net/onrc/onos/datastore/RCTable.java
+++ b/src/main/java/net/onrc/onos/datastore/RCTable.java
@@ -9,6 +9,7 @@
 import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
 import edu.stanford.ramcloud.JRamCloud.ObjectExistsException;
 import edu.stanford.ramcloud.JRamCloud.RejectRules;
+import edu.stanford.ramcloud.JRamCloud.RejectRulesException;
 import edu.stanford.ramcloud.JRamCloud.WrongVersionException;
 
 /**
@@ -106,16 +107,21 @@
 
 	JRamCloud rcClient = RCClient.getClient();
 
-	RejectRules rules = rcClient.new RejectRules();
-	rules.setExists();
+	RejectRules rules = new RejectRules();
+	rules.rejectIfExists();
 
-	long updated_version = rcClient.writeRule(this.rcTableId, key, value,
-	        rules);
-	return updated_version;
+	try {
+	    return rcClient.write(this.rcTableId, key, value, rules);
+	} catch (ObjectExistsException e) {
+	    throw e;
+	} catch (RejectRulesException e) {
+	    log.error("Unexpected RejectRulesException", e);
+	    return JRamCloud.VERSION_NONEXISTENT;
+	}
     }
 
     /**
-     * Create a Key-Value entry on table, without existance checking.
+     * Create a Key-Value entry on table, without existence checking.
      *
      * @param key
      * @param value
@@ -140,13 +146,17 @@
 
 	JRamCloud rcClient = RCClient.getClient();
 
-	// FIXME underlying JRamCloud cannot detect "not exist"
-	// RejectRules rules = rcClient.new RejectRules();
-	// rules.setDoesntExists();
-	// JRamCloud.Object rcObj = rcClient.read(this.rcTableId, key, rules);
-	JRamCloud.Object rcObj = rcClient.read(this.rcTableId, key);
-
-	return new Entry(rcObj.key, rcObj.value, rcObj.version);
+	RejectRules rules = new RejectRules();
+	rules.rejectIfDoesntExists();
+	try {
+	    JRamCloud.Object rcObj = rcClient.read(this.rcTableId, key, rules);
+	    return new Entry(rcObj.key, rcObj.value, rcObj.version);
+	} catch (ObjectDoesntExistException e) {
+	    throw e;
+	} catch (RejectRulesException e) {
+	    log.error("Unexpected RejectRulesException", e);
+	    return null;
+	}
     }
 
     /**
@@ -165,13 +175,18 @@
 
 	JRamCloud rcClient = RCClient.getClient();
 
-	RejectRules rules = rcClient.new RejectRules();
-	rules.setDoesntExists();
-	rules.setNeVersion(version);
+	RejectRules rules = new RejectRules();
+	rules.rejectIfDoesntExists();
+	rules.rejectIfNeVersion(version);
 
-	long updated_version = rcClient.writeRule(this.rcTableId, key, value,
-	        rules);
-	return updated_version;
+	try {
+	    return rcClient.write(this.rcTableId, key, value, rules);
+	} catch (ObjectDoesntExistException|WrongVersionException e) {
+	    throw e;
+	} catch (RejectRulesException e) {
+	    log.error("Unexpected RejectRulesException", e);
+	    return JRamCloud.VERSION_NONEXISTENT;
+	}
     }
 
     /**
@@ -187,13 +202,17 @@
 
 	JRamCloud rcClient = RCClient.getClient();
 
-	RejectRules rules = rcClient.new RejectRules();
-	rules.setDoesntExists();
+	RejectRules rules = new RejectRules();
+	rules.rejectIfDoesntExists();
 
-	long updated_version = rcClient.writeRule(this.rcTableId, key, value,
-	        rules);
-	return updated_version;
-
+	try {
+	    return rcClient.write(this.rcTableId, key, value, rules);
+	} catch (ObjectDoesntExistException e) {
+	    throw e;
+	} catch (RejectRulesException e) {
+	    log.error("Unexpected RejectRulesException", e);
+	    return JRamCloud.VERSION_NONEXISTENT;
+	}
     }
 
     /**
@@ -210,13 +229,18 @@
 	    throws ObjectDoesntExistException, WrongVersionException {
 	JRamCloud rcClient = RCClient.getClient();
 
-	// FIXME underlying JRamCloud does not support cond. remove now
-	RejectRules rules = rcClient.new RejectRules();
-	rules.setDoesntExists();
-	rules.setNeVersion(version);
+	RejectRules rules = new RejectRules();
+	rules.rejectIfDoesntExists();
+	rules.rejectIfNeVersion(version);
 
-	long removed_version = rcClient.remove(this.rcTableId, key, rules);
-	return removed_version;
+	try {
+	    return rcClient.remove(this.rcTableId, key, rules);
+	} catch (ObjectDoesntExistException|WrongVersionException e) {
+	    throw e;
+	} catch (RejectRulesException e) {
+	    log.error("Unexpected RejectRulesException", e);
+	    return JRamCloud.VERSION_NONEXISTENT;
+	}
     }
 
     /**