Index: src/main/java/org/apache/log4j/net/SocketHubAppender.java
===================================================================
--- src/main/java/org/apache/log4j/net/SocketHubAppender.java	(revision 592202)
+++ src/main/java/org/apache/log4j/net/SocketHubAppender.java	(working copy)
@@ -17,18 +17,18 @@
 
 package org.apache.log4j.net;
 
-import java.util.Vector;
-import java.net.Socket;
-import java.net.ServerSocket;
-import java.net.SocketException;
-import java.io.ObjectOutputStream;
 import java.io.IOException;
 import java.io.InterruptedIOException;
+import java.io.ObjectOutputStream;
 import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.Vector;
 
+import org.apache.log4j.AppenderSkeleton;
 import org.apache.log4j.helpers.LogLog;
 import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.AppenderSkeleton;
 
 /**
   Sends {@link LoggingEvent} objects to a set of remote log servers,
@@ -115,20 +115,19 @@
   private ServerMonitor serverMonitor = null;
   private boolean locationInfo = false;
   
-  public SocketHubAppender() { }
+    public SocketHubAppender() {
+    }
 
   /**
      Connects to remote server at <code>address</code> and <code>port</code>. */
-  public
-  SocketHubAppender(int _port) {
+    public SocketHubAppender(int _port) {
     port = _port;
     startServer();
   }
 
   /**
      Set up the socket server on the specified port.  */
-  public
-  void activateOptions() {
+    public void activateOptions() {
     startServer();
   }
 
@@ -136,9 +135,7 @@
      Close this appender. 
      <p>This will mark the appender as closed and
      call then {@link #cleanUp} method. */
-  synchronized
-  public
-  void close() {
+    synchronized public void close() {
     if(closed)
       return;
 
@@ -151,11 +148,12 @@
   /**
      Release the underlying ServerMonitor thread, and drop the connections
      to all connected remote servers. */
-  public 
-  void cleanUp() {
+    public void cleanUp() {
     // stop the monitor thread
 	LogLog.debug("stopping ServerSocket");
+        if (serverMonitor != null) {
     serverMonitor.stopMonitor();
+        }
     serverMonitor = null;
     
     // close all of the connections
@@ -165,8 +163,7 @@
       if(oos != null) {
         try {
         	oos.close();
-        }
-        catch(IOException e) {
+                } catch (IOException e) {
         	LogLog.error("could not close oos.", e);
         }
         
@@ -177,8 +174,7 @@
 
   /**
     Append an event to all of current connections. */
-  public
-  void append(LoggingEvent event) {
+    public void append(LoggingEvent event) {
 	// if no event or no open connections, exit now
     if(event == null || oosList.size() == 0)
       return;
@@ -194,8 +190,7 @@
       ObjectOutputStream oos = null;
       try {
         oos = (ObjectOutputStream)oosList.elementAt(streamCount);
-      }
-      catch (ArrayIndexOutOfBoundsException e) {
+            } catch (ArrayIndexOutOfBoundsException e) {
         // catch this, but just don't assign a value
         // this should not really occur as this method is
         // the only one that can remove oos's (besides cleanUp).
@@ -212,8 +207,7 @@
     	// then creates a serious memory leak.
     	// right now we always reset. TODO - set up frequency counter per oos?
     	oos.reset();
-      }
-      catch(IOException e) {
+            } catch (IOException e) {
       	// there was an io exception so just drop the connection
       	oosList.removeElementAt(streamCount);
       	LogLog.debug("dropped connection");
@@ -227,23 +221,25 @@
   /**
      The SocketHubAppender does not use a layout. Hence, this method returns
      <code>false</code>. */
-  public
-  boolean requiresLayout() {
+    public boolean requiresLayout() {
     return false;
   }
   
   /**
      The <b>Port</b> option takes a positive integer representing
-     the port where the server is waiting for connections. */
-  public
-  void setPort(int _port) {
+       the port where the server is waiting for connections, or 
+       if set to 0, signal to automatically choose a free port.
+       
+       If 0 is chosen, after {@link #activateOptions()} is called, {@link #getPort()}
+       will return the <i>actual</i> port in use.
+        */
+    public void setPort(int _port) {
     port = _port;
   }
   
   /**
      Returns value of the <b>Port</b> option. */
-  public
-  int getPort() {
+    public int getPort() {
     return port;
   }
   
@@ -251,43 +247,76 @@
      The <b>LocationInfo</b> option takes a boolean value. If true,
      the information sent to the remote host will include location
      information. By default no location information is sent to the server. */
-  public
-  void setLocationInfo(boolean _locationInfo) {
+    public void setLocationInfo(boolean _locationInfo) {
     locationInfo = _locationInfo;
   }
   
   /**
      Returns value of the <b>LocationInfo</b> option. */
-  public
-  boolean getLocationInfo() {
+    public boolean getLocationInfo() {
     return locationInfo;
   }
   
   /**
     Start the ServerMonitor thread. */
-  private
-  void startServer() {
+    private void startServer() {
     serverMonitor = new ServerMonitor(port, oosList);
+        /*
+         * Make sure that this SocketHubAppender exposes the same port 
+         * # that the serverMonitor is using.  If this object was configured
+         * with port == 0, then the SeverMonitor will assign a random port,
+         * so we need to update ourselves here.
+         */
+        this.port = serverMonitor.port;
   }
   
   /**
     This class is used internally to monitor a ServerSocket
     and register new connections in a vector passed in the
     constructor. */
-  private
-  class ServerMonitor implements Runnable {
+    private class ServerMonitor implements Runnable {
     private int port;
     private Vector oosList;
     private boolean keepRunning;
     private Thread monitorThread;
+        private ServerSocket serverSocket;
     
     /**
       Create a thread and start the monitor. */
-    public
-    ServerMonitor(int _port, Vector _oosList) {
+        public ServerMonitor(int _port, Vector _oosList) {
       port = _port;
       oosList = _oosList;
       keepRunning = true;
+            serverSocket = null;
+            try {
+                serverSocket = new ServerSocket(port);
+                serverSocket.setSoTimeout(1000);
+                /*
+                 * If we have been asked to choose a random port, then 
+                 * expose what port it was actually chosen.
+                 * 
+                 * This is useful for sub-classes that need to expose to their
+                 * clients on which port they need to connect on.
+                 */
+
+                /*
+                 * LOOK CAREFULLY
+                 * 
+                 * 'Tis odd, but at this point, getLocalPort returns 0, but then _after_ the call, the port
+                 * is set, so we ask it twice..  The first check in the if block effectively
+                 * choose the port...
+                 */
+                if (port == 0) {
+                    port = serverSocket.getLocalPort();
+                }
+            } catch (Exception e) {
+                LogLog
+                        .error(
+                                "exception setting timeout, shutting down server socket.",
+                                e);
+                keepRunning = false;
+                return;
+            }
       monitorThread = new Thread(this);
       monitorThread.setDaemon(true);
       monitorThread.start();
@@ -296,16 +325,13 @@
     /**
       Stops the monitor. This method will not return until
       the thread has finished executing. */
-    public
-    synchronized
-    void stopMonitor() {
+        public synchronized void stopMonitor() {
       if (keepRunning) {
     	LogLog.debug("server monitor thread shutting down");
         keepRunning = false;
         try {
           monitorThread.join();
-        }
-        catch (InterruptedException e) {
+                } catch (InterruptedException e) {
           // do nothing?
         }
         
@@ -318,41 +344,23 @@
     /**
       Method that runs, monitoring the ServerSocket and adding connections as
       they connect to the socket. */
-    public
-    void run() {
-      ServerSocket serverSocket = null;
-      try {
-        serverSocket = new ServerSocket(port);
-        serverSocket.setSoTimeout(1000);
-      }
-      catch (Exception e) {
-        LogLog.error("exception setting timeout, shutting down server socket.", e);
-        keepRunning = false;
-        return;
-      }
+        public void run() {
 
       try {
-    	try {
-        	serverSocket.setSoTimeout(1000);
-    	}
-    	catch (SocketException e) {
-          LogLog.error("exception setting timeout, shutting down server socket.", e);
-          return;
-    	}
       
     	while (keepRunning) {
           Socket socket = null;
           try {
             socket = serverSocket.accept();
-          }
-          catch (InterruptedIOException e) {
+                    } catch (InterruptedIOException e) {
             // timeout occurred, so just loop
-          }
-          catch (SocketException e) {
-            LogLog.error("exception accepting socket, shutting down server socket.", e);
+                    } catch (SocketException e) {
+                        LogLog
+                                .error(
+                                        "exception accepting socket, shutting down server socket.",
+                                        e);
             keepRunning = false;
-          }
-          catch (IOException e) {
+                    } catch (IOException e) {
             LogLog.error("exception accepting socket.", e);
           }
 	        
@@ -360,31 +368,32 @@
           if (socket != null) {
             try {
               InetAddress remoteAddress = socket.getInetAddress();
-              LogLog.debug("accepting connection from " + remoteAddress.getHostName() 
-			   + " (" + remoteAddress.getHostAddress() + ")");
+                            LogLog.debug("accepting connection from " +
+                                    remoteAddress.getHostName() + " (" +
+                                    remoteAddress.getHostAddress() + ")");
 	        	
               // create an ObjectOutputStream
-              ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
+                            ObjectOutputStream oos = new ObjectOutputStream(
+                                    socket.getOutputStream());
 	            
               // add it to the oosList.  OK since Vector is synchronized.
               oosList.addElement(oos);
-            }
-            catch (IOException e) {
-              LogLog.error("exception creating output stream on socket.", e);
-            }
+                        } catch (IOException e) {
+                            LogLog
+                                    .error(
+                                            "exception creating output stream on socket.",
+                                            e);
           }
         }
       }
-      finally {
+            } finally {
     	// close the socket
     	try {
     		serverSocket.close();
-    	}
-    	catch (IOException e) {
+                } catch (IOException e) {
     		// do nothing with it?
     	}
       }
     }
   }
 }
-
