Added ZeroConf support to most of the network-based appenders and receivers.

To enable ZeroConf advertising of an appender or receiver, a user can now:
 - add jmdns jar to their classpath 
 - set the 'advertiseViaMulticastDNS' param to 'true'

Also added support for discovery of appenders in Chainsaw (Chainsaw will automatically configure a matching receiver when connected).
Supported appenders:
    SocketAppender
    SocketHubAppender (ZeroConfSocketHubAppender is still functional)
    UDPAppender
    MulticastAppender
Supported receivers:
    SocketReceiver
    SocketHubReceiver (also receives events from ZeroConfSocketHubAppender)
    XMLSocketReceiver (can receive events sent over TCP by other logging frameworks)
    UDPReceiver
    MulticastReceiver

Implementation details:
 - removed Zeroconf4log4j class, jmdns access is now through the ZeroConfSupport class (class provides support of JmDNS and ServiceInfo creation via reflection, and supports both jmdns 1.0 and jmdns 3.1 apis)
 - ZeroConfSupport class is now used by ZeroConfSocketHubAppender, Chainsaw and all appenders & receivers that can advertise their configuration via ZeroConf
 - added new 'advertiseViaMulticastDNS' param to the appenders and receivers that support ZeroConf
 - updated the ZeroConf site documentation
 - updated release notes
 - updated the ZeroConfPlugin html file
 - tested appenders with 1.0 and 3.1 jmdns jars
 - updated log4j references in poms to log4j 1.2.16-snapshot where necessary 

For those wanting to add ZeroConf support to third-party appenders and have Chainsaw discover the appenders, the service info naming convention is described here: https://issues.apache.org/bugzilla/show_bug.cgi?id=48907


git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/companions/zeroconf/trunk@924176 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java b/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java
index 272663d..b24ff90 100644
--- a/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java
+++ b/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java
@@ -42,63 +42,18 @@
     public static final String DEFAULT_ZEROCONF_ZONE = "_log4j._tcp.local.";
     private String zeroConfZone = DEFAULT_ZEROCONF_ZONE;
 
-    private Object logger;
-    private Method logInfoMethod;
-    private Method logErrorMethod;
-
     private int actualPortUsed;
     private InetAddress actualAddressUsed;
+    private ZeroConfSupport zeroConfSupport;
 
     public ZeroConfSocketHubAppender() {
         setName("SocketHubAppender");
-        try {
-            Method getLoggerMethod = this.getClass().getMethod("getLogger",
-                    new Class[0]);
-            logger = getLoggerMethod.invoke(this, new Object[0]);
-            logInfoMethod = logger.getClass().getMethod("info",
-                    new Class[] { Object.class });
-            logErrorMethod = logger.getClass().getMethod("error",
-                    new Class[] { Object.class });
-        } catch (Exception e) {
-            // we're not in log4j1.3 land
-        }
     }
 
     public void activateOptions() {
         super.activateOptions();
-        try {
-            JmDNS jmDNS = Zeroconf4log4j.getInstance();
-            ServiceInfo info = buildServiceInfo();
-            logWithlog4j12Compatibility(Level.INFO,
-                    "Registering this SocketHubAppender as :" + info);
-            jmDNS.registerService(info);
-        } catch (IOException e) {
-            logWithlog4j12Compatibility(
-                    Level.ERROR,
-                    "Failed to instantiate JmDNS to broadcast via ZeroConf, will now operate in simple SocketHubAppender mode");
-        }
-    }
-
-    private ServiceInfo buildServiceInfo() {
-        return new ServiceInfo(zeroConfZone, getName(), actualPortUsed,
-                "SocketHubAppender on port " + this.actualPortUsed);
-    }
-
-    private void logWithlog4j12Compatibility(Level level, String message) {
-        if (logger != null && logInfoMethod != null & logErrorMethod != null) {
-            try {
-                switch (level.toInt()) {
-                case Level.INFO_INT:
-                    logInfoMethod.invoke(logger, new Object[] { message });
-                    break;
-                case Level.ERROR_INT:
-                    logInfoMethod.invoke(logger, new Object[] { message });
-                    break;
-                }
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
+        zeroConfSupport = new ZeroConfSupport(zeroConfZone, actualPortUsed, getName());
+        zeroConfSupport.advertise();
     }
 
     /**
@@ -127,16 +82,9 @@
 
     public synchronized void close() {
         super.close();
-        try {
-            JmDNS jmDNS = Zeroconf4log4j.getInstance();
-            ServiceInfo info = buildServiceInfo();
-            logWithlog4j12Compatibility(Level.INFO,
-                    "Deregistering this SocketHubAppender (" + info + ")");
-            jmDNS.unregisterService(info);
-        } catch (Exception e) {
-            logWithlog4j12Compatibility(
-                    Level.ERROR,
-                    "Failed to instantiate JmDNS to broadcast via ZeroConf, will now operate in simple SocketHubAppender mode");
+        if (zeroConfSupport != null)
+        {
+            zeroConfSupport.unadvertise();
         }
     }
 
diff --git a/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java b/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java
deleted file mode 100644
index da21625..0000000
--- a/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.log4j.net;
-
-import javax.jmdns.JmDNS;
-
-/**
- * This singleton holds the single instance of the JmDNS instance that is used to broadcast
- * Appender related information via ZeroConf.  Once referenced, a single JmDNS instance is created
- * and held.  To ensure your JVM exits cleanly you should ensure that you call the {@link #shutdown() } method
- * to broadcast the disappearance of your devices, and cleanup sockets.  (alternatively you can call the close() 
- * method on the JmDNS instead, totally up to you...)
- * 
- * See http://jmdns.sf.net for more information about JmDNS and ZeroConf.
- * 
- * @author psmith
- *
- */
-public class Zeroconf4log4j {
-
-    private static JmDNS instance;
-
-    /**
-     * Returns the current instance of the JmDNS being used by log4j.
-     * 
-     * @throws RuntimeException if JmDNS was not correctly initialized.
-     * 
-     * @return
-     */
-    public static synchronized JmDNS getInstance() {
-        if (instance == null) {
-            try {
-                instance = new JmDNS();
-            } catch (Exception e) {
-                throw new RuntimeException(
-                        "Failed to create an instance of JmDNS", e);
-            }
-        }
-        return instance;
-    }
-
-    /**
-     * Ensures JmDNS cleanly broadcasts 'goodbye' and closes any sockets, and (more importantly)
-     * ensures some Threads exit so your JVM can exit.
-     * 
-     * This clears an internal {@link JmDNS} variable so that a subsequent call to {@link #getInstance()}
-     * will initialize and create a new one.
-     *
-     */
-    public static void shutdown() {
-        if (instance != null) {
-            instance.close();
-            instance = null;
-        }
-    }
-}
diff --git a/src/test/java/org/apache/log4j/net/ZeroConfSocketHubAppenderTest.java b/src/test/java/org/apache/log4j/net/ZeroConfSocketHubAppenderTest.java
index 7e9930b..fb88e90 100644
--- a/src/test/java/org/apache/log4j/net/ZeroConfSocketHubAppenderTest.java
+++ b/src/test/java/org/apache/log4j/net/ZeroConfSocketHubAppenderTest.java
@@ -41,13 +41,12 @@
 
     protected void setUp() throws Exception {
         super.setUp();
-        jmdns = Zeroconf4log4j.getInstance();
+        jmdns = (JmDNS) ZeroConfSupport.getJMDNSInstance();
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        Zeroconf4log4j.shutdown();
-
+        jmdns.close();
     }
 
     /**