Merge branch 'release-0.9.4-pre-rc' into master

Change-Id: I5c0f14671f13c4415d1377f5044925032dd77cd1
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
index 6faa8dd..153a32d 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
@@ -215,8 +215,8 @@
         clusterIPC.start();
         clientIPC.start();
         webServer.start();
-        info = new ClusterControllerInfo(ccId, ccConfig.getClientListenAddress(), ccConfig.getClientListenPort(),
-                webServer.getListeningPort());
+        info = new ClusterControllerInfo(ccId, ccConfig.getClientPublicAddress(), ccConfig.getClientPublicPort(),
+                ccConfig.getConsolePublicPort());
         timer.schedule(sweeper, 0, ccConfig.getHeartbeatPeriodMillis());
         jobLog.open();
         startApplication();
@@ -409,7 +409,7 @@
     }
 
     public NetworkAddress getDatasetDirectoryServiceInfo() {
-        return new NetworkAddress(ccConfig.getClientListenAddress(), ccConfig.getClientListenPort());
+        return new NetworkAddress(ccConfig.getClientPublicAddress(), ccConfig.getClientPublicPort());
     }
 
     public JobIdFactory getJobIdFactory() {
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
index 889e140..f83df6e 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
@@ -45,14 +45,19 @@
     public enum Option implements IOption {
         APP_CLASS(STRING, (String) null),
         ADDRESS(STRING, InetAddress.getLoopbackAddress().getHostAddress()),
+        PUBLIC_ADDRESS(STRING, ADDRESS),
         CLUSTER_LISTEN_ADDRESS(STRING, ADDRESS),
         CLUSTER_LISTEN_PORT(INTEGER, 1099),
-        CLUSTER_PUBLIC_ADDRESS(STRING, CLUSTER_LISTEN_ADDRESS),
+        CLUSTER_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
         CLUSTER_PUBLIC_PORT(INTEGER, CLUSTER_LISTEN_PORT),
         CLIENT_LISTEN_ADDRESS(STRING, ADDRESS),
         CLIENT_LISTEN_PORT(INTEGER, 1098),
+        CLIENT_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
+        CLIENT_PUBLIC_PORT(INTEGER, CLIENT_LISTEN_PORT),
         CONSOLE_LISTEN_ADDRESS(STRING, ADDRESS),
         CONSOLE_LISTEN_PORT(INTEGER, 16001),
+        CONSOLE_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
+        CONSOLE_PUBLIC_PORT(INTEGER, CONSOLE_LISTEN_PORT),
         HEARTBEAT_PERIOD(LONG, 10000L), // TODO (mblow): add time unit
         HEARTBEAT_MAX_MISSES(INTEGER, 5),
         PROFILE_DUMP_PERIOD(INTEGER, 0),
@@ -118,6 +123,10 @@
                     return "Application CC main class";
                 case ADDRESS:
                     return "Default bind address for all services on this cluster controller";
+                case PUBLIC_ADDRESS:
+                    return "Default public address that other processes should use to contact this cluster controller. "
+                            + "All services will advertise this address unless a service-specific public address is "
+                            + "supplied.";
                 case CLUSTER_LISTEN_ADDRESS:
                     return "Sets the IP Address to listen for connections from NCs";
                 case CLUSTER_LISTEN_PORT:
@@ -130,10 +139,18 @@
                     return "Sets the IP Address to listen for connections from clients";
                 case CLIENT_LISTEN_PORT:
                     return "Sets the port to listen for connections from clients";
+                case CLIENT_PUBLIC_ADDRESS:
+                    return "The IP Address which clients should use to connect";
+                case CLIENT_PUBLIC_PORT:
+                    return "The port which clients should use to connect";
                 case CONSOLE_LISTEN_ADDRESS:
                     return "Sets the listen address for the Cluster Controller";
                 case CONSOLE_LISTEN_PORT:
                     return "Sets the http port for the Cluster Controller)";
+                case CONSOLE_PUBLIC_ADDRESS:
+                    return "Sets the address on which to contact the http console for the Cluster Controller";
+                case CONSOLE_PUBLIC_PORT:
+                    return "Sets the port on which to contact the http console for the Cluster Controller)";
                 case HEARTBEAT_PERIOD:
                     return "Sets the time duration between two heartbeats from each node controller in milliseconds";
                 case HEARTBEAT_MAX_MISSES:
@@ -261,6 +278,22 @@
         configManager.set(Option.CLIENT_LISTEN_PORT, clientListenPort);
     }
 
+    public String getClientPublicAddress() {
+        return getAppConfig().getString(Option.CLIENT_PUBLIC_ADDRESS);
+    }
+
+    public void setClientPublicAddress(String clientPublicAddress) {
+        configManager.set(Option.CLIENT_PUBLIC_ADDRESS, clientPublicAddress);
+    }
+
+    public int getClientPublicPort() {
+        return getAppConfig().getInt(Option.CLIENT_PUBLIC_PORT);
+    }
+
+    public void setClientPublicPort(int clientPublicPort) {
+        configManager.set(Option.CLIENT_PUBLIC_PORT, clientPublicPort);
+    }
+
     public int getConsoleListenPort() {
         return getAppConfig().getInt(Option.CONSOLE_LISTEN_PORT);
     }
@@ -269,6 +302,14 @@
         configManager.set(Option.CONSOLE_LISTEN_PORT, consoleListenPort);
     }
 
+    public int getConsolePublicPort() {
+        return getAppConfig().getInt(Option.CONSOLE_PUBLIC_PORT);
+    }
+
+    public void setConsolePublicPort(int consolePublicPort) {
+        configManager.set(Option.CONSOLE_PUBLIC_PORT, consolePublicPort);
+    }
+
     public long getHeartbeatPeriodMillis() {
         return getAppConfig().getLong(Option.HEARTBEAT_PERIOD);
     }
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
index 75c0827..aa3260d 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
@@ -21,7 +21,6 @@
 import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER;
 import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
 import static org.apache.hyracks.control.common.config.OptionTypes.LONG;
-import static org.apache.hyracks.control.common.config.OptionTypes.SHORT;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
 import static org.apache.hyracks.control.common.config.OptionTypes.STRING_ARRAY;
 
@@ -34,7 +33,6 @@
 import org.apache.hyracks.api.config.IOption;
 import org.apache.hyracks.api.config.IOptionType;
 import org.apache.hyracks.api.config.Section;
-import org.apache.hyracks.api.control.CcId;
 import org.apache.hyracks.control.common.config.ConfigManager;
 import org.apache.hyracks.util.file.FileUtil;
 
@@ -65,10 +63,10 @@
         MESSAGING_LISTEN_PORT(INTEGER, 0),
         MESSAGING_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
         MESSAGING_PUBLIC_PORT(INTEGER, MESSAGING_LISTEN_PORT),
-        REPLICATION_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
-        REPLICATION_PUBLIC_PORT(INTEGER, 2000),
         REPLICATION_LISTEN_ADDRESS(STRING, ADDRESS),
         REPLICATION_LISTEN_PORT(INTEGER, 2000),
+        REPLICATION_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
+        REPLICATION_PUBLIC_PORT(INTEGER, REPLICATION_LISTEN_PORT),
         CLUSTER_CONNECT_RETRIES(INTEGER, 5),
         IODEVICES(
                 STRING_ARRAY,
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java
index 1b1a1e0..247c001 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/MXHelper.java
@@ -28,6 +28,7 @@
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.commons.lang3.SystemUtils;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -44,16 +45,21 @@
     private static Method getMaxFileDescriptorCount;
 
     static {
-        try {
-            getOpenFileDescriptorCount = osMXBean.getClass().getMethod("getOpenFileDescriptorCount");
-            getMaxFileDescriptorCount = osMXBean.getClass().getDeclaredMethod("getMaxFileDescriptorCount");
-            getOpenFileDescriptorCount.setAccessible(true);
-            getMaxFileDescriptorCount.setAccessible(true);
-        } catch (Throwable th) { // NOSONAR: diagnostic code shouldn't cause server failure
-            getOpenFileDescriptorCount = null;
-            getMaxFileDescriptorCount = null;
-            LOGGER.log(Level.WARN, "Failed setting up the methods to get the number of file descriptors through {}",
-                    osMXBean.getClass().getName(), th);
+        if (SystemUtils.IS_OS_WINDOWS) {
+            LOGGER.info("Access to file descriptors (FDs) is not available on Windows; FD info will not be logged");
+        } else {
+            Class<? extends OperatingSystemMXBean> osMXBeanClass = osMXBean.getClass();
+            try {
+                getOpenFileDescriptorCount = osMXBeanClass.getMethod("getOpenFileDescriptorCount");
+                getMaxFileDescriptorCount = osMXBeanClass.getDeclaredMethod("getMaxFileDescriptorCount");
+                getOpenFileDescriptorCount.setAccessible(true);
+                getMaxFileDescriptorCount.setAccessible(true);
+            } catch (Throwable th) { // NOSONAR: diagnostic code shouldn't cause server failure
+                getOpenFileDescriptorCount = null;
+                getMaxFileDescriptorCount = null;
+                LOGGER.warn("Failed setting up the methods to get the number of file descriptors through {}",
+                        osMXBeanClass.getName(), th);
+            }
         }
     }