I\'m writing an end-to-end test that my Java program releases all of its resources - threads, server sockets, client sockets. It\'s a library, so releasing resources by exit
I was able to hook into java.net.Socket and java.net.ServerSocket and spy all new instances of those classes. The complete code can be seen in the source repository. Here is an overview of the approach:
When a Socket or ServerSocket is instantiated, the first thing in its constructor is a call to setImpl() which instantiates the object which really implements the socket functionality. The default implementation is an instance of java.net.SocksSocketImpl, but it's possible to override that by setting a custom java.net.SocketImplFactory through java.net.Socket#setSocketImplFactory and java.net.ServerSocket#setSocketFactory.
This is complicated a bit by all implementations of java.net.SocketImpl being package-private, but with a little bit of reflection that's not too hard:
private static SocketImpl newSocketImpl() {
try {
Class<?> defaultSocketImpl = Class.forName("java.net.SocksSocketImpl");
Constructor<?> constructor = defaultSocketImpl.getDeclaredConstructor();
constructor.setAccessible(true);
return (SocketImpl) constructor.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
The SocketImplFactory implementation for spying on all sockets as they are created looks something like this:
final List<SocketImpl> allSockets = Collections.synchronizedList(new ArrayList<SocketImpl>());
ServerSocket.setSocketFactory(new SocketImplFactory() {
public SocketImpl createSocketImpl() {
SocketImpl socket = newSocketImpl();
allSockets.add(socket);
return socket;
}
});
Note that setSocketFactory/setSocketImplFactory can be called only once, so you either need to have only one test which does that (like I have it), or you must create a static singleton (yuck!) for holding that spy.
Then the question is that that how to find out whether the socket is closed? Both Socket and ServerSocket have a method isClosed(), but that uses a boolean internal to those classes for keeping track of whether it was closed - the SocketImpl instance does not have an easy way of checking whether it was closed. (BTW, both Socket and ServerSocket are backed by a SocketImpl - there is no "ServerSocketImpl".)
Thankfully the SocketImpl has a reference to the Socket or ServerSocket which it is backing. The aforementioned setImpl() method calls impl.setSocket(this) or impl.setServerSocket(this), and it's possible to get that reference back by calling java.net.SocketImpl#getSocket or java.net.SocketImpl#getServerSocket.
Once again those methods are package-private, so a little bit of reflection is needed:
private static Socket getSocket(SocketImpl impl) {
try {
Method getSocket = SocketImpl.class.getDeclaredMethod("getSocket");
getSocket.setAccessible(true);
return (Socket) getSocket.invoke(impl);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static ServerSocket getServerSocket(SocketImpl impl) {
try {
Method getServerSocket = SocketImpl.class.getDeclaredMethod("getServerSocket");
getServerSocket.setAccessible(true);
return (ServerSocket) getServerSocket.invoke(impl);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Note that getSocket/getServerSocket may not be called inside the SocketImplFactory, because Socket/ServerSocket sets them only after the SocketImpl is returned from there.
Now there is all the infrastructure necessary for checking in our tests whatever we want about the Socket/ServerSocket:
for (SocketImpl impl : allSockets) {
assertIsClosed(getSocket(impl));
}
The full source code is here.
I haven't tried it myself, but the JavaSpecialists newsletter presents a similar problem:
http://www.javaspecialists.eu/archive/Issue169.html
At the bottom, he describes an approach using AspectJ. You could probably put the pointcut around the constructor that creates the socket, and have code that registers socket creation there.