Add Download hostname override config (#2680)

* Add Download hostname override config

* Fix Checkstyle errors

* Move to regular command line flag

* Refactor to method

* Remove static var manipulation

* Fix whitespace
diff --git a/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/Runtime.java b/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/Runtime.java
index 1d959c2..14de304 100644
--- a/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/Runtime.java
+++ b/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/Runtime.java
@@ -54,7 +54,8 @@
     Port("port"),
     Property("D"),
     ReleaseFile("release-file"),
-    Verbose("verbose");
+    Verbose("verbose"),
+    DownloadHostName("download-hostname");
 
     final String name;
 
@@ -73,7 +74,7 @@
         .build();
 
     final Option baseTemplate = Option.builder()
-        .desc("Base configuration to use for deloying topologies")
+        .desc("Base configuration to use for deploying topologies")
         .longOpt(Flag.BaseTemplate.name)
         .hasArg()
         .argName(Flag.BaseTemplate.name)
@@ -119,6 +120,14 @@
         .required(false)
         .build();
 
+    final Option downloadHostName = Option.builder()
+        .desc("Download Hostname Override")
+        .longOpt(Flag.DownloadHostName.name)
+        .hasArg()
+        .argName(Flag.DownloadHostName.name)
+        .required(false)
+        .build();
+
     return new Options()
         .addOption(baseTemplate)
         .addOption(cluster)
@@ -126,7 +135,8 @@
         .addOption(port)
         .addOption(release)
         .addOption(property)
-        .addOption(verbose);
+        .addOption(verbose)
+        .addOption(downloadHostName);
   }
 
   private static Options constructHelpOptions() {
@@ -187,6 +197,13 @@
     return Constants.DEFAULT_PORT;
   }
 
+  private static String getDownloadHostName(CommandLine cmd) {
+    if (cmd.hasOption(Flag.DownloadHostName.name)) {
+      return String.valueOf(cmd.getOptionValue(Flag.DownloadHostName.name));
+    }
+    return null;
+  }
+
   private static String loadOverrides(CommandLine cmd) throws IOException {
     return ConfigUtils.createOverrideConfiguration(
         cmd.getOptionProperties(Flag.Property.name));
@@ -240,6 +257,7 @@
     final String releaseFile = getReleaseFile(toolsHome, cmd);
     final String configurationOverrides = loadOverrides(cmd);
     final int port = getPort(cmd);
+    final String downloadHostName = getDownloadHostName(cmd);
 
     final Config baseConfiguration =
         ConfigUtils.getBaseConfiguration(heronDirectory,
@@ -264,6 +282,8 @@
         configurationOverrides);
     contextHandler.setAttribute(HeronResource.ATTRIBUTE_PORT,
         String.valueOf(port));
+    contextHandler.setAttribute(HeronResource.ATTRIBUTE_DOWNLOAD_HOSTNAME,
+        String.valueOf(downloadHostName));
 
     server.setHandler(contextHandler);
 
diff --git a/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/FileResource.java b/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/FileResource.java
index 869ec8f..b94c912 100644
--- a/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/FileResource.java
+++ b/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/FileResource.java
@@ -31,6 +31,7 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.StreamingOutput;
 
+import org.eclipse.jetty.util.StringUtil;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
 import org.slf4j.Logger;
@@ -52,6 +53,9 @@
   private static final String FILE_SYSTEM_DIRECTORY
       = "heron.apiserver.http.file.system.directory";
 
+  private static final String DOWNLOAD_HOSTNAME_OVERRIDE
+      = "heron.apiserver.http.download.hostname";
+
   private static InetAddress ip;
   private static String hostname;
 
@@ -60,10 +64,13 @@
       ip = InetAddress.getLocalHost();
       hostname = ip.getHostName();
     } catch (UnknownHostException e) {
-      LOG.info("Failed or resolve IP address of localhost");
+      LOG.info("Failed to resolve IP address of localhost");
     }
   }
 
+/**
+ * Endpoints for artifacts upload
+ */
   @POST
   @Path("/upload")
   @Consumes(MediaType.MULTIPART_FORM_DATA)
@@ -90,9 +97,9 @@
 
     String uploadDir = config.getStringValue(FILE_SYSTEM_DIRECTORY);
 
-    String fileName = UUID.randomUUID() + "-" + fileDetail.getFileName();
+    final String fileName = UUID.randomUUID() + "-" + fileDetail.getFileName();
 
-    String uploadedFileLocation
+    final String uploadedFileLocation
         = uploadDir + "/" + fileName;
 
     // save it
@@ -107,11 +114,14 @@
     }
 
     String uri = String.format("http://%s:%s/api/v1/file/download/%s",
-        (hostname != null) ? hostname : ip, getPort(), fileName);
+        getHostNameOrIP(), getPort(), fileName);
 
     return Response.status(Response.Status.OK).entity(uri).build();
   }
 
+/**
+ * Endpoints for artifacts download
+ */
   @GET
   @Path("/download/{file}")
   public Response downloadPdfFile(final @PathParam("file") String file) {
@@ -143,4 +153,12 @@
     return Config.toLocalMode(builder.build());
   }
 
+  private String getHostNameOrIP() {
+    // Override hostname if provided in flags
+    if (StringUtil.isNotBlank(getDownloadHostName())) {
+      return getDownloadHostName();
+    }
+    return (hostname != null) ? hostname : ((ip != null) ? ip.toString() : "");
+  }
+
 }
diff --git a/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/HeronResource.java b/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/HeronResource.java
index 7eb2702..6ed1e66 100644
--- a/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/HeronResource.java
+++ b/heron/tools/apiserver/src/java/com/twitter/heron/apiserver/resources/HeronResource.java
@@ -25,6 +25,7 @@
   public static final String ATTRIBUTE_CONFIGURATION_DIRECTORY = "configuration_directory";
   public static final String ATTRIBUTE_CONFIGURATION_OVERRIDE_PATH = "configuration_override";
   public static final String ATTRIBUTE_PORT = "port";
+  public static final String ATTRIBUTE_DOWNLOAD_HOSTNAME = "download_hostname";
 
   @Context
   protected ServletContext servletContext;
@@ -34,6 +35,7 @@
   private String configurationOverridePath;
   private String cluster;
   private String port;
+  private String downloadHostname;
 
   Config getBaseConfiguration() {
     if (baseConfiguration == null) {
@@ -74,4 +76,13 @@
 
     return port;
   }
+
+  String getDownloadHostName() {
+    if (downloadHostname == null) {
+      downloadHostname = (String) servletContext.getAttribute(ATTRIBUTE_DOWNLOAD_HOSTNAME);
+    }
+
+    return downloadHostname;
+  }
+
 }