Extract the object o string rendering engine

Refactor the generation of audit string entries: extract
the rendering interface (AuditEvent to String) and put the current
logic into a Csv rendering which is bound by default.

Change-Id: Icbb1b30ca23a095c92f51c31d6aa509fd6cd11bd
diff --git a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditFormatters.java b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditFormatters.java
new file mode 100644
index 0000000..4e3798b
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditFormatters.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed 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 com.googlesource.gerrit.plugins.auditsl4j;
+
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+class AuditFormatters {
+  private static final SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSSS");
+
+  @SuppressWarnings("serial")
+  private static final Map<Class<?>, AuditFormatter<?>> AUDIT_FORMATTERS =
+      Collections.unmodifiableMap(
+          new HashMap<Class<?>, AuditFormatter<? extends Object>>() {
+            {
+              put(HttpAuditEventFormat.CLASS, new HttpAuditEventFormat());
+              put(RpcAuditEventFormat.CLASS, new RpcAuditEventFormat());
+              put(SshAuditEventFormat.CLASS, new SshAuditEventFormat());
+              put(AuditEventFormat.CLASS, new AuditEventFormat());
+            }
+          });
+
+  public static <T> String getFormattedAuditSingle(T result) {
+    if (result == null) return "";
+
+    @SuppressWarnings("unchecked")
+    AuditFormatter<T> fmt = (AuditFormatter<T>) AUDIT_FORMATTERS.get(result.getClass());
+    if (fmt == null) return result.toString();
+
+    return fmt.format(result);
+  }
+
+  public static synchronized String getFormattedTS(long when) {
+    return dateFmt.format(new Date(when));
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditRenderer.java b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditRenderer.java
new file mode 100644
index 0000000..f89046e
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditRenderer.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed 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 com.googlesource.gerrit.plugins.auditsl4j;
+
+import com.google.gerrit.audit.AuditEvent;
+import com.google.inject.ImplementedBy;
+
+@ImplementedBy(AuditRendererToCsv.class)
+public interface AuditRenderer {
+
+  String render(AuditEvent auditEvent);
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditRendererToCsv.java b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditRendererToCsv.java
new file mode 100644
index 0000000..4f2a6e3
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditRendererToCsv.java
@@ -0,0 +1,84 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed 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 com.googlesource.gerrit.plugins.auditsl4j;
+
+import static com.googlesource.gerrit.plugins.auditsl4j.AuditFormatters.getFormattedAuditSingle;
+import static com.googlesource.gerrit.plugins.auditsl4j.AuditFormatters.getFormattedTS;
+
+import com.google.common.collect.Multimap;
+import com.google.gerrit.audit.AuditEvent;
+import java.util.Collection;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class AuditRendererToCsv implements AuditRenderer {
+
+  @Override
+  public String render(AuditEvent auditEvent) {
+    return String.format(
+        "%1$s | %2$s | %3$s | %4$s | %5$s | %6$s | %7$s | %8$s | %9$s | %10$s",
+        auditEvent.uuid.uuid(),
+        getFormattedTS(auditEvent.when),
+        auditEvent.sessionId,
+        getFormattedAuditSingle(auditEvent.who),
+        getFormattedAuditSingle(auditEvent),
+        auditEvent.what,
+        getFormattedAuditList(auditEvent.params),
+        getFormattedAuditSingle(auditEvent.result),
+        getFormattedTS(auditEvent.timeAtStart),
+        auditEvent.elapsed);
+  }
+
+  private Object getFormattedAuditList(Multimap<String, ?> params) {
+    if (params == null || params.size() == 0) {
+      return "[]";
+    }
+
+    StringBuilder formattedOut = new StringBuilder("[");
+
+    Set<String> paramNames = new TreeSet<>(params.keySet());
+
+    int numParams = 0;
+    for (String paramName : paramNames) {
+      if (numParams++ > 0) {
+        formattedOut.append(",");
+      }
+      formattedOut.append(paramName);
+      formattedOut.append("=");
+      formattedOut.append(getFormattedAudit(params.get(paramName)));
+    }
+
+    formattedOut.append(']');
+
+    return formattedOut.toString();
+  }
+
+  private Object getFormattedAudit(Collection<? extends Object> values) {
+    StringBuilder out = new StringBuilder();
+    int numValues = 0;
+    for (Object object : values) {
+      if (numValues > 0) {
+        out.append(",");
+      }
+      out.append(getFormattedAuditSingle(object));
+      numValues++;
+    }
+
+    if (numValues > 1) {
+      return "[" + out.toString() + "]";
+    }
+    return out.toString();
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java
index bca501e..54e004d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java
@@ -14,44 +14,25 @@
 
 package com.googlesource.gerrit.plugins.auditsl4j;
 
-import com.google.common.collect.Multimap;
 import com.google.gerrit.audit.AuditEvent;
 import com.google.gerrit.audit.AuditListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
 
 @Singleton
 public class LoggerAudit implements AuditListener {
-  private final SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSSS");
   private final AuditWriter auditWriter;
+  private final AuditRenderer auditRenderer;
 
   public static final String AUDIT_LOGGER_NAME = LoggerAudit.class.getName();
 
-  @SuppressWarnings("serial")
-  private static final Map<Class<?>, AuditFormatter<?>> AUDIT_FORMATTERS =
-      Collections.unmodifiableMap(
-          new HashMap<Class<?>, AuditFormatter<? extends Object>>() {
-            {
-              put(HttpAuditEventFormat.CLASS, new HttpAuditEventFormat());
-              put(RpcAuditEventFormat.CLASS, new RpcAuditEventFormat());
-              put(SshAuditEventFormat.CLASS, new SshAuditEventFormat());
-              put(AuditEventFormat.CLASS, new AuditEventFormat());
-            }
-          });
-
   @Inject
-  LoggerAudit(AuditWriter auditWriter) {
+  LoggerAudit(AuditWriter auditWriter, AuditRenderer auditRenderer) {
     this.auditWriter = auditWriter;
+    this.auditRenderer = auditRenderer;
+
     writeHeaders(auditWriter);
   }
 
@@ -68,77 +49,8 @@
   }
 
   @Override
-  public void onAuditableAction(AuditEvent action) {
-    auditWriter.write(getFormattedAudit(action));
-  }
-
-  private String getFormattedAudit(AuditEvent action) {
-    return String.format(
-        "%1$s | %2$s | %3$s | %4$s | %5$s | %6$s | %7$s | %8$s | %9$s | %10$s",
-        action.uuid.uuid(),
-        getFormattedTS(action.when),
-        action.sessionId,
-        getFormattedAuditSingle(action.who),
-        getFormattedAuditSingle(action),
-        action.what,
-        getFormattedAuditList(action.params),
-        getFormattedAuditSingle(action.result),
-        getFormattedTS(action.timeAtStart),
-        action.elapsed);
-  }
-
-  private Object getFormattedAuditList(Multimap<String, ?> params) {
-    if (params == null || params.size() == 0) {
-      return "[]";
-    }
-
-    StringBuilder formattedOut = new StringBuilder("[");
-
-    Set<String> paramNames = new TreeSet<>(params.keySet());
-
-    int numParams = 0;
-    for (String paramName : paramNames) {
-      if (numParams++ > 0) {
-        formattedOut.append(",");
-      }
-      formattedOut.append(paramName);
-      formattedOut.append("=");
-      formattedOut.append(getFormattedAudit(params.get(paramName)));
-    }
-
-    formattedOut.append(']');
-
-    return formattedOut.toString();
-  }
-
-  private Object getFormattedAudit(Collection<? extends Object> values) {
-    StringBuilder out = new StringBuilder();
-    int numValues = 0;
-    for (Object object : values) {
-      if (numValues > 0) {
-        out.append(",");
-      }
-      out.append(getFormattedAuditSingle(object));
-      numValues++;
-    }
-
-    if (numValues > 1) {
-      return "[" + out.toString() + "]";
-    }
-    return out.toString();
-  }
-
-  private <T> String getFormattedAuditSingle(T result) {
-    if (result == null) return "";
-
-    @SuppressWarnings("unchecked")
-    AuditFormatter<T> fmt = (AuditFormatter<T>) AUDIT_FORMATTERS.get(result.getClass());
-    if (fmt == null) return result.toString();
-
-    return fmt.format(result);
-  }
-
-  private synchronized String getFormattedTS(long when) {
-    return dateFmt.format(new Date(when));
+  public void onAuditableAction(AuditEvent auditEvent) {
+    String auditString = auditRenderer.render(auditEvent);
+    auditWriter.write(auditString);
   }
 }