Skip to content

Commit

Permalink
Massaging the change.
Browse files Browse the repository at this point in the history
The listener better be abstract class to allow us to add more callbacks.
We should support multiple listeners.
Added the close callback for symmetry.
Call to listeners should be after we process the event since listeners aren't fully trusted to get things right.
Renamed the class since from users' perspective it is not external.
Added help screen
  • Loading branch information
kohsuke committed Nov 3, 2013
1 parent 18d0a05 commit cf4f830
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 40 deletions.
61 changes: 61 additions & 0 deletions src/main/java/org/kohsuke/file_leak_detector/ActivityListener.java
@@ -0,0 +1,61 @@
package org.kohsuke.file_leak_detector;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.zip.ZipFile;

/**
* Allows user programs to receive callbacks for file open/close activities.
*
* <p>
* Instantiate this class and put it into {@link #LIST} to start receiving callbacks.
* Listeners must be concurrent and re-entrant safe.
*
* @author Michal Linhard (michal@linhard.sk)
* @author Kohsuke Kawaguchi
*/
public abstract class ActivityListener {
/**
* Called when a new file is opened.
*
* @param obj
* {@link FileInputStream}, {@link FileOutputStream}, {@link RandomAccessFile}, or {@link ZipFile}.
* @param file
* File being opened.
*/
public void open(Object obj, File file) {
}

/**
* Called when a new socket is opened.
*
* @param obj
* {@link Socket}, {@link ServerSocket} or {@link SocketChannel}
*/
public void openSocket(Object obj) {
}

/**
* Called when a file is closed.
*
* This method tolerates a double-close where a close method is called on an already closed object.
*
* @param obj
* {@link FileInputStream}, {@link FileOutputStream}, {@link RandomAccessFile}, {@link Socket}, {@link ServerSocket}, or {@link ZipFile}.
*/
public void close(Object obj) {
}

/**
* These listeners get called.
*/
public static final List<ActivityListener> LIST = new CopyOnWriteArrayList<ActivityListener>();

}
3 changes: 2 additions & 1 deletion src/main/java/org/kohsuke/file_leak_detector/AgentMain.java
Expand Up @@ -72,7 +72,7 @@ public static void premain(String agentArguments, Instrumentation instrumentatio
Listener.ERROR = new PrintWriter(new FileOutputStream(t.substring(6)));
} else
if(t.startsWith("listener=")) {
Listener.EXTERNAL = (ExternalListener) AgentMain.class.getClassLoader().loadClass(t.substring(9)).newInstance();
ActivityListener.LIST.add((ActivityListener) AgentMain.class.getClassLoader().loadClass(t.substring(9)).newInstance());
} else {
System.err.println("Unknown option: "+t);
usageAndQuit();
Expand Down Expand Up @@ -154,6 +154,7 @@ static void printOptions() {
System.err.println(" http=PORT - Run a mini HTTP server that you can access to get stats on demand");
System.err.println(" Specify 0 to choose random available port, -1 to disable, which is default.");
System.err.println(" strong - Don't let GC auto-close leaking file descriptors");
System.err.println(" listener=S - Specify the fully qualified name of ActivityListener class to activate from beginning");
}

static List<ClassTransformSpec> createSpec() {
Expand Down
28 changes: 0 additions & 28 deletions src/main/java/org/kohsuke/file_leak_detector/ExternalListener.java

This file was deleted.

32 changes: 21 additions & 11 deletions src/main/java/org/kohsuke/file_leak_detector/Listener.java
Expand Up @@ -175,11 +175,6 @@ public void dump(String prefix, PrintWriter ps) {
*/
/*package*/ static boolean AGENT_INSTALLED = false;

/**
* Implementation of {@link ExternalListener}.
*/
public static ExternalListener EXTERNAL = null;

/**
* Returns true if the leak detector agent is running.
*/
Expand All @@ -200,34 +195,46 @@ public static synchronized void makeStrong() {
* File being opened.
*/
public static synchronized void open(Object _this, File f) {
if (EXTERNAL != null)
EXTERNAL.open(_this, f);
put(_this, new FileRecord(f));

for (ActivityListener al : ActivityListener.LIST) {
al.open(_this,f);
}
}

/**
* Called when a socket is opened.
*/
public static synchronized void openSocket(Object _this) {
if (EXTERNAL != null)
EXTERNAL.openSocket(_this);
// intercept when
if (_this instanceof SocketImpl) {
try {
// one of the following must be true
SocketImpl si = (SocketImpl) _this;
Socket s = (Socket)SOCKETIMPL_SOCKET.get(si);
if (s!=null)
if (s!=null) {
put(_this, new SocketRecord(s));
for (ActivityListener al : ActivityListener.LIST) {
al.openSocket(s);
}
}
ServerSocket ss = (ServerSocket)SOCKETIMPL_SERVER_SOCKET.get(si);
if (ss!=null)
if (ss!=null) {
put(_this, new ServerSocketRecord(ss));
for (ActivityListener al : ActivityListener.LIST) {
al.openSocket(ss);
}
}
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
if (_this instanceof SocketChannel) {
put(_this, new SocketChannelRecord((SocketChannel) _this));

for (ActivityListener al : ActivityListener.LIST) {
al.openSocket(_this);
}
}
}

Expand Down Expand Up @@ -263,6 +270,9 @@ public static synchronized void close(Object _this) {
r.dump("Closed ",TRACE);
tracing = false;
}
for (ActivityListener al : ActivityListener.LIST) {
al.close(_this);
}
}

/**
Expand Down

0 comments on commit cf4f830

Please sign in to comment.