You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by mp...@apache.org on 2016/03/29 03:05:24 UTC

incubator-kudu git commit: KUDU-839. Add Status class to Java client for use in RowError

Repository: incubator-kudu
Updated Branches:
  refs/heads/master 1b768723f -> c8598ff04


KUDU-839. Add Status class to Java client for use in RowError

This class is the Java equivalent of the C++ kudu::Status class and
shares all of the same functionality except for the Clone...() methods.
The thought there is that we would primarily construct these on the
server side, not the client side.

Change-Id: I58e3c949cf441b7dd798c5001aeed747457a8807
Reviewed-on: http://gerrit.cloudera.org:8080/2640
Reviewed-by: Adar Dembo <ad...@cloudera.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kudu/commit/c8598ff0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kudu/tree/c8598ff0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kudu/diff/c8598ff0

Branch: refs/heads/master
Commit: c8598ff04325da0ac7e1a04b768bf33724acf5f3
Parents: 1b76872
Author: Mike Percy <mp...@apache.org>
Authored: Fri Mar 25 18:33:03 2016 -0700
Committer: Mike Percy <mp...@apache.org>
Committed: Tue Mar 29 01:04:54 2016 +0000

----------------------------------------------------------------------
 .../org/kududb/client/AsyncKuduSession.java     |   6 +-
 .../main/java/org/kududb/client/RowError.java   |  27 +-
 .../src/main/java/org/kududb/client/Status.java | 343 +++++++++++++++++++
 .../org/kududb/client/TestErrorCollector.java   |  10 +-
 .../test/java/org/kududb/client/TestStatus.java |  55 +++
 src/kudu/common/wire_protocol.proto             |   2 +-
 src/kudu/util/status.h                          |   1 +
 7 files changed, 424 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/c8598ff0/java/kudu-client/src/main/java/org/kududb/client/AsyncKuduSession.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/kududb/client/AsyncKuduSession.java b/java/kudu-client/src/main/java/org/kududb/client/AsyncKuduSession.java
index e9a2a18..1bbc74f 100644
--- a/java/kudu-client/src/main/java/org/kududb/client/AsyncKuduSession.java
+++ b/java/kudu-client/src/main/java/org/kududb/client/AsyncKuduSession.java
@@ -325,12 +325,12 @@ public class AsyncKuduSession implements SessionConfiguration {
    * This will flush all the batches but not the operations that are currently in lookup.
    */
   private Deferred<ArrayList<BatchResponse>> flushAllBatches() {
-    HashMap<Slice, Batch> copyOfOps;
-    final ArrayList<Deferred<BatchResponse>> d = new ArrayList<>(operations.size());
+    Map<Slice, Batch> copyOfOps;
+    final List<Deferred<BatchResponse>> d = new ArrayList<>(operations.size());
     synchronized (this) {
       copyOfOps = new HashMap<>(operations);
     }
-    for (Map.Entry<Slice, Batch> entry: copyOfOps.entrySet()) {
+    for (Map.Entry<Slice, Batch> entry : copyOfOps.entrySet()) {
       d.add(flushTablet(entry.getKey(), entry.getValue()));
     }
     return Deferred.group(d);

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/c8598ff0/java/kudu-client/src/main/java/org/kududb/client/RowError.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/kududb/client/RowError.java b/java/kudu-client/src/main/java/org/kududb/client/RowError.java
index c2e0b59..1570376 100644
--- a/java/kudu-client/src/main/java/org/kududb/client/RowError.java
+++ b/java/kudu-client/src/main/java/org/kududb/client/RowError.java
@@ -27,35 +27,42 @@ import org.kududb.tserver.Tserver;
 @InterfaceAudience.Public
 @InterfaceStability.Evolving
 public class RowError {
-  private final String status;
-  private final String message;
+  private final Status status;
   private final Operation operation;
   private final String tsUUID;
 
   /**
    * Package-private for unit tests.
    */
-  RowError(String errorStatus, String errorMessage, Operation operation, String tsUUID) {
-    this.status = errorStatus;
-    this.message = errorMessage;
+  RowError(Status status, Operation operation, String tsUUID) {
+    this.status = status;
     this.operation = operation;
     this.tsUUID = tsUUID;
   }
 
   /**
+   * Get the status code and message of the row error.
+   */
+  public Status getErrorStatus() {
+    return status;
+  }
+
+  /**
    * Get the string-representation of the error code that the tablet server returned.
    * @return A short string representation of the error.
+   * @deprecated Please use getErrorStatus() instead. Will be removed in a future version.
    */
   public String getStatus() {
-    return status;
+    return status.getCodeName();
   }
 
   /**
    * Get the error message the tablet server sent.
    * @return The error message.
+   * @deprecated Please use getErrorStatus() instead. Will be removed in a future version.
    */
   public String getMessage() {
-    return message;
+    return status.getMessage();
   }
 
   /**
@@ -79,8 +86,7 @@ public class RowError {
     return "Row error for primary key=" + Bytes.pretty(operation.getRow().encodePrimaryKey()) +
         ", tablet=" + operation.getTablet().getTabletIdAsString() +
         ", server=" + tsUUID +
-        ", status=" + status +
-        ", message=" + message;
+        ", status=" + status.toString();
   }
 
   /**
@@ -93,7 +99,6 @@ public class RowError {
   static RowError fromRowErrorPb(Tserver.WriteResponsePB.PerRowErrorPB errorPB,
                                  Operation operation, String tsUUID) {
     WireProtocol.AppStatusPB statusPB = errorPB.getError();
-    return new RowError(statusPB.getCode().toString(),
-        statusPB.getMessage(), operation, tsUUID);
+    return new RowError(Status.fromPB(statusPB), operation, tsUUID);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/c8598ff0/java/kudu-client/src/main/java/org/kududb/client/Status.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/kududb/client/Status.java b/java/kudu-client/src/main/java/org/kududb/client/Status.java
new file mode 100644
index 0000000..b89f73d
--- /dev/null
+++ b/java/kudu-client/src/main/java/org/kududb/client/Status.java
@@ -0,0 +1,343 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 org.kududb.client;
+
+import org.kududb.WireProtocol;
+import org.kududb.annotations.InterfaceAudience;
+import org.kududb.annotations.InterfaceStability;
+
+/**
+ * Representation of an error code and message. Wraps {@link WireProtocol.AppStatusPB}.
+ * See also {@code src/kudu/util/status.h} in the C++ codebase.
+ *
+ * <p>Do not use the {@code @deprecated} methods in this class.</p>
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public class Status {
+  private final WireProtocol.AppStatusPB appStatusPB;
+
+  private Status(WireProtocol.AppStatusPB appStatusPB) {
+    this.appStatusPB = appStatusPB;
+  }
+
+  private Status(WireProtocol.AppStatusPB.ErrorCode code, String msg, int posixCode) {
+    this.appStatusPB =
+        WireProtocol.AppStatusPB.newBuilder()
+            .setCode(code)
+            .setMessage(msg)
+            .setPosixCode(posixCode)
+            .build();
+  }
+
+  private Status(WireProtocol.AppStatusPB.ErrorCode code, String msg) {
+    this(code, msg, -1);
+  }
+
+  private Status(WireProtocol.AppStatusPB.ErrorCode code) {
+    this(code, "", -1);
+  }
+
+  // Factory methods.
+
+  /**
+   * Create a Status object from a {@link WireProtocol.AppStatusPB} protobuf object.
+   * Package-private because we shade Protobuf and this is not usable outside this package.
+   */
+  static Status fromPB(WireProtocol.AppStatusPB pb) {
+    return new Status(pb);
+  }
+
+  public static Status OK() {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.OK);
+  }
+
+  public static Status NotFound(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NOT_FOUND, msg);
+  }
+  public static Status NotFound(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NOT_FOUND, msg, posixCode);
+  }
+
+  public static Status Corruption(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.CORRUPTION, msg);
+  }
+  public static Status Corruption(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.CORRUPTION, msg, posixCode);
+  }
+
+  public static Status NotSupported(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NOT_SUPPORTED, msg);
+  }
+  public static Status NotSupported(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NOT_SUPPORTED, msg, posixCode);
+  }
+
+  public static Status InvalidArgument(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.INVALID_ARGUMENT, msg);
+  }
+  public static Status InvalidArgument(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.INVALID_ARGUMENT, msg, posixCode);
+  }
+
+  public static Status IOError(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.IO_ERROR, msg);
+  }
+  public static Status IOError(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.IO_ERROR, msg, posixCode);
+  }
+
+  public static Status AlreadyPresent(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.ALREADY_PRESENT, msg);
+  }
+  public static Status AlreadyPresent(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.ALREADY_PRESENT, msg, posixCode);
+  }
+
+  public static Status RuntimeError(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.RUNTIME_ERROR, msg);
+  }
+  public static Status RuntimeError(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.RUNTIME_ERROR, msg, posixCode);
+  }
+
+  public static Status NetworkError(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NETWORK_ERROR, msg);
+  }
+  public static Status NetworkError(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NETWORK_ERROR, msg, posixCode);
+  }
+
+  public static Status IllegalState(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.ILLEGAL_STATE, msg);
+  }
+  public static Status IllegalState(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.ILLEGAL_STATE, msg, posixCode);
+  }
+
+  public static Status NotAuthorized(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NOT_AUTHORIZED, msg);
+  }
+  public static Status NotAuthorized(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.NOT_AUTHORIZED, msg, posixCode);
+  }
+
+  public static Status Aborted(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.ABORTED, msg);
+  }
+  public static Status Aborted(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.ABORTED, msg, posixCode);
+  }
+
+  public static Status RemoteError(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.REMOTE_ERROR, msg);
+  }
+  public static Status RemoteError(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.REMOTE_ERROR, msg, posixCode);
+  }
+
+  public static Status ServiceUnavailable(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.SERVICE_UNAVAILABLE, msg);
+  }
+  public static Status ServiceUnavailable(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.SERVICE_UNAVAILABLE, msg, posixCode);
+  }
+
+  public static Status TimedOut(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.TIMED_OUT, msg);
+  }
+  public static Status TimedOut(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.TIMED_OUT, msg, posixCode);
+  }
+
+  public static Status Uninitialized(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.UNINITIALIZED, msg);
+  }
+  public static Status Uninitialized(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.UNINITIALIZED, msg, posixCode);
+  }
+
+  public static Status ConfigurationError(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.CONFIGURATION_ERROR, msg);
+  }
+  public static Status ConfigurationError(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.CONFIGURATION_ERROR, msg, posixCode);
+  }
+
+  public static Status Incomplete(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.INCOMPLETE, msg);
+  }
+  public static Status Incomplete(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.INCOMPLETE, msg, posixCode);
+  }
+
+  public static Status EndOfFile(String msg) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.END_OF_FILE, msg);
+  }
+  public static Status EndOfFile(String msg, int posixCode) {
+    return new Status(WireProtocol.AppStatusPB.ErrorCode.END_OF_FILE, msg, posixCode);
+  }
+
+  // Boolean status checks.
+
+  public boolean ok() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.OK;
+  }
+  public boolean isCorruption() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.CORRUPTION;
+  }
+  public boolean isNotFound() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.NOT_FOUND;
+  }
+  public boolean isNotSupported() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.NOT_SUPPORTED;
+  }
+  public boolean isInvalidArgument() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.INVALID_ARGUMENT;
+  }
+  public boolean isIOError() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.IO_ERROR;
+  }
+  public boolean isAlreadyPresent() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.ALREADY_PRESENT;
+  }
+  public boolean isRuntimeError() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.RUNTIME_ERROR;
+  }
+  public boolean isNetworkError() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.NETWORK_ERROR;
+  }
+  public boolean isIllegalState() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.ILLEGAL_STATE;
+  }
+  public boolean isNotAuthorized() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.NOT_AUTHORIZED;
+  }
+  public boolean isAborted() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.ABORTED;
+  }
+  public boolean isRemoteError() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.REMOTE_ERROR;
+  }
+  public boolean isServiceUnavailable() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.SERVICE_UNAVAILABLE;
+  }
+  public boolean isTimedOut() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.TIMED_OUT;
+  }
+  public boolean isUninitialized() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.UNINITIALIZED;
+  }
+  public boolean isConfigurationError() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.CONFIGURATION_ERROR;
+  }
+  public boolean isIncomplete() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.INCOMPLETE;
+  }
+  public boolean isEndOfFile() {
+    return appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.END_OF_FILE;
+  }
+
+  /**
+   * Return a human-readable version of the status code.
+   * See also status.cc in the C++ codebase.
+   */
+  private String getCodeAsString() {
+    switch (appStatusPB.getCode().getNumber()) {
+      case WireProtocol.AppStatusPB.ErrorCode.OK_VALUE:
+        return "OK";
+      case WireProtocol.AppStatusPB.ErrorCode.NOT_FOUND_VALUE:
+        return "Not found";
+      case WireProtocol.AppStatusPB.ErrorCode.CORRUPTION_VALUE:
+        return "Corruption";
+      case WireProtocol.AppStatusPB.ErrorCode.NOT_SUPPORTED_VALUE:
+        return "Not implemented";
+      case WireProtocol.AppStatusPB.ErrorCode.INVALID_ARGUMENT_VALUE:
+        return "Invalid argument";
+      case WireProtocol.AppStatusPB.ErrorCode.IO_ERROR_VALUE:
+        return "IO error";
+      case WireProtocol.AppStatusPB.ErrorCode.ALREADY_PRESENT_VALUE:
+        return "Already present";
+      case WireProtocol.AppStatusPB.ErrorCode.RUNTIME_ERROR_VALUE:
+        return "Runtime error";
+      case WireProtocol.AppStatusPB.ErrorCode.NETWORK_ERROR_VALUE:
+        return "Network error";
+      case WireProtocol.AppStatusPB.ErrorCode.ILLEGAL_STATE_VALUE:
+        return "Illegal state";
+      case WireProtocol.AppStatusPB.ErrorCode.NOT_AUTHORIZED_VALUE:
+        return "Not authorized";
+      case WireProtocol.AppStatusPB.ErrorCode.ABORTED_VALUE:
+        return "Aborted";
+      case WireProtocol.AppStatusPB.ErrorCode.REMOTE_ERROR_VALUE:
+        return "Remote error";
+      case WireProtocol.AppStatusPB.ErrorCode.SERVICE_UNAVAILABLE_VALUE:
+        return "Service unavailable";
+      case WireProtocol.AppStatusPB.ErrorCode.TIMED_OUT_VALUE:
+        return "Timed out";
+      case WireProtocol.AppStatusPB.ErrorCode.UNINITIALIZED_VALUE:
+        return "Uninitialized";
+      case WireProtocol.AppStatusPB.ErrorCode.CONFIGURATION_ERROR_VALUE:
+        return "Configuration error";
+      case WireProtocol.AppStatusPB.ErrorCode.INCOMPLETE_VALUE:
+        return "Incomplete";
+      case WireProtocol.AppStatusPB.ErrorCode.END_OF_FILE_VALUE:
+        return "End of file";
+      default:
+        return "Unknown error (" + appStatusPB.getCode().getNumber() + ")";
+    }
+  }
+
+  /**
+   * Get the posix code associated with the error.
+   * @return {@code -1} if no posix code is set. Otherwise, returns the posix code.
+   */
+  public int getPosixCode() {
+    return appStatusPB.getPosixCode();
+  }
+
+  /**
+   * Get enum code name.
+   * Intended for internal use only.
+   */
+  String getCodeName() {
+    return appStatusPB.getCode().name();
+  }
+
+  /**
+   * Returns string error message.
+   * Intended for internal use only.
+   */
+  String getMessage() {
+    return appStatusPB.getMessage();
+  }
+
+  /**
+   * Get a human-readable version of the Status message fit for logging or display.
+   */
+  @Override
+  public String toString() {
+    String str = getCodeAsString();
+    if (appStatusPB.getCode() == WireProtocol.AppStatusPB.ErrorCode.OK) {
+      return str;
+    }
+    str = String.format("%s: %s", str, appStatusPB.getMessage());
+    if (appStatusPB.getPosixCode() != -1) {
+      str = String.format("%s (error %d)", str, appStatusPB.getPosixCode());
+    }
+    return str;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/c8598ff0/java/kudu-client/src/test/java/org/kududb/client/TestErrorCollector.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/test/java/org/kududb/client/TestErrorCollector.java b/java/kudu-client/src/test/java/org/kududb/client/TestErrorCollector.java
index 01be75c..883b2e1 100644
--- a/java/kudu-client/src/test/java/org/kududb/client/TestErrorCollector.java
+++ b/java/kudu-client/src/test/java/org/kududb/client/TestErrorCollector.java
@@ -42,7 +42,7 @@ public class TestErrorCollector {
     Assert.assertEquals(0, collector.countErrors());
     Assert.assertFalse(reos.isOverflowed());
     Assert.assertEquals(countToTest, reos.getRowErrors().length);
-    Assert.assertEquals(countToTest + "", reos.getRowErrors()[0].getStatus());
+    Assert.assertEquals(countToTest, reos.getRowErrors()[0].getErrorStatus().getPosixCode());
 
     // Test filling the collector to the max.
     countToTest = maxErrors;
@@ -52,7 +52,7 @@ public class TestErrorCollector {
     Assert.assertEquals(0, collector.countErrors());
     Assert.assertFalse(reos.isOverflowed());
     Assert.assertEquals(countToTest, reos.getRowErrors().length);
-    Assert.assertEquals((countToTest - 1) + "", reos.getRowErrors()[9].getStatus());
+    Assert.assertEquals(countToTest - 1, reos.getRowErrors()[9].getErrorStatus().getPosixCode());
 
     // Test overflowing.
     countToTest = 95;
@@ -62,7 +62,7 @@ public class TestErrorCollector {
     Assert.assertEquals(0, collector.countErrors());
     Assert.assertTrue(reos.isOverflowed());
     Assert.assertEquals(maxErrors, reos.getRowErrors().length);
-    Assert.assertEquals((countToTest - 1) + "", reos.getRowErrors()[9].getStatus());
+    Assert.assertEquals(countToTest - 1, reos.getRowErrors()[9].getErrorStatus().getPosixCode());
 
     // Test overflowing on a newly created collector.
     countToTest = 95;
@@ -73,7 +73,7 @@ public class TestErrorCollector {
     Assert.assertEquals(0, collector.countErrors());
     Assert.assertTrue(reos.isOverflowed());
     Assert.assertEquals(maxErrors, reos.getRowErrors().length);
-    Assert.assertEquals((countToTest - 1) + "", reos.getRowErrors()[9].getStatus());
+    Assert.assertEquals(countToTest - 1, reos.getRowErrors()[9].getErrorStatus().getPosixCode());
   }
 
   private void fillCollectorWith(ErrorCollector collector, int errorsToAdd) {
@@ -85,6 +85,6 @@ public class TestErrorCollector {
   private RowError createRowError(int id) {
     // Use the error status as a way to message pass and so that we can test we're getting the right
     // messages on the other end.
-    return new RowError(id + "", "test", null, "test");
+    return new RowError(Status.NotAuthorized("test", id), null, "test");
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/c8598ff0/java/kudu-client/src/test/java/org/kududb/client/TestStatus.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/test/java/org/kududb/client/TestStatus.java b/java/kudu-client/src/test/java/org/kududb/client/TestStatus.java
new file mode 100644
index 0000000..11bd23b
--- /dev/null
+++ b/java/kudu-client/src/test/java/org/kududb/client/TestStatus.java
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 org.kududb.client;
+
+import org.junit.Test;
+import org.kududb.client.Status;
+
+import static org.junit.Assert.*;
+
+public class TestStatus {
+
+  @Test
+  public void testOKStatus() {
+    Status s = Status.OK();
+    assertTrue(s.ok());
+    assertFalse(s.isNotAuthorized());
+    assertEquals(-1, s.getPosixCode());
+    assertEquals("OK", s.toString());
+  }
+
+  @Test
+  public void testStatusNonPosix() {
+    Status s = Status.Aborted("foo");
+    assertFalse(s.ok());
+    assertTrue(s.isAborted());
+    assertEquals("ABORTED", s.getCodeName());
+    assertEquals("foo", s.getMessage());
+    assertEquals(-1, s.getPosixCode());
+    assertEquals("Aborted: foo", s.toString());
+  }
+
+  @Test
+  public void testPosixCode() {
+    Status s = Status.NotFound("File not found", 2);
+    assertFalse(s.ok());
+    assertFalse(s.isAborted());
+    assertTrue(s.isNotFound());
+    assertEquals(2, s.getPosixCode());
+    assertEquals("Not found: File not found (error 2)", s.toString());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/c8598ff0/src/kudu/common/wire_protocol.proto
----------------------------------------------------------------------
diff --git a/src/kudu/common/wire_protocol.proto b/src/kudu/common/wire_protocol.proto
index 7f79475..936c8e6 100644
--- a/src/kudu/common/wire_protocol.proto
+++ b/src/kudu/common/wire_protocol.proto
@@ -32,7 +32,7 @@ import "kudu/consensus/metadata.proto";
 // should have this (or a more complex error result) as an optional field
 // in its response.
 //
-// This maps to kudu::Status in C++.
+// This maps to kudu::Status in C++ and org.kududb.Status in Java.
 message AppStatusPB {
   enum ErrorCode {
     UNKNOWN_ERROR = 999;

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/c8598ff0/src/kudu/util/status.h
----------------------------------------------------------------------
diff --git a/src/kudu/util/status.h b/src/kudu/util/status.h
index 5003be3..5124b7e 100644
--- a/src/kudu/util/status.h
+++ b/src/kudu/util/status.h
@@ -315,6 +315,7 @@ class KUDU_EXPORT Status {
     kEndOfFile = 18,
     // NOTE: Remember to duplicate these constants into wire_protocol.proto and
     // and to add StatusTo/FromPB ser/deser cases in wire_protocol.cc !
+    // Also remember to make the same changes to the java client in Status.java.
     //
     // TODO: Move error codes into an error_code.proto or something similar.
   };