package org.intrace.agent.server; import java.io.IOException; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.intrace.agent.AgentInit; import org.intrace.agent.ClassTransformer; import org.intrace.output.InstruRunnable; /** * TCP Server used for communication with Trace clients. */ public class AgentServer extends InstruRunnable { // CTor field private final ClassTransformer transformer; // Map of client connections private static final Map<AgentClientConnection, Object> clientConnections = new ConcurrentHashMap<AgentClientConnection, Object>(); // Target server port private final int serverPort; // Start signalled private static boolean startSignaled = false; public static synchronized void setStartSignalled() { startSignaled = true; AgentServer.class.notifyAll(); } public static synchronized void waitForStartSignal() throws InterruptedException { while (!startSignaled) { AgentServer.class.wait(); } } /** * cTor * * @param xiT * @param serverPort */ public AgentServer(ClassTransformer xiT, int xiServerPort) { transformer = xiT; serverPort = xiServerPort; } /** * @param connection * Remove this connection. */ public static void addClientConnection(AgentClientConnection connection) { clientConnections.put(connection, new Object()); } /** * @param connection * Remove this connection. */ public static void removeClientConnection(AgentClientConnection connection) { clientConnections.remove(connection); } /** * Broadcast a message to all currently connected clients. * * @param requestingConn * @param message * @throws IOException */ public static void broadcastMessage(AgentClientConnection requestingConn, Object message) throws IOException { IOException ex = null; for (AgentClientConnection clientConn : clientConnections.keySet()) { try { clientConn.sendMessage(message); } catch (IOException ioex) { // Only remember exceptions for the connection sending the message if (requestingConn == clientConn) { ex = ioex; } } } if (ex != null) { throw ex; } } public void runMethod() { // Server constants // Number used for naming client threads int clientNum = 2; // Number of allowed exceptions before we give up int numAllowedExceptions = 10; // Default listen port - we increment the port if we cannot listen on this // port int tracePort = serverPort; while (numAllowedExceptions > 0) { try { ServerSocket serversock = new ServerSocket(tracePort); System.out.println("## InTrace Agent listening on port " + serversock.getLocalPort()); System.setProperty("org.intrace.port", Integer.toString(serversock.getLocalPort())); AgentInit.setServerPort(serversock.getLocalPort()); while (true) { Socket connectedClient = serversock.accept(); AgentClientConnection clientConnection = new AgentClientConnection( connectedClient, transformer); addClientConnection(clientConnection); clientConnection.start(clientNum); clientNum++; } } catch (BindException e) { numAllowedExceptions--; System.out.println("## Unable to listen on port: " + tracePort); tracePort++; } catch (Throwable t) { numAllowedExceptions--; t.printStackTrace(); try { Thread.sleep(5 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("## Too many exceptions - server thread quitting."); } /** * Start the Server - create a new, named, daemon thread. */ public void start() { Thread traceServer = new Thread(this); traceServer.setName("TraceServer"); traceServer.setDaemon(true); traceServer.start(); } }