actually I've found a problem with the commit.
If ZeroconfSocketHubAppender class calls super.activateOptions() which
then creates the SocketServer, the actual creation of the ServerSocket
is done by another thread (see the SocketMonitor constructor), which
means the call back to the protected method to create the socket is
done via another thread.
This means that after super.activateOptions() call returns,
ZeroconfSocketHubAppender still doesn't know what the port is going to
be used (it's a timing thing).
I think the call to create the ServerSocket needs to be done in the
SocketMonitor constructor before the thread is started as I had
originally in my previous patch. Otherwise subclasses have to
implement a tricky wait mechanism to see what port is used before
fully activating themselves.
Can we please move that into the constructor?
Paul
On 16/11/2007, at 5:37 AM, Curt Arnold wrote:
On Nov 15, 2007, at 4:36 AM, Paul Smith wrote:
Ok, i'm a bit tired, so I ended up just going simple and pretty
much following Curt's idea, see below. Thoughts?
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 [EMAIL PROTECTED] LoggingEvent} objects to a set of remote log servers,
That chunk seems just like the IDE at work moving things around.
@@ -271,6 +271,19 @@
}
/**
+ * Once the [EMAIL PROTECTED] ServerSocket} is created and bound, this
method is called to notify the class the details
+ * of the address and port chosen. In the standard
SocketHubAppender case this will be the
+ * requested port, but if the port is specified as 0, then a
random port is chosen by the underlying OS.
+ * Child classes may be interested in the actual port chosen,
and this method may be overridden
+ * and used to gain the details of the actual socket being
listened on.
+ * @param address
+ * @param actualPortUsed
+ */
+ protected void socketBound(InetAddress address, int
actualPortUsed) {
+
+ }
+
+ /**
This class is used internally to monitor a ServerSocket
and register new connections in a vector passed in the
constructor. */
Will discuss later in message.
@@ -280,6 +293,7 @@
private Vector oosList;
private boolean keepRunning;
private Thread monitorThread;
+ private ServerSocket serverSocket;
/**
Create a thread and start the monitor. */
@@ -288,9 +302,15 @@
port = _port;
oosList = _oosList;
keepRunning = true;
+ try {
+ serverSocket = new ServerSocket(port);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to create a
ServerSocket", e);
+ }
monitorThread = new Thread(this);
monitorThread.setDaemon(true);
monitorThread.start();
+ socketBound(serverSocket.getInetAddress(),
serverSocket.getLocalPort());
}
/**
@@ -320,9 +340,8 @@
they connect to the socket. */
public
void run() {
- ServerSocket serverSocket = null;
+
try {
- serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(1000);
}
catch (Exception e) {
This still moves behavior around a bit. I noticed that the inner
class is not defined as static, so it has access to all the methods
and members of its enclosing class, so you could keep the same
notification method, but minimize the changes to the SocketMonitor
by just calling socketBound after the existing socket creation code.
@@ -323,6 +336,7 @@
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
+ socketBound(serverSocket.getInetAddress(),
serverSocket.getLocalPort());
serverSocket.setSoTimeout(1000);
}
catch (Exception e) {
But I didn't see much benefit from hiding the rest of the
serverSocket from the extending class, so I first simplified the
code to:
@@ -323,6 +336,7 @@
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
+ socketBound(serverSocket);
serverSocket.setSoTimeout(1000);
}
catch (Exception e) {
which lets the extending class extract as much or little info out of
the class as possible. But once I did that, it seemed even more
simple to use a protected method to create the socket which is
easier to explain and lets the extending class do everything the
other approaches do and more.
Index: src/main/java/org/apache/log4j/net/SocketHubAppender.java
===================================================================
--- src/main/java/org/apache/log4j/net/SocketHubAppender.java
(revision 592094)
+++ src/main/java/org/apache/log4j/net/SocketHubAppender.java
(working copy)
@@ -271,6 +271,16 @@
}
/**
+ * Creates a server socket to accept connections.
+ * @param socketPort port on which the socket should listen, may
be zero.
+ * @return new socket.
+ * @throws IOException IO error when opening the socket.
+ */
+ protected ServerSocket createServerSocket(final int socketPort)
throws IOException {
+ return new ServerSocket(socketPort);
+ }
+
+ /**
This class is used internally to monitor a ServerSocket
and register new connections in a vector passed in the
constructor. */
@@ -322,7 +332,7 @@
void run() {
ServerSocket serverSocket = null;
try {
- serverSocket = new ServerSocket(port);
+ serverSocket = createServerSocket(port);
serverSocket.setSoTimeout(1000);
}
catch (Exception e) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
Paul Smith
Core Engineering Manager
Aconex
The easy way to save time and money on your project
696 Bourke Street, Melbourne,
VIC 3000, Australia
Tel: +61 3 9240 0200 Fax: +61 3 9240 0299
Email: [EMAIL PROTECTED] www.aconex.com
This email and any attachments are intended solely for the addressee.
The contents may be privileged, confidential and/or subject to
copyright or other applicable law. No confidentiality or privilege is
lost by an erroneous transmission. If you have received this e-mail in
error, please let us know by reply e-mail and delete or destroy this
mail and all copies. If you are not the intended recipient of this
message you must not disseminate, copy or take any action in reliance
on it. The sender takes no responsibility for the effect of this
message upon the recipient's computer system.