Support hostname resolution for cluster configuration

Change-Id: I9afb97bfba05366fa63dc7b9022b914bd2d1cce0
(cherry picked from commit 97cd95d5a2a7a1bf1f3bfd3091f2d66f747eee33)
diff --git a/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java b/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java
index 7c324f4..8bc4757 100644
--- a/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java
+++ b/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java
@@ -15,10 +15,12 @@
  */
 package org.onosproject.cluster;
 
-import org.onlab.packet.IpAddress;
-
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.Objects;
 
+import org.onlab.packet.IpAddress;
+
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -30,13 +32,14 @@
     public static final int DEFAULT_PORT = 9876;
 
     private final NodeId id;
-    private final IpAddress ip;
+    private final String host;
     private final int tcpPort;
+    private transient volatile IpAddress ip;
 
     // For serialization
     private DefaultControllerNode() {
         this.id = null;
-        this.ip = null;
+        this.host = null;
         this.tcpPort = 0;
     }
 
@@ -44,23 +47,44 @@
      * Creates a new instance with the specified id and IP address.
      *
      * @param id instance identifier
+     * @param host instance hostname
+     */
+    public DefaultControllerNode(NodeId id, String host) {
+        this(id, host, DEFAULT_PORT);
+    }
+
+    /**
+     * Creates a new instance with the specified id and IP address and TCP port.
+     *
+     * @param id instance identifier
+     * @param host instance host name
+     * @param tcpPort TCP port
+     */
+    public DefaultControllerNode(NodeId id, String host, int tcpPort) {
+        this.id = checkNotNull(id);
+        this.host = host;
+        this.tcpPort = tcpPort;
+    }
+
+    /**
+     * Creates a new instance with the specified id and IP address.
+     *
+     * @param id instance identifier
      * @param ip instance IP address
      */
     public DefaultControllerNode(NodeId id, IpAddress ip) {
-        this(id, ip, DEFAULT_PORT);
+        this(id, ip != null ? ip.toString() : null, DEFAULT_PORT);
     }
 
     /**
-     * Creates a new instance with the specified id and IP address and TCP port.
+     * Creates a new instance with the specified id and IP address.
      *
      * @param id instance identifier
      * @param ip instance IP address
      * @param tcpPort TCP port
      */
     public DefaultControllerNode(NodeId id, IpAddress ip, int tcpPort) {
-        this.id = checkNotNull(id);
-        this.ip = ip;
-        this.tcpPort = tcpPort;
+        this(id, ip != null ? ip.toString() : null, tcpPort);
     }
 
     @Override
@@ -69,10 +93,35 @@
     }
 
     @Override
-    public IpAddress ip() {
+    public String host() {
+        return host;
+    }
+
+    @Override
+    public IpAddress ip(boolean resolve) {
+        if (resolve) {
+            ip = resolveIp();
+            return ip;
+        }
+
+        if (ip == null) {
+            synchronized (this) {
+                if (ip == null) {
+                    ip = resolveIp();
+                }
+            }
+        }
         return ip;
     }
 
+    private IpAddress resolveIp() {
+        try {
+            return IpAddress.valueOf(InetAddress.getByName(host));
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
     @Override
     public int tcpPort() {
         return tcpPort;
@@ -97,8 +146,11 @@
 
     @Override
     public String toString() {
-        return toStringHelper(this).add("id", id)
-                .add("ip", ip).add("tcpPort", tcpPort).toString();
+        return toStringHelper(this)
+            .add("id", id)
+            .add("host", host)
+            .add("tcpPort", tcpPort)
+            .toString();
     }
 
 }