Author: sdeboy
Date: Wed Mar 17 07:16:06 2010
New Revision: 924176

URL: http://svn.apache.org/viewvc?rev=924176&view=rev
Log:
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

Modified:
    logging/chainsaw/trunk/pom.xml
    
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
    
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
    
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.html
    logging/chainsaw/trunk/src/site/apt/zeroconf.apt

Modified: logging/chainsaw/trunk/pom.xml
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/pom.xml?rev=924176&r1=924175&r2=924176&view=diff
==============================================================================
--- logging/chainsaw/trunk/pom.xml (original)
+++ logging/chainsaw/trunk/pom.xml Wed Mar 17 07:16:06 2010
@@ -349,7 +349,7 @@
     <dependency>
       <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
-      <version>1.2.16</version>
+      <version>1.2.16-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>xstream</groupId>

Modified: 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java?rev=924176&r1=924175&r2=924176&view=diff
==============================================================================
--- 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
 (original)
+++ 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
 Wed Mar 17 07:16:06 2010
@@ -10,8 +10,10 @@ import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import javax.jmdns.JmDNS;
 import javax.jmdns.ServiceEvent;
@@ -41,12 +43,17 @@ import org.apache.log4j.chainsaw.help.He
 import org.apache.log4j.chainsaw.icons.ChainsawIcons;
 import org.apache.log4j.chainsaw.plugins.GUIPluginSkeleton;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.net.MulticastReceiver;
 import org.apache.log4j.net.SocketHubReceiver;
-import org.apache.log4j.net.ZeroConfSocketHubAppender;
-import org.apache.log4j.net.Zeroconf4log4j;
+import org.apache.log4j.net.SocketReceiver;
+import org.apache.log4j.net.UDPReceiver;
+import org.apache.log4j.net.XMLSocketReceiver;
+import org.apache.log4j.net.ZeroConfSupport;
 import org.apache.log4j.plugins.Plugin;
 import org.apache.log4j.plugins.PluginEvent;
 import org.apache.log4j.plugins.PluginListener;
+import org.apache.log4j.plugins.Receiver;
 import org.apache.log4j.spi.LoggerRepositoryEx;
 
 import com.thoughtworks.xstream.XStream;
@@ -62,9 +69,6 @@ import com.thoughtworks.xstream.io.xml.D
  * TODO add the
  * default Zone, and the list of user-specified zones to a preferenceModel
  * 
- * To run this in trial mode, first run {...@link 
ZeroConfSocketHubAppenderTestBed}, then
- * run this class' main(..) method.
- * 
  * @author psmith
  * 
  */
@@ -80,8 +84,6 @@ public class ZeroConfPlugin extends GUIP
     
     private final JScrollPane scrollPane = new JScrollPane(deviceTable);
 
-    private JmDNS jmDNS;
-
     private ZeroConfPreferenceModel preferenceModel;
     
     private Map serviceInfoToReceiveMap = new HashMap();
@@ -97,13 +99,19 @@ public class ZeroConfPlugin extends GUIP
     });  
     
     private JMenuItem nothingToConnectTo = new JMenuItem("No devices 
discovered");
-    
+    private static final String MULTICAST_APPENDER_SERVICE_NAME = 
"_log4j_xml_mcast_appender.local.";
+    private static final String UDP_APPENDER_SERVICE_NAME = 
"_log4j_xml_udp_appender.local.";
+    private static final String XML_SOCKET_APPENDER_SERVICE_NAME = 
"_log4j_xml_tcpconnect_appender.local.";
+    private static final String SOCKET_APPENDER_SERVICE_NAME = 
"_log4j_obj_tcpconnect_appender.local.";
+    private static final String SOCKETHUB_APPENDER_SERVICE_NAME = 
"_log4j_obj_tcpaccept_appender.local.";
+    private JmDNS jmDNS;
+
     public ZeroConfPlugin() {
         setName("Zeroconf");
     }
 
     public void shutdown() {
-        Zeroconf4log4j.shutdown();
+        jmDNS.close();
         save();
     }
 
@@ -123,14 +131,10 @@ public class ZeroConfPlugin extends GUIP
 
     public void activateOptions() {
         setLayout(new BorderLayout());
-        jmDNS = Zeroconf4log4j.getInstance();
+        jmDNS = (JmDNS) ZeroConfSupport.getJMDNSInstance();
 
-        jmDNS.addServiceListener(
-                ZeroConfSocketHubAppender.DEFAULT_ZEROCONF_ZONE,
-                new ZeroConfServiceListener());
+        registerServiceListenersForAppenders();
 
-        
jmDNS.addServiceListener(ZeroConfSocketHubAppender.DEFAULT_ZEROCONF_ZONE, 
discoveredDevices);
-        
         deviceTable.addMouseListener(new ConnectorMouseListener());
 
         
@@ -179,7 +183,28 @@ public class ZeroConfPlugin extends GUIP
         discoveredDevices.setZeroConfPreferenceModel(preferenceModel);
         discoveredDevices.setZeroConfPluginParent(this);
     }
-    
+
+    private void registerServiceListenersForAppenders()
+    {
+        Set serviceNames = new HashSet();
+        serviceNames.add(MULTICAST_APPENDER_SERVICE_NAME);
+        serviceNames.add(SOCKET_APPENDER_SERVICE_NAME);
+        serviceNames.add(SOCKETHUB_APPENDER_SERVICE_NAME);
+        serviceNames.add(UDP_APPENDER_SERVICE_NAME);
+        serviceNames.add(XML_SOCKET_APPENDER_SERVICE_NAME);
+
+        for (Iterator iter = serviceNames.iterator(); iter.hasNext();) {
+            String serviceName = iter.next().toString();
+            jmDNS.addServiceListener(
+                    serviceName,
+                    new ZeroConfServiceListener());
+
+            jmDNS.addServiceListener(serviceName, discoveredDevices);
+        }
+
+        //now add each appender constant
+    }
+
     /**
      * Sets the icon of this parent container (a JTabbedPane, we hope
      *
@@ -286,7 +311,7 @@ public class ZeroConfPlugin extends GUIP
             connectToMenu.insert(connectToDeviceMenuItem,0);
         }
 //         if the device name is one of the autoconnect devices, then connect 
immediately
-        if (preferenceModel.getAutoConnectDevices().contains(name)) {
+        if (preferenceModel != null && preferenceModel.getAutoConnectDevices() 
!= null && preferenceModel.getAutoConnectDevices().contains(name)) {
             new Thread(new Runnable() {
 
                 public void run() {
@@ -432,15 +457,12 @@ public class ZeroConfPlugin extends GUIP
      */
     private void connectTo(ServiceInfo info) {
         LOG.info("Connection request for " + info);
-        int port = info.getPort();
-        String hostAddress = info.getHostAddress();
-       
-//        TODO handle different receivers than just SocketHubReceiver
-        SocketHubReceiver receiver = new SocketHubReceiver();
-        receiver.setHost(hostAddress);
-        receiver.setPort(port);
-        receiver.setName(info.getName());
-        
+        //Chainsaw can construct receivers from discovered appenders
+        Receiver receiver = getReceiver(info);
+        //if null, unable to resolve the service name..no-op
+        if (receiver == null) {
+            return;
+        }
         
((LoggerRepositoryEx)LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(receiver);
         receiver.activateOptions();
         LOG.info("Receiver '" + receiver.getName() + "' has been started");
@@ -460,6 +482,69 @@ public class ZeroConfPlugin extends GUIP
 //        discoveredDevices.fireContentsChanged();
     }
 
+    private Receiver getReceiver(ServiceInfo info) {
+        String zone = info.getType();
+        int port = info.getPort();
+        String hostAddress = info.getHostAddress();
+        String name = info.getName();
+        String decoderClass = info.getPropertyString("decoder");
+
+        //MulticastAppender
+        if (MULTICAST_APPENDER_SERVICE_NAME.equals(zone)) {
+            MulticastReceiver receiver = new MulticastReceiver();
+            //this needs to be a multicast address, not the host address, so 
we need to use a property
+            receiver.setAddress(info.getPropertyString("multicastAddress"));
+            receiver.setPort(port);
+            receiver.setName(name + "-receiver");
+            if (decoderClass != null && !decoderClass.equals("")) {
+                receiver.setDecoder(decoderClass);
+            }
+
+            return receiver;
+        }
+        //UDPAppender
+        if (UDP_APPENDER_SERVICE_NAME.equals(zone)) {
+            UDPReceiver receiver = new UDPReceiver();
+            receiver.setPort(port);
+            receiver.setName(name + "-receiver");
+            if (decoderClass != null && !decoderClass.equals("")) {
+                receiver.setDecoder(decoderClass);
+            }
+            return receiver;
+        }
+
+        //non-log4j XML-based socketappender
+        if (XML_SOCKET_APPENDER_SERVICE_NAME.equals(zone)) {
+            XMLSocketReceiver receiver = new XMLSocketReceiver();
+            receiver.setPort(port);
+            receiver.setName(name + "-receiver");
+            if (decoderClass != null && !decoderClass.equals("")) {
+                receiver.setDecoder(decoderClass);
+            }
+            return receiver;
+        }
+
+        //SocketAppender
+        if (SOCKET_APPENDER_SERVICE_NAME.equals(zone)) {
+            SocketReceiver receiver = new SocketReceiver();
+            receiver.setPort(port);
+            receiver.setName(name + "-receiver");
+            return receiver;
+        }
+
+        //SocketHubAppender
+        if (SOCKETHUB_APPENDER_SERVICE_NAME.equals(zone)) {
+            SocketHubReceiver receiver = new SocketHubReceiver();
+            receiver.setHost(hostAddress);
+            receiver.setPort(port);
+            receiver.setName(name + "-receiver");
+            return receiver;
+        }
+        //not recognized
+        LogLog.debug("Unable to find receiver for appender with service name: 
" + zone);
+        return null;
+    }
+
     /**
      * Finds the matching JMenuItem based on name, may return null if there is 
no match.
      * 

Modified: 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html?rev=924176&r1=924175&r2=924176&view=diff
==============================================================================
--- 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
 (original)
+++ 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
 Wed Mar 17 07:16:06 2010
@@ -10,6 +10,23 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is 
subject to change.  If you are experiencing problems displaying events in 
Chainsaw, please delete everything in the $user.dir/.chainsaw directory and 
restart Chainsaw.
 <br>
 <h1>1.99.99</h1>
+<h2>16 Mar 2010</h2>
+<ul>
+<li>
+Added ZeroConf support to most of the network-based appenders and receivers - 
just add the jmdns jar to your classpath and set the 'advertiseViaMulticastDNS' 
param to 'true'.  Also added
+support for discovery of these appenders in Chainsaw (once you 'connect' to an 
advertised appender, Chainsaw will automatically configure a matching 
receiver).<br>
+Supported appenders:
+    <ul>SocketAppender</ul>
+    <ul>SocketHubAppender (ZeroConfSocketHubAppender is still functional)</ul>
+    <ul>UDPAppender</ul>
+    <ul>MulticastAppender</ul>
+Supported receivers:
+    <ul>SocketReceiver</ul>
+    <ul>SocketHubReceiver (also receives events from 
ZeroConfSocketHubAppender)</ul>
+    <ul>XMLSocketReceiver (can receive events sent over TCP by other logging 
frameworks)</ul>
+    <ul>UDPReceiver</ul>
+    <ul>MulticastReceiver</ul>
+</ul>
 <h2>14 Mar 2010</h2>
 <ul>
 <li>

Modified: 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.html
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.html?rev=924176&r1=924175&r2=924176&view=diff
==============================================================================
--- 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.html
 (original)
+++ 
logging/chainsaw/trunk/src/main/resources/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.html
 Wed Mar 17 07:16:06 2010
@@ -20,7 +20,7 @@ devices on your local network such as pr
 Zeroconf is an open-standard that many vendors are using to reduce cost of 
configuration.  The <b>JmDNS</b> project
 is an Apache 2.0 licensed library that implements the ZeroConf protocol.  
Chainsaw and log4j use
 JmDNS to broadcast Appender information so that a matching Receiver can be 
easily created to connect to each other
-to stream logging messages into Chainsaw.  
+to stream logging messages into Chainsaw.
 </p>
 <p>
 <ul>
@@ -30,19 +30,16 @@ to stream logging messages into Chainsaw
 </p>
 <h2>Interesting... So what do I need to use ZeroConf with Chainsaw & 
log4j?</h2>
 <p>
-The log4j team has created an additional JAR file that can be added to your 
existing
-application to enable ZeroConf configuration. You just need to download the 
<code>log4j-zeroconf.jar</code> and the JmDNS package (you must use
-at least version 1.0 of JmDNS) and add 
-both JARs to your application's classpath. </p>
-<p> Then change your references from <code>SocketHubAppender</code>
-to <code><b>ZeroConf</b>SocketHubAppender</code>. (We recommend you change the 
'name' propety from it's default to make it easy for you to use, other
-wise it's name will appear as the default 'SocketHubAppender').
-</p>
+Most of the network-based appenders are ZeroConf-capable - all you have to do 
to use ZeroConf is to
+download the JmDNS package (at least version 1.0), add the JmDNS jar to your 
application's classpath, and set the "advertiseViaMulticastDNS"
+parameter to 'true' for any of the appenders or receivers you want to 
advertise (most of the time you will want to advertise appenders, so they can be
+automatically detected by Chainsaw).</p>
 <p>You're log4j.xml configuration file could be as simple as this:</p>
 <pre>
 &lt;log4j:configuration debug="false" threshold="debug"  
xmlns:log4j="http://jakarta.apache.org/log4j/&gt;
-    &lt;appender name="zeroconf" 
class="org.apache.log4j.net.ZeroConfSocketHubAppender"&gt;
+    &lt;appender name="zeroconf" 
class="org.apache.log4j.net.SocketHubAppender"&gt;
         &lt;param name="Name" value="MyZeroConfSockeHubAppender" /&gt;
+        &lt;param name="advertiseViaMulticastDNS" value="true" /&gt;
     &lt;/appender&gt;
     &lt;!--ROOT Logger--&gt;
     &lt;root&gt;
@@ -52,12 +49,16 @@ wise it's name will appear as the defaul
 &lt;/log4j:configuration&gt;
 </pre>
 <p>
-Once you have started your application using this new appender, then from 
within Chainsaw, the ZeroConf tab will show detected
-applications.  You can simply double click on the detected app, and Chainsaw 
will connect a Receiver to it.  You can even tick the "Auto-Connect"
+Once you have started your application using this configuration, from within 
Chainsaw, the ZeroConf tab will show detected
+applications.  You can simply double click on the detected appender and 
Chainsaw will connect a Receiver to it.  You can even tick the "Auto-Connect"
 check box, and next time Chainsaw see's this application, it will 
automatically connect to it.
 </p>
+<p>Most of the network-based Receivers are also ZeroConf capable, giving 
ZeroConf-aware appenders or applications
+the ability to discover the receivers and configure appenders to connect to 
those Receivers.
+</p>
 <h2>Cool... But I have some applications that use log4j 1.2.x.  Will it still 
work?</h2>
-<p>Yes.  We have designed a backward compatible mechanism to expose log4j 
1.2.x SocketHubAppender so that Chainsaw can detect it automatically.  
+<p>Yes.  We have designed a backward compatible mechanism to expose prior 
versions of log4j's SocketHubAppender (ZeroConfSocketHubAppender)
+so that Chainsaw can detect it automatically.
 </p>
 
 <h2>But... Surely there's a catch?</h2>

Modified: logging/chainsaw/trunk/src/site/apt/zeroconf.apt
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/site/apt/zeroconf.apt?rev=924176&r1=924175&r2=924176&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/site/apt/zeroconf.apt (original)
+++ logging/chainsaw/trunk/src/site/apt/zeroconf.apt Wed Mar 17 07:16:06 2010
@@ -14,21 +14,45 @@
 ~~ limitations under the License.
 ZeroConf - Zero Configuration
 
-       Chainsaw has ZeroConf elements embedded within it, but you'll need to 
add a few things to your application to enable your application for ZeroConf.
+    Chainsaw can use ZeroConf to discover advertised appenders and 
automatically configure a matching receiver, but you must update your 
configuration in order to advertise your appender via ZeroConf.
+    
+    If you are using a newer version of log4j (1.2.16 or greater), most of the 
network-based appenders are capable of advertising their configurations via 
ZeroConf, but have this
+capability disabled by default.
+    To advertise an appender via ZeroConf:
+        [[1]] Download {{{http://sourceforge.net/projects/jmdns/}JmDNS}}
 
-       Download:                                            
-       
-               [[1]] 
{{{http://logging.apache.org/log4j/docs/webstart/chainsaw/log4j-zeroconf.zip}log4j
 ZeroConf extension}}
-               
-               [[2]] {{{http://sourceforge.net/projects/jmdns/}JmDNS}}
-               
-               [[3]] Add the <log4j-zeroconf.jar> and the <jmdns.jar> from 
these bundles and add them to your application's classpath. 
-               
-               [[4]] Modify your log4j configuration so that it use the 
ZeroConfSocketHubAppender.  
-               
-       Here is a complete log4j.xml file that you can use as a base:
-       
-+-------------------------------+                                              
+        [[2]] Add the <jmdns.jar> to your application's classpath
+
+        [[3]] Modify your log4j configuration so that the appender is set to 
advertise its configuration via ZeroConf (by setting the 
'advertiseViaMulticastDNS' parameter to 'true')
+
+    Here is a complete log4j.xml file that you can use as a base 
SocketAppender configuration which advertises the appender via ZeroConf:</p>
+
++-------------------------------+
+<log4j:configuration debug="false" threshold="debug"  
xmlns:log4j="http://jakarta.apache.org/log4j/";>
+    <appender name="socketAppender" 
class="org.apache.log4j.net.SocketAppender">
+        <param name="Name" value="MySockeAppender" />
+        <param name="advertiseViaMulticastDNS" value="true" />
+    </appender>
+    <!--ROOT Logger-->
+    <root>
+        <level value="INFO" />
+        <appender-ref ref="socketAppender" />
+    </root>
+</log4j:configuration>
++-------------------------------+
+
+    If you are using an older version of log4j (prior to 1.2.16), 
ZeroConfSocketHubAppender is a ZeroConf-capable appender which is backward 
compatible with the prior versions of SocketHubAppender and can advertise the 
appender configuration via ZeroConf:</p>
+        [[1]] Download {{{http://sourceforge.net/projects/jmdns/}JmDNS}}
+
+        [[2]] Add the <i>jmdns.jar</i> to your application's classpath
+
+        [[3]] Download 
{{{http://logging.apache.org/log4j/docs/webstart/chainsaw/log4j-zeroconf.zip}log4j
 ZeroConf extension (provides ZeroConfSocketHubAppender)}}
+
+        [[4]] Add the <log4j-zeroconf.jar> to your application's classpath
+
+    Here is a complete log4j.xml file that you can use as a base 
ZeroConfSocketAppender configuration which advertises the appender via 
ZeroConf:</p>
+
++-------------------------------+
 <log4j:configuration debug="false" threshold="debug"  
xmlns:log4j="http://jakarta.apache.org/log4j/";>
     <appender name="zeroconf" 
class="org.apache.log4j.net.ZeroConfSocketHubAppender">
         <param name="Name" value="MyZeroConfSockeHubAppender" />
@@ -41,12 +65,8 @@ ZeroConf - Zero Configuration
 </log4j:configuration>
 +-------------------------------+
 
-       Once configured and your applicatiion started, you should be able to 
click on the Zeroconf tab inside Chainsaw, and see the 
"MyZeroConfSocketHubAppender" listed.  If you double click on the row, Chainsaw 
will automatically connect to your application and start receiving events.  You 
can tick the 'auto-connect' option to have Chainsaw immediately connect as soon 
as it sees your application started.  Great for Dev/QA environment.
-       
-       The Zeroconf-enabled SocketHubAppender broadcasts it's existence via a 
multicast protocol, passing enough information for Chainsaw to be able to 
connect to it.
-       
-Firewalls
+    Once you have enabled ZeroConf in your log4j configuration and started 
your application, you should be able to click on the Zeroconf tab inside 
Chainsaw and see the advertised appenders listed. If you double click on a row,
+Chainsaw will automatically connect to your application and start receiving 
events. You can tick the 'auto-connect' option to have Chainsaw immediately 
connect as soon as it sees your application started. Great for Dev/QA 
environment.</p>
 
-       Multicast protocols generally don't pass through firewall, so in a 
production environment Zeroconf won't work.
-       
-       
\ No newline at end of file
+Firewalls
+    Multicast protocols generally don't pass through firewall, so in a 
production environment Zeroconf won't work.</p>


Reply via email to