BATCHEE-99 add metrics to simplerest

Patch provided by Florian Reisecker, txs!
diff --git a/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java b/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java
index b86239f..d9ded4c 100644
--- a/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java
+++ b/gui/servlet/embedded/src/main/java/org/apache/batchee/servlet/SimpleRestController.java
@@ -19,6 +19,13 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Properties;
 
@@ -29,6 +36,8 @@
 import javax.batch.operations.NoSuchJobExecutionException;
 import javax.batch.runtime.BatchStatus;
 import javax.batch.runtime.JobExecution;
+import javax.batch.runtime.Metric;
+import javax.batch.runtime.StepExecution;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -37,12 +46,15 @@
  */
 public class SimpleRestController {
     public static final String REST_CONTENT_TYPE = "text/plain";
+    public static final String NOT_FOUND_STRING = "-";
+    public static final char CSV_DELIMITER = ';';
 
     public static final String OP_START = "start/";
     public static final String OP_STATUS = "status/";
+    public static final String OP_METRICS = "metrics/";
+
     public static final String OP_STOP = "stop/";
     public static final String OP_RESTART = "restart/";
-
     public static final long NO_JOB_ID = -1L;
 
     private final JobOperator jobOperator;
@@ -62,6 +74,8 @@
             startBatch(path.substring(OP_START.length()), req, resp);
         } else if (path != null && path.startsWith(OP_STATUS)) {
             batchStatus(path.substring(OP_STATUS.length()), req, resp);
+        } else if (path != null && path.startsWith(OP_METRICS)) {
+            batchMetrics(path.substring(OP_METRICS.length()), req, resp);
         } else if (path != null && path.startsWith(OP_STOP)) {
             batchStop(path.substring(OP_STOP.length()), req, resp);
         } else if (path != null && path.startsWith(OP_RESTART)) {
@@ -106,6 +120,28 @@
         }
     }
 
+    private void batchMetrics(String batchId, HttpServletRequest req, HttpServletResponse resp) {
+        Long executionId = extractExecutionId(batchId, resp);
+        if (executionId == null) {
+            return;
+        }
+
+        try {
+            JobExecution jobExecution = jobOperator.getJobExecution(executionId);
+            BatchStatus batchStatus = jobExecution.getBatchStatus();
+
+            List<StepExecution> stepExecutions = jobOperator.getStepExecutions(executionId);
+            reportSuccess(executionId, resp, batchStatus.name());
+            reportMetricsCsv(resp, stepExecutions);
+        } catch (NoSuchJobExecutionException noSuchJob) {
+            reportFailure(executionId, resp, "NoSuchJob");
+        } catch (Exception generalException) {
+            StringBuilder msg = new StringBuilder("Failure in BatchExecution");
+            appendExceptionMsg(msg, generalException);
+            reportFailure(executionId, resp, msg.toString());
+        }
+    }
+
     private void batchStop(String batchId, HttpServletRequest req, HttpServletResponse resp) {
         Long executionId = extractExecutionId(batchId, resp);
         if (executionId == null) {
@@ -166,6 +202,10 @@
         msg.append("  Sample: http://localhost:8080/myapp/jbatch/rest/status/23\n");
         msg.append("  will return the state of executionId 23\n\n");
 
+        msg.append("* ").append(OP_METRICS).append(" - query the current metrics \n");
+        msg.append("  Sample: http://localhost:8080/myapp/jbatch/rest/metrics/23\n");
+        msg.append("  will return the metrics of executionId 23\n\n");
+
         msg.append("* ").append(OP_STOP).append(" - stop the job with the given executionId \n");
         msg.append("  Sample: http://localhost:8080/myapp/jbatch/rest/stop/23\n");
         msg.append("  will stop the job with executionId 23\n\n");
@@ -228,6 +268,56 @@
         writeContent(resp, content);
     }
 
+    private void reportMetricsCsv(HttpServletResponse resp, List<StepExecution> stepExecutions) {
+        StringBuilder stringBuilder = new StringBuilder(200);
+        stringBuilder.append("\n");
+
+        // append csv header to stringbuilder
+        joinCsv(stringBuilder, Arrays.asList("STEP_EXECUTION_ID", "STEP_NAME"));
+        stringBuilder.append(CSV_DELIMITER);
+        joinCsv(stringBuilder, Arrays.asList(Metric.MetricType.values()));
+        stringBuilder.append("\n");
+
+        Collections.sort(stepExecutions, new Comparator<StepExecution>() {
+            @Override
+            public int compare(StepExecution o1, StepExecution o2) {
+                return Long.compare(o1.getStepExecutionId(), o2.getStepExecutionId());
+            }
+        });
+        // append csv values to stringbuilder, one stepExecution per line
+        for (StepExecution stepExecution : stepExecutions) {
+            stringBuilder.append(stepExecution.getStepExecutionId());
+            stringBuilder.append(CSV_DELIMITER);
+            stringBuilder.append(stepExecution.getStepName());
+            stringBuilder.append(CSV_DELIMITER);
+
+            Metric[] metricsArray = stepExecution.getMetrics();
+            Map<Metric.MetricType, Metric> sourceMap = new HashMap<Metric.MetricType, Metric>();
+            for (Metric metric : metricsArray) {
+                sourceMap.put(metric.getType(), metric);
+            }
+
+            List<String> orderedMetricsValues = new ArrayList<String>();
+            for (Metric.MetricType type : Metric.MetricType.values()) {
+                orderedMetricsValues.add(sourceMap.containsKey(type) ? String.valueOf(sourceMap.get(type).getValue()) : NOT_FOUND_STRING);
+            }
+            joinCsv(stringBuilder, orderedMetricsValues);
+
+            stringBuilder.append("\n");
+        }
+
+        writeContent(resp, stringBuilder.toString());
+    }
+
+    private void joinCsv(StringBuilder builder, List values) {
+        for (ListIterator iter = values.listIterator(); iter.hasNext(); ) {
+            builder.append(iter.next());
+            if (iter.hasNext()) {
+                builder.append(CSV_DELIMITER);
+            }
+        }
+    }
+
     private void writeContent(HttpServletResponse resp, String content) {
         try {
             resp.getWriter().append(content);