add error code and string formatting to exception

Change-Id: I83941719c6ee0a5a2ce7337b328ad094116fd13f
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1000
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Yingyi Bu <buyingyi@gmail.com>
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/ErrorCode.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/ErrorCode.java
new file mode 100644
index 0000000..1a883b5
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/ErrorCode.java
@@ -0,0 +1,23 @@
+/*
+ * 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.apache.hyracks.api.exceptions;
+
+public class ErrorCode extends HyracksException {
+    public static final int UNKNOWN = 0;
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksDataException.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksDataException.java
index eaf8df9..73f921f4 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksDataException.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksDataException.java
@@ -18,24 +18,76 @@
  */
 package org.apache.hyracks.api.exceptions;
 
+import java.io.Serializable;
+import java.util.Formatter;
+
 public class HyracksDataException extends HyracksException {
     private static final long serialVersionUID = 1L;
 
+    public static final String NONE = "";
+    public static final String HYRACKS = "HYR";
+
+    private final String component;
+    private final int errorCode;
+    private final Serializable[] params;
     private String nodeId;
 
+    private volatile transient String msgCache;
+
     public HyracksDataException() {
+        this(NONE, ErrorCode.UNKNOWN, new Object[0]);
     }
 
     public HyracksDataException(String message) {
-        super(message);
+        this(NONE, ErrorCode.UNKNOWN, message);
     }
 
     public HyracksDataException(Throwable cause) {
-        super(cause);
+        this(NONE, ErrorCode.UNKNOWN, cause);
     }
 
     public HyracksDataException(String message, Throwable cause) {
+        this(NONE, ErrorCode.UNKNOWN, message, cause);
+    }
+
+    public HyracksDataException(String component, int errorCode, Serializable... params) {
+        this.component = component;
+        this.errorCode = errorCode;
+        this.params = params;
+    }
+
+    public HyracksDataException(String component, int errorCode, String message, Serializable... params) {
+        super(message);
+        this.component = component;
+        this.errorCode = errorCode;
+        this.params = params;
+    }
+
+    public HyracksDataException(String component, int errorCode, Throwable cause, Serializable... params) {
+        super(cause);
+        this.component = component;
+        this.errorCode = errorCode;
+        this.params = params;
+    }
+
+    public HyracksDataException(String component, int errorCode, String message, Throwable cause,
+            Serializable... params) {
         super(message, cause);
+        this.component = component;
+        this.errorCode = errorCode;
+        this.params = params;
+    }
+
+    public String getComponent() {
+        return component;
+    }
+
+    public int getErrorCode() {
+        return errorCode;
+    }
+
+    public Object[] getParams() {
+        return params;
     }
 
     public void setNodeId(String nodeId) {
@@ -45,4 +97,33 @@
     public String getNodeId() {
         return nodeId;
     }
+
+    @Override
+    public String getMessage() {
+        if (msgCache == null) {
+            msgCache = formatMessage(component, errorCode, super.getMessage(), params);
+        }
+        return msgCache;
+    }
+
+    /**
+     * formats a error message
+     * Example:
+     * formatMessage(HYRACKS, ErrorCode.UNKNOWN, "%1$s -- %2$s", "one", "two") returns "HYR0000: one -- two"
+     *
+     * @param component the software component in which the error originated
+     * @param errorCode the error code itself
+     * @param message   the user provided error message (a format string as specified in {@link java.util.Formatter})
+     * @param params    an array of objects taht will be provided to the {@link java.util.Formatter}
+     * @return the formatted string
+     */
+    public static String formatMessage(String component, int errorCode, String message, Serializable... params) {
+        try (Formatter fmt = new Formatter()) {
+            if (! NONE.equals(component)) {
+                fmt.format("%1$s%2$04d: ", component, errorCode);
+            }
+            fmt.format(message, (Object[]) params);
+            return fmt.out().toString();
+        }
+    }
 }
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/rewriting/ErrorReportingTest.java b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/rewriting/ErrorReportingTest.java
index 6b08c3e..cdabcda 100644
--- a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/rewriting/ErrorReportingTest.java
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/rewriting/ErrorReportingTest.java
@@ -69,8 +69,8 @@
         try {
             runTest(spec);
         } catch (Exception e) {
-            Throwable t = getRootCause(e);
-            Assert.assertTrue(t.getMessage().equals(EXPECTED_ERROR_MESSAGE));
+            String actualMessage = getRootCause(e).getMessage();
+            Assert.assertTrue(actualMessage.equals(EXPECTED_ERROR_MESSAGE));
         }
     }