Fix Super Dev Mode's code server to launch on localhost by default.
(There were comments about this but it wasn't actually true.)
Add -bindAddress option to override this. In particular, -bindAddress 0.0.0.0
restores previous behavior.

Review at http://gwt-code-reviews.appspot.com/1740803

Review by: acleung@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11063 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
index aa44ef8..6419d86 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
@@ -23,6 +23,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.net.InetAddress;
 
 /**
  * <p>This class contains the {@link #main main method} that starts the code server for
@@ -49,9 +50,11 @@
     try {
       start(options);
 
+      String url = "http://" + options.getPreferredHost() + ":" + options.getPort() + "/";
+
       System.out.println();
       System.out.println("The code server is ready.");
-      System.out.println("Next, visit: http://localhost:" + options.getPort() + "/");
+      System.out.println("Next, visit: " + url);
     } catch (Throwable t) {
       t.printStackTrace();
       System.exit(1);
@@ -88,7 +91,7 @@
     SourceHandler sourceHandler = new SourceHandler(modules, logger);
 
     WebServer webServer = new WebServer(sourceHandler, modules,
-        options.getPort(), logger);
+        options.getBindAddress(), options.getPort(), logger);
     webServer.start();
 
     return webServer;
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java
index f4af813..2924e44 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java
@@ -21,8 +21,11 @@
 import com.google.gwt.util.tools.ArgHandlerDir;
 import com.google.gwt.util.tools.ArgHandlerExtra;
 import com.google.gwt.util.tools.ArgHandlerInt;
+import com.google.gwt.util.tools.ArgHandlerString;
 
 import java.io.File;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -35,6 +38,8 @@
   private File workDir;
   private List<String> moduleNames = new ArrayList<String>();
   private final List<File> sourcePath = new ArrayList<File>();
+  private String bindAddress = "127.0.0.1";
+  private String preferredHost = "localhost";
   private int port = 9876;
 
   /**
@@ -61,6 +66,20 @@
   }
 
   /**
+   * The IP address where the code server should listen.
+   */
+  String getBindAddress() {
+    return bindAddress;
+  }
+
+  /**
+   * The hostname to put in a URL pointing to the code server.
+   */
+  String getPreferredHost() {
+    return preferredHost;
+  }
+
+  /**
    * The port where the code server will listen for HTTP requests.
    */
   int getPort() {
@@ -74,6 +93,7 @@
   private class ArgProcessor extends ArgProcessorBase {
 
     public ArgProcessor() {
+      registerHandler(new BindAddressFlag());
       registerHandler(new PortFlag());
       registerHandler(new WorkDirFlag());
       registerHandler(new SourceFlag());
@@ -87,6 +107,43 @@
 
   }
 
+  private class BindAddressFlag extends ArgHandlerString {
+
+    @Override
+    public String getTag() {
+      return "-bindAddress";
+    }
+
+    @Override
+    public String[] getTagArgs() {
+      return new String[] {"address"};
+    }
+
+    @Override
+    public String getPurpose() {
+      return "The ip address of the code server. Defaults to 127.0.0.1.";
+    }
+
+    @Override
+    public boolean setString(String newValue) {
+      try {
+        InetAddress bindAddress = InetAddress.getByName(newValue);
+        if (bindAddress.isAnyLocalAddress()) {
+          preferredHost = InetAddress.getLocalHost().getHostName();
+        } else {
+          preferredHost = newValue;
+        }
+      } catch (UnknownHostException e) {
+        System.err.println("Can't resolve bind address: " + newValue);
+        return false;
+      }
+
+      // Save the original since there's no way to get it back from an InetAddress.
+      bindAddress = newValue;
+      return true;
+    }
+  }
+
   private class PortFlag extends ArgHandlerInt {
 
     @Override
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
index a850293..5f85a54 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
@@ -37,6 +37,7 @@
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Writer;
+import java.net.InetAddress;
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.HashMap;
@@ -83,13 +84,16 @@
 
   private final Modules modules;
 
+  private final String bindAddress;
   private final int port;
   private final TreeLogger logger;
   private Server server;
 
-  public WebServer(SourceHandler handler, Modules modules, int port, TreeLogger logger) {
+  WebServer(SourceHandler handler, Modules modules, String bindAddress, int port,
+      TreeLogger logger) {
     this.handler = handler;
     this.modules = modules;
+    this.bindAddress = bindAddress;
     this.port = port;
     this.logger = logger;
   }
@@ -97,6 +101,7 @@
   public void start() throws UnableToCompleteException {
 
     SelectChannelConnector connector = new SelectChannelConnector();
+    connector.setHost(bindAddress);
     connector.setPort(port);
     connector.setReuseAddress(false);
     connector.setSoLingerTime(0);