Refactor SSH Commands

... in preparation for implementation of other interfaces (such as
REST interface)

Change-Id: I3f0ec2fda93fa618aec19bdeee6aad83d497c59c
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifest.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifestCommand.java
similarity index 67%
rename from src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifest.java
rename to src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifestCommand.java
index 68e772d..b508589 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifest.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/BranchManifestCommand.java
@@ -33,7 +33,7 @@
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
 @CommandMetaData(name = "branch", description = "branch all projects described in a manifest on the server")
-public class BranchManifest extends SshCommand {
+public class BranchManifestCommand extends SshCommand {
 
   @Inject
   private GitRepositoryManager gitRepoManager;
@@ -54,6 +54,10 @@
       usage = "", required = true)
   private String newBranch;
 
+  @Option(name = "-o", aliases = {"--output-type"},
+      usage = "", required = false)
+  private Utilities.OutputType outputType;
+
   @Override
   protected void run() {
     stdout.println("Branching manifest:");
@@ -61,32 +65,9 @@
     stdout.println(manifestCommitish);
     stdout.println(manifestPath);
 
+    Utilities.branchManifest(gitRepoManager, manifestRepo, manifestCommitish,
+        manifestPath, newBranch, stdout, stderr,
+        outputType==Utilities.OutputType.JSON);
 
-    Project.NameKey p = new Project.NameKey(manifestRepo);
-    try {
-      Repository repo = gitRepoManager.openRepository(p);
-      ObjectId commitId = repo.resolve(manifestCommitish);
-      VersionedManifests vManifests = new VersionedManifests(manifestCommitish);
-      vManifests.load(repo, commitId);
-      CanonicalManifest manifests = new CanonicalManifest(vManifests);
-
-      Manifest manifest = manifests.getCanonicalManifest(manifestPath);
-
-      stdout.println("");
-      stdout.println("Branch '" + newBranch +
-          "' will be created for the following projects:");
-      for (com.amd.gerrit.plugins.manifestsubscription.manifest.Project proj :
-            manifest.getProject()) {
-        stdout.print(proj.getRevision());
-        stdout.print("\t");
-        stdout.println(proj.getName());
-      }
-
-      VersionedManifests.branchManifest(gitRepoManager, manifest, newBranch);
-
-    } catch (IOException | ConfigInvalidException | ManifestReadException |
-        JAXBException | GitAPIException e) {
-      e.printStackTrace(stderr);
-    }
   }
 }
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ShowSubscription.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ShowSubscriptionCommand.java
similarity index 66%
rename from src/main/java/com/amd/gerrit/plugins/manifestsubscription/ShowSubscription.java
rename to src/main/java/com/amd/gerrit/plugins/manifestsubscription/ShowSubscriptionCommand.java
index 6837311..786bb56 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ShowSubscription.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/ShowSubscriptionCommand.java
@@ -20,32 +20,24 @@
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
 
+import org.kohsuke.args4j.Option;
+
 import java.util.Set;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
 @CommandMetaData(name = "show", description = "Show states of manifest-subscription")
-public class ShowSubscription extends SshCommand {
+public class ShowSubscriptionCommand extends SshCommand {
 
   @Inject
   private ManifestSubscription manifestSubscription;
 
+  @Option(name = "-o", aliases = {"--output-type"},
+      usage = "", required = false)
+  private Utilities.OutputType outputType;
+
   @Override
-  protected void run() throws UnloggedFailure, Failure, Exception {
-    stdout.println("Enabled manifest repositories:");
-
-    Set<String> repos = manifestSubscription.getEnabledManifestSource();
-    Set<ProjectBranchKey> projects = manifestSubscription.getSubscribedProjects();
-
-    for (String repo : repos) {
-      stdout.println(repo);
-    }
-
-    stdout.println("");
-    stdout.println("Monitoring projects:");
-
-    for (ProjectBranchKey project : projects) {
-      stdout.println(project.getProject() + " | " + project.getBranch());
-    }
-
+  protected void run() {
+    Utilities.showSubscription(manifestSubscription, stdout,
+        outputType==Utilities.OutputType.JSON);
   }
 }
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java
index 5137cc5..c514182 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/SshModule.java
@@ -19,8 +19,8 @@
 class SshModule extends PluginCommandModule {
   @Override
   protected void configureCommands() {
-    command(ShowSubscription.class);
-    command(BranchManifest.class);
-    command(TagManifest.class);
+    command(ShowSubscriptionCommand.class);
+    command(BranchManifestCommand.class);
+    command(TagManifestCommand.class);
   }
 }
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/TagManifest.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/TagManifestCommand.java
similarity index 67%
rename from src/main/java/com/amd/gerrit/plugins/manifestsubscription/TagManifest.java
rename to src/main/java/com/amd/gerrit/plugins/manifestsubscription/TagManifestCommand.java
index 71e5aa6..b6e91b9 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/TagManifest.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/TagManifestCommand.java
@@ -33,7 +33,7 @@
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
 @CommandMetaData(name = "tag", description = "tag all projects described in a manifest on the server")
-public class TagManifest extends SshCommand {
+public class TagManifestCommand extends SshCommand {
 
   @Inject
   private GitRepositoryManager gitRepoManager;
@@ -54,6 +54,10 @@
       usage = "", required = true)
   private String newTag;
 
+  @Option(name = "-o", aliases = {"--output-type"},
+      usage = "", required = false)
+  private Utilities.OutputType outputType;
+
   @Override
   protected void run() {
     stdout.println("Tagging manifest:");
@@ -61,32 +65,8 @@
     stdout.println(manifestCommitish);
     stdout.println(manifestPath);
 
-
-    Project.NameKey p = new Project.NameKey(manifestRepo);
-    try {
-      Repository repo = gitRepoManager.openRepository(p);
-      ObjectId commitId = repo.resolve(manifestCommitish);
-      VersionedManifests vManifests = new VersionedManifests(manifestCommitish);
-      vManifests.load(repo, commitId);
-      CanonicalManifest manifests = new CanonicalManifest(vManifests);
-
-      Manifest manifest = manifests.getCanonicalManifest(manifestPath);
-
-      stdout.println("");
-      stdout.println("Tag '" + newTag +
-          "' will be created for the following projects:");
-      for (com.amd.gerrit.plugins.manifestsubscription.manifest.Project proj :
-            manifest.getProject()) {
-        stdout.print(proj.getRevision());
-        stdout.print("\t");
-        stdout.println(proj.getName());
-      }
-
-      VersionedManifests.tagManifest(gitRepoManager, manifest, newTag);
-
-    } catch (IOException | ConfigInvalidException | ManifestReadException |
-        JAXBException | GitAPIException e) {
-      e.printStackTrace(stderr);
-    }
+    Utilities.tagManifest(gitRepoManager, manifestRepo, manifestCommitish,
+        manifestPath, newTag, stdout, stderr,
+        outputType==Utilities.OutputType.JSON);
   }
 }
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/Utilities.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/Utilities.java
new file mode 100644
index 0000000..8a8a2d8
--- /dev/null
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/Utilities.java
@@ -0,0 +1,186 @@
+// Copyright (C) 2016 Advanced Micro Devices, Inc.  All rights reserved.
+//
+// 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.amd.gerrit.plugins.manifestsubscription;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Maps;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import com.amd.gerrit.plugins.manifestsubscription.manifest.Manifest;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.bind.JAXBException;
+
+public class Utilities {
+  private static Gson gson = new GsonBuilder()
+      .generateNonExecutableJson()
+      .setPrettyPrinting()
+      .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+      .create();
+
+  public enum OutputType {
+    TEXT,
+    JSON
+  }
+
+  static Manifest getManifest(GitRepositoryManager gitRepoManager,
+                             String manifestRepo, String manifestCommitish,
+                             String manifestPath)
+      throws ManifestReadException, IOException, ConfigInvalidException,
+                                                                 JAXBException {
+
+    Project.NameKey p = new Project.NameKey(manifestRepo);
+
+    Repository repo = gitRepoManager.openRepository(p);
+    ObjectId commitId = repo.resolve(manifestCommitish);
+    VersionedManifests vManifests = new VersionedManifests(manifestCommitish);
+    vManifests.load(repo, commitId);
+    CanonicalManifest manifests = new CanonicalManifest(vManifests);
+
+    return manifests.getCanonicalManifest(manifestPath);
+  }
+
+  private static void outputError(Writer output, PrintWriter error,
+                                  boolean inJSON, Exception e) {
+    if (inJSON) {
+      Map<String, Map<String, String>> errorJSON = Maps.newHashMap();
+      errorJSON.put("error", Maps.<String, String>newHashMap());
+      errorJSON.get("error").put("message",
+          Throwables.getStackTraceAsString(e));
+
+      gson.toJson(errorJSON, output);
+    } else {
+      e.printStackTrace(error);
+    }
+  }
+
+  private static void outputSuccess(String type, String newRef, Writer output,
+                                    boolean inJSON, Manifest manifest) {
+    if (inJSON) {
+      gson.toJson(manifest, output);
+    } else {
+      PrintWriter stdout;
+      if (output instanceof PrintWriter) {
+        stdout = (PrintWriter) output;
+      } else {
+        stdout = new PrintWriter(output);
+      }
+
+      stdout.println("");
+      stdout.println(type + " '" + newRef +
+          "' will be created for the following projects:");
+      for (com.amd.gerrit.plugins.manifestsubscription.manifest.Project proj :
+          manifest.getProject()) {
+        stdout.print(proj.getRevision());
+        stdout.print("\t");
+        stdout.println(proj.getName());
+      }
+    }
+  }
+
+  static void branchManifest(GitRepositoryManager gitRepoManager,
+                             String manifestRepo, String manifestCommitish,
+                             String manifestPath, String newBranch,
+                             Writer output, PrintWriter error, boolean inJSON) {
+
+    Manifest manifest;
+    try {
+      manifest = getManifest(gitRepoManager, manifestRepo,
+                              manifestCommitish, manifestPath);
+      VersionedManifests.branchManifest(gitRepoManager, manifest, newBranch);
+
+    } catch (IOException | ConfigInvalidException | ManifestReadException |
+        JAXBException | GitAPIException e) {
+      outputError(output, error, inJSON, e);
+      return;
+    }
+
+    outputSuccess("Branch", newBranch, output, inJSON, manifest);
+  }
+
+  static void tagManifest(GitRepositoryManager gitRepoManager,
+                             String manifestRepo, String manifestCommitish,
+                             String manifestPath, String newTag,
+                             Writer output, PrintWriter error, boolean inJSON) {
+
+    Manifest manifest;
+    try {
+      manifest = getManifest(gitRepoManager, manifestRepo,
+          manifestCommitish, manifestPath);
+      VersionedManifests.tagManifest(gitRepoManager, manifest, newTag);
+
+    } catch (IOException | ConfigInvalidException | ManifestReadException |
+        JAXBException | GitAPIException e) {
+      outputError(output, error, inJSON, e);
+      return;
+    }
+
+    outputSuccess("Tag", newTag, output, inJSON, manifest);
+  }
+
+  static void showSubscription(ManifestSubscription manifestSubscription,
+                               Writer output, boolean inJSON) {
+
+    Set<String> repos = manifestSubscription.getEnabledManifestSource();
+    Set<ProjectBranchKey> projects = manifestSubscription.getSubscribedProjects();
+    
+
+    if (inJSON) {
+
+      Map<String, Set> result = Maps.newHashMap();
+
+      result.put("manifest_subscriptions", repos);
+      result.put("monitored_projects", projects);
+
+      gson.toJson(result, output);
+
+    } else {
+      PrintWriter writer;
+      if (output instanceof PrintWriter) {
+        writer = (PrintWriter) output;
+      } else {
+        writer = new PrintWriter(output);
+      }
+
+      writer.println("Enabled manifest repositories:");
+
+      for (String repo : repos) {
+        writer.println(repo);
+      }
+
+      writer.println("");
+      writer.println("Monitoring projects:");
+
+      for (ProjectBranchKey project : projects) {
+        writer.println(project.getProject() + " | " + project.getBranch());
+      }
+
+    }
+  }
+}
diff --git a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java
index 137724f..3e1f8d3 100644
--- a/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java
+++ b/src/main/java/com/amd/gerrit/plugins/manifestsubscription/VersionedManifests.java
@@ -23,9 +23,6 @@
 import com.google.gerrit.server.git.VersionedMetaData;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.jgit.api.errors.InvalidRefNameException;
-import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
-import org.eclipse.jgit.api.errors.RefNotFoundException;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.PersonIdent;