Now that log4j 1.2.16 has the new createSocket method, we can trap this, store the details
of the port/address, and use that in the broadcast of what the SocketHubAppender is listening on.
Includes test case. Changed dependency on zeroconf to require log4j 1.2.16-SNAPSHOT until release.
git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/companions/zeroconf/trunk@634548 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 2bac96a..6143015 100644
--- a/pom.xml
+++ b/pom.xml
@@ -163,6 +163,7 @@
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
+
<configuration>
<descriptors>
<descriptor>src/assembly/bin.xml</descriptor>
@@ -171,6 +172,7 @@
</configuration>
<executions>
<execution>
+ <phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
@@ -181,6 +183,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
+ <phase>package</phase>
<goals>
<goal>jar</goal>
<goal>javadoc</goal>
@@ -210,7 +213,7 @@
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
- <version>1.2.9</version>
+ <version>1.2.16-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>jmdns</groupId>
diff --git a/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java b/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java
index c3d7a75..272663d 100644
--- a/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java
+++ b/src/main/java/org/apache/log4j/net/ZeroConfSocketHubAppender.java
@@ -18,60 +18,74 @@
import java.io.IOException;
import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.ServerSocket;
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.
*
+ * This class relies on log4j 1.2.16 or later.
+ *
* @author psmith
*
*/
public class ZeroConfSocketHubAppender extends SocketHubAppender {
- public static final String DEFAULT_ZEROCONF_ZONE="_log4j._tcp.local.";
+ 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;
+
public ZeroConfSocketHubAppender() {
setName("SocketHubAppender");
try {
- Method getLoggerMethod = this.getClass().getMethod("getLogger", new Class[0]);
+ 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) {
+ 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);
+ 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");
+ 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() );
+ 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) {
+ if (logger != null && logInfoMethod != null & logErrorMethod != null) {
try {
switch (level.toInt()) {
case Level.INFO_INT:
@@ -96,7 +110,6 @@
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 ".",
@@ -108,20 +121,39 @@
* @param zeroConfZone
*/
public void setZeroConfZone(String zeroConfZone) {
-// TODO work out a sane checking mechanism that verifies the value is a correct ZeroConf zone
+ // 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 + ")");
+ 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");
+ logWithlog4j12Compatibility(
+ Level.ERROR,
+ "Failed to instantiate JmDNS to broadcast via ZeroConf, will now operate in simple SocketHubAppender mode");
}
}
-
-
+
+ protected ServerSocket createServerSocket(int socketPort)
+ throws IOException {
+ ServerSocket serverSocket = super.createServerSocket(socketPort);
+ this.actualPortUsed = serverSocket.getLocalPort();
+ this.actualAddressUsed = serverSocket.getInetAddress();
+ return serverSocket;
+ }
+
+ public final int getActualPortUsed() {
+ return actualPortUsed;
+ }
+
+ public final InetAddress getActualAddressUsed() {
+ return actualAddressUsed;
+ }
+
}
diff --git a/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java b/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java
index 77a5508..da21625 100644
--- a/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java
+++ b/src/main/java/org/apache/log4j/net/Zeroconf4log4j.java
@@ -32,43 +32,39 @@
*/
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");
- }
- }
+ private static JmDNS instance;
/**
* Returns the current instance of the JmDNS being used by log4j.
*
- * @throws IllegalStateException if JmDNS was not correctly initialized.
+ * @throws RuntimeException if JmDNS was not correctly initialized.
*
* @return
*/
- public static JmDNS getInstance() {
- checkState();
+ 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;
}
- 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 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() {
- checkState();
- instance.close();
+ 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 acb761b..7e9930b 100644
--- a/src/test/java/org/apache/log4j/net/ZeroConfSocketHubAppenderTest.java
+++ b/src/test/java/org/apache/log4j/net/ZeroConfSocketHubAppenderTest.java
@@ -2,6 +2,7 @@
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
+import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import junit.framework.TestCase;
@@ -10,59 +11,100 @@
* Some test methods to validate that the ZeroConf stuff works as expected/advertised
*
* @author psmith
- *
*/
public class ZeroConfSocketHubAppenderTest extends TestCase {
+ private final class TestServiceListener implements ServiceListener {
+ final ModifiableBoolean addedFlag = new ModifiableBoolean();
+ final ModifiableBoolean removedFlag = new ModifiableBoolean();
+ private ServiceInfo lastInfo;
+ private ServiceEvent lastEvent;
+
+ public void serviceAdded(ServiceEvent event) {
+ addedFlag.setValue(true);
+ lastEvent = event;
+ }
+
+ public void serviceRemoved(ServiceEvent event) {
+ removedFlag.setValue(true);
+ lastEvent = event;
+ }
+
+ public void serviceResolved(ServiceEvent event) {
+ lastInfo = event.getInfo();
+ }
+ }
+
private static final int DEFAULT_TIMEOUT_FOR_ZEROCONF_EVENTS_TO_APPEAR = 2000;
+ JmDNS jmdns;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ jmdns = Zeroconf4log4j.getInstance();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ Zeroconf4log4j.shutdown();
+
+ }
+
/**
- * This does a simple test, as a test harness, to make sure the Appender can be created
- * and that it can shutdown appropriately. in older versions of JmDNS a non-daemon thread
- * could hold the JVM open preventing it from shutting down.
+ * This does a simple test, as a test harness, to make sure the Appender can be created and that
+ * it can shutdown appropriately. in older versions of JmDNS a non-daemon thread could hold the
+ * JVM open preventing it from shutting down.
*
- * @see com.strangeberry.jmdns.tools.Main for a ZeroConf Network browser in Swing allowing you to see the broadcasts
- *
+ * @see com.strangeberry.jmdns.tools.Main for a ZeroConf Network browser in Swing allowing you
+ * to see the broadcasts
* @throws Exception
*/
public void testSimpleTest() throws Exception {
- JmDNS jmdns = Zeroconf4log4j.getInstance();
-
- final ModifiableBoolean addedFlag = new ModifiableBoolean();
- final ModifiableBoolean removedFlag = new ModifiableBoolean();
-
- /**
- * This is just a test to make sure I'm not stupid.
- */
- assertTrue(!addedFlag.isSet());
- assertTrue(!removedFlag.isSet());
-
- jmdns.addServiceListener(ZeroConfSocketHubAppender.DEFAULT_ZEROCONF_ZONE, new ServiceListener() {
- public void serviceAdded(ServiceEvent event) {
- addedFlag.setValue(true);
-
- }
-
- public void serviceRemoved(ServiceEvent event) {
- removedFlag.setValue(true);
- }
-
- public void serviceResolved(ServiceEvent event) {
-
- }});
+ TestServiceListener testServiceListener = new TestServiceListener();
+ jmdns.addServiceListener(
+ ZeroConfSocketHubAppender.DEFAULT_ZEROCONF_ZONE,
+ testServiceListener);
ZeroConfSocketHubAppender appender = new ZeroConfSocketHubAppender();
appender.setName("SimpleTest");
appender.activateOptions();
-
+
Thread.sleep(DEFAULT_TIMEOUT_FOR_ZEROCONF_EVENTS_TO_APPEAR);
+
+ assertTrue("Should have detected the addition",
+ testServiceListener.addedFlag.isSet());
+
+ appender.close();
+
+ Thread.sleep(DEFAULT_TIMEOUT_FOR_ZEROCONF_EVENTS_TO_APPEAR);
+
+ }
+
+ public void testRandomPortWorksOk() throws Exception {
- assertTrue("Should have detected the addition", addedFlag.isSet());
+ TestServiceListener testServiceListener = new TestServiceListener();
+ jmdns.addServiceListener(
+ ZeroConfSocketHubAppender.DEFAULT_ZEROCONF_ZONE,
+ testServiceListener);
+
+
+ ZeroConfSocketHubAppender appender = new ZeroConfSocketHubAppender();
+ appender.setPort(0);
+ appender.setName("RandomPortTest");
+ appender.activateOptions();
+ assertTrue("Port should have been automatically chosen", appender
+ .getActualPortUsed() != 0);
+ assertTrue("Should have detected the addition",
+ testServiceListener.addedFlag.isSet());
+
+ ServiceEvent lastEvent = testServiceListener.lastEvent;
+ jmdns.requestServiceInfo(lastEvent.getType(), lastEvent.getName());
+ assertEquals(
+ "The JmDNS port ServiceInfo should have matched what we expect to broadcast from the appender",
+ testServiceListener.lastInfo.getPort(), appender
+ .getActualPortUsed());
appender.close();
- Zeroconf4log4j.shutdown();
-
- Thread.sleep(DEFAULT_TIMEOUT_FOR_ZEROCONF_EVENTS_TO_APPEAR);
-
+
}
}