Relocating the zeroconf to a seperate companion module.
git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/companions/zeroconf/trunk@546009 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
new file mode 100644
index 0000000..f6a06d2
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java
@@ -0,0 +1,111 @@
+package org.apache.log4j.net;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import javax.jmdns.JmDNS;
+import javax.jmdns.ServiceInfo;
+
+import org.apache.log4j.Level;
+
+
+/**
+ * A sub-class of SocketHubAppender that broadcasts its configuration via Zeroconf.
+ *
+ * This allows Zeroconf aware applications such as Chainsaw to be able to detect them, and automatically configure
+ * themselves to be able to connect to them.
+ *
+ * @author psmith
+ *
+ */
+public class ZeroConfSocketHubAppender extends SocketHubAppender {
+
+ 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;
+
+ 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(), getPort(), "SocketHubAppender on port " + getPort() );
+ }
+
+ 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();
+ }
+ }
+ }
+
+ /**
+ * Returns the ZeroConf domain that will be used to register this 'device'.
+ *
+ * @return String ZeroConf zone
+ */
+ public String getZeroConfZone() {
+ return zeroConfZone;
+ }
+
+
+ /**
+ * Sets the ZeroConf zone to register this device under, BE CAREFUL with this value
+ * as ZeroConf has some weird naming conventions, it should start with an "_" and end in a ".",
+ * if you're not sure about this value might I suggest that you leave it at the default value
+ * which is specified in {@link #DEFAULT_ZEROCONF_ZONE }.
+ *
+ * This method does NO(0, zero, pun not intended) checks on this value.
+ *
+ * @param zeroConfZone
+ */
+ public void setZeroConfZone(String zeroConfZone) {
+// TODO work out a sane checking mechanism that verifies the value is a correct ZeroConf zone
+ this.zeroConfZone = zeroConfZone;
+ }
+ 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");
+ }
+ }
+
+
+}
diff --git a/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java b/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java
new file mode 100644
index 0000000..0083add
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java
@@ -0,0 +1,58 @@
+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 final JmDNS instance;
+
+ static {
+ try {
+ instance = new JmDNS();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to initialize JmDNS");
+ }
+ }
+
+ /**
+ * Returns the current instance of the JmDNS being used by log4j.
+ *
+ * @throws IllegalStateException if JmDNS was not correctly initialized.
+ *
+ * @return
+ */
+ public static JmDNS getInstance() {
+ checkState();
+ return instance;
+ }
+
+ private static void checkState() {
+ if (instance == null) {
+ throw new IllegalStateException(
+ "JmDNS did not initialize correctly");
+ }
+ }
+
+ /**
+ * Ensures JmDNS cleanly broadcasts 'goodbye' and closes any sockets, and (more imporantly)
+ * ensures some Threads exit so your JVM can exit.
+ *
+ */
+ public static void shutdown() {
+ checkState();
+ instance.close();
+ }
+}