Add formatter for zip, jar and war files

The new ZipFormatter shows the list of directories and files that are
contained in the zip archive. This allows a reviewer to inspect the
archive content without downloading the file.

Change-Id: I1ffe3b4f507cb636a67ea89ddc75c541ca6380dc
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
index 65be419..d822faf 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/Module.java
@@ -31,6 +31,7 @@
 import com.googlesource.gerrit.plugins.xdocs.formatter.Formatter;
 import com.googlesource.gerrit.plugins.xdocs.formatter.MarkdownFormatter;
 import com.googlesource.gerrit.plugins.xdocs.formatter.PlainTextFormatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.ZipFormatter;
 
 import java.util.List;
 
@@ -57,6 +58,9 @@
     bind(Formatter.class)
         .annotatedWith(Exports.named(PlainTextFormatter.NAME))
         .to(PlainTextFormatter.class);
+    bind(Formatter.class)
+        .annotatedWith(Exports.named(ZipFormatter.NAME))
+        .to(ZipFormatter.class);
 
     DynamicSet.bind(binder(), ProjectWebLink.class)
         .to(XDocWebLink.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
index e84e1e4..1f86e69 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/XDocGlobalConfig.java
@@ -17,9 +17,12 @@
 import com.googlesource.gerrit.plugins.xdocs.formatter.AsciidoctorFormatter;
 import com.googlesource.gerrit.plugins.xdocs.formatter.MarkdownFormatter;
 import com.googlesource.gerrit.plugins.xdocs.formatter.PlainTextFormatter;
+import com.googlesource.gerrit.plugins.xdocs.formatter.ZipFormatter;
 
 import org.eclipse.jgit.lib.Config;
 
+import java.util.Arrays;
+
 public class XDocGlobalConfig {
   public static final String SECTION_FORMATTER = "formatter";
   public static final String KEY_ALLOW_HTML = "allowHtml";
@@ -49,5 +52,7 @@
         "text/x-markdown");
     cfg.setString(SECTION_FORMATTER, PlainTextFormatter.NAME, KEY_MIME_TYPE,
         "text/plain");
+    cfg.setStringList(SECTION_FORMATTER, ZipFormatter.NAME, KEY_EXT,
+        Arrays.asList("jar", "war", "zip"));
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/ZipFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/ZipFormatter.java
new file mode 100644
index 0000000..fcb9bd8
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/formatter/ZipFormatter.java
@@ -0,0 +1,77 @@
+// Copyright (C) 2014 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.xdocs.formatter;
+
+import com.google.inject.Inject;
+
+import com.googlesource.gerrit.plugins.xdocs.ConfigSection;
+
+import org.apache.commons.io.FileUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class ZipFormatter implements StreamFormatter {
+  public static final String NAME = "ZIP";
+
+  private final FormatterUtil util;
+  private final HtmlBuilder html;
+
+  @Inject
+  ZipFormatter(
+      Formatters formatters,
+      FormatterUtil formatterUtil,
+      HtmlBuilder html) {
+    this.util = formatterUtil;
+    this.html = html;
+  }
+
+  @Override
+  public String format(String projectName, String revision, ConfigSection globalCfg,
+      InputStream raw) throws IOException {
+    html.startDocument()
+        .openHead()
+        .closeHead()
+        .openBody()
+        .openTable()
+        .appendCellHeader("name")
+        .appendCellHeader("size")
+        .appendCellHeader("last modified");
+    try (ZipInputStream zip = new ZipInputStream(raw)) {
+      for (ZipEntry entry; (entry = zip.getNextEntry()) != null;) {
+        html.openRow()
+            .appendCell(entry.getName());
+        if (!entry.isDirectory()) {
+          if (entry.getSize() != -1) {
+            html.appendCell(FileUtils.byteCountToDisplaySize(entry.getSize()));
+          } else {
+            html.appendCell("n/a");
+          }
+        } else {
+          html.appendCell();
+        }
+        html.appendDateCell(entry.getTime())
+            .closeRow();
+      }
+    }
+    html.closeTable()
+        .closeBody()
+        .endDocument();
+
+    return util.applyCss(html.toString(), NAME, projectName);
+  }
+}
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index f7b2632..7477b6e 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -82,6 +82,13 @@
     <td><a href="../../../Documentation/licenses.html#Apache2_0">Apache2.0</a></td>
     <td><a href="http://commons.apache.org">http://commons.apache.org</a></td>
   </tr>
+  <tr>
+    <td><tt>ZipFormatter</tt></td>
+    <td><tt>ZIP</tt></td>
+    <td>Formatter for zip files.</td>
+    <td></td>
+    <td></td>
+  </tr>
 </table>
 
 <a id="htmlDiff">
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 26d773e..2b12b55 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -96,7 +96,7 @@
 	Overrides the [global configuration of `inheritCss`](#formatterInheritCss)
 	for this formatter.
 
-	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
 
 	Default: `true` (CSS is inherited)
 
@@ -111,7 +111,7 @@
 	Overrides the [global configuration of `cssTheme`](#formatterCssTheme)
 	for this formatter.
 
-	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
 
 	By default not set.
 
@@ -137,6 +137,7 @@
 
 * `ASCIIDOCTOR`: `@PLUGIN@/asciidoctor.css`
 * `MARKDOWN`: `@PLUGIN@/markdown.css`
+* `ZIP`: `@PLUGIN@/zip.css`
 
 If link:inheritCss[inheritCss] is set to true custom CSS files are
 inherited from parent projects.
@@ -158,6 +159,10 @@
     mimeType = text/x-markdown
   [formatter "PLAIN_TEXT"]
     mimeType = text/plain
+  [formatter "ZIP"]
+    ext = jar
+    ext = war
+    ext = zip
 ```
 
 Supported formatters:
@@ -165,6 +170,7 @@
 * `ASCIIDOCTOR`
 * `MARKDOWN`
 * `PLAIN_TEXT`
+* `ZIP`
 
 <a id="formatterExt">
 formatter.<formatter>.ext
@@ -243,7 +249,7 @@
 
 	Can be overridden on [project-level](#inheritCss).
 
-	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
 
 	Default: `true` (CSS is inherited)
 
@@ -256,7 +262,7 @@
 
 	Can be overridden on [project-level](#cssTheme).
 
-	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`
+	Supported for the following formatters: `ASCIIDOCTOR`, `MARKDOWN`, `ZIP`
 
 	By default not set.
 
@@ -295,3 +301,4 @@
 
 * `ASCIIDOCTOR`: `asciidoctor.css`
 * `MARKDOWN`: `markdown.css`
+* `ZIP`: `zip.css`