--- /dev/null
+// SocketClient.java\r
+// $Id: SocketClient.java,v 1.1 2010/06/15 12:26:10 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.http.socket ;\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.DataOutputStream;\r
+import java.io.IOException;\r
+import java.io.PrintStream;\r
+\r
+import java.net.InetAddress;\r
+import java.net.Socket;\r
+import java.net.SocketException;\r
+\r
+import org.w3c.jigsaw.http.Client;\r
+import org.w3c.jigsaw.http.ClientException;\r
+import org.w3c.jigsaw.http.httpd;\r
+\r
+import org.w3c.tools.resources.ServerInterface;\r
+\r
+/**\r
+ * This class implements the object that handles client connections. \r
+ * One such object exists per open connections at any given time.\r
+ * <p>The basic architecture is the following: the httpd instance accepts \r
+ * new connections on its port. When such a connection is accepted a Client \r
+ * object is requested to the client pool (which can implement what ever \r
+ * strategy is suitable). Each request is than managed by looking up an\r
+ * resource and invoking the resource methods corresponding to the request.\r
+ * @see org.w3c.jigsaw.http.httpd\r
+ * @see org.w3c.jigsaw.http.Request\r
+ * @see org.w3c.jigsaw.http.Reply\r
+ */\r
+\r
+public class SocketClient extends Client implements Runnable {\r
+ private static final boolean trace = false;\r
+\r
+ /**\r
+ * The ClientFactory that created this client.\r
+ */\r
+ private SocketClientFactory pool = null ;\r
+ /**\r
+ * The socket currently handled by the client.\r
+ */\r
+ protected Socket socket = null ;\r
+ /**\r
+ * Is this client still alive ?\r
+ */\r
+ protected boolean alive = false;\r
+ /**\r
+ * The client state for this client, has managed by the SocketClientFactory\r
+ * @see SocketClientFactory\r
+ */\r
+ SocketClientState state = null;\r
+ /**\r
+ * Number of times this client was bound to a connection.\r
+ */\r
+ protected int bindcount = 0;\r
+ /**\r
+ * The thread that we have been attached to.\r
+ */\r
+ protected Thread thread = null;\r
+ /**\r
+ * Our reusable output buffer.\r
+ */\r
+ protected SocketOutputBuffer bufout = null;\r
+ /**\r
+ * Our we idle (waiting for next request ?)\r
+ */\r
+ protected boolean idle = false;\r
+\r
+ /**\r
+ * are we done?\r
+ */\r
+ protected boolean done = false;\r
+\r
+ /**\r
+ * Print that client into a String.\r
+ * @return A String instance.\r
+ */\r
+\r
+ public String toString() {\r
+ if ( thread != null )\r
+ return "client-"+state.id+"("+thread.getName()+")";\r
+ else\r
+ return "client-"+state.id;\r
+ }\r
+\r
+ /**\r
+ * If this client is allocated a thread, join it.\r
+ */\r
+\r
+ public void join() {\r
+ if (thread != null) {\r
+ while ( true ) {\r
+ try {\r
+ thread.join();\r
+ } catch (InterruptedException ex) {\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Run for our newly attached connection.\r
+ * @return A boolean, <strong>true</strong> if the client is to be killed\r
+ * as decided by its SocketClientFactory creator.\r
+ */\r
+\r
+ public void run() {\r
+ thread = Thread.currentThread();\r
+ if ( trace )\r
+ System.out.println(this+": powered by "+thread);\r
+ try {\r
+ if ( bufout == null ) {\r
+ // Make sure that buffer is a little smaller then the client\r
+ // buffer. so writing to it will not copy it\r
+ int bufsize = getServer().getClientBufferSize() - 1;\r
+ bufout = new SocketOutputBuffer(socket.getOutputStream()\r
+ , bufsize);\r
+ } else {\r
+ bufout.reuse(socket.getOutputStream());\r
+ }\r
+ startConnection(new BufferedInputStream(socket.getInputStream())\r
+ , new DataOutputStream(bufout));\r
+ } catch (IOException ex) {\r
+ if ( debug )\r
+ ex.printStackTrace();\r
+ } catch (ClientException ex) {\r
+ if ( debug )\r
+ ex.printStackTrace();\r
+ // Emit some debugging traces:\r
+ if ( debug ) {\r
+ if (ex.ex != null )\r
+ ex.ex.printStackTrace() ;\r
+ else\r
+ ex.printStackTrace();\r
+ }\r
+ // If output is null, we have killed the connection...\r
+ if ( alive && ! idle ) {\r
+ error("caught ClientException: [" \r
+ + ex.getClass().getName()\r
+ + "] " + ex.getMessage()) ;\r
+ }\r
+ } catch (Exception ex) {\r
+ if (debug) {\r
+ System.out.println("unknown exception caught in client run");\r
+ ex.printStackTrace();\r
+ }\r
+ } finally {\r
+ if ( ! pool.clientConnectionFinished(this) ) {\r
+ pool.clientFinished(this);\r
+ }\r
+ thread = null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Client implementation - Get the IP address of this client.\r
+ * @return An InetAddress instance, or <strong>null</strong> if the\r
+ * client is not currently running.\r
+ */\r
+\r
+ public InetAddress getInetAddress () {\r
+ return (socket != null) ? socket.getInetAddress() : null;\r
+ }\r
+\r
+ /**\r
+ * Client implementation - This connection has been stopped.\r
+ * Make sure the whole socket is closed, and be ready to handle \r
+ * next connection.\r
+ */\r
+\r
+ protected void stopConnection() {\r
+ if ( trace )\r
+ System.out.println(this+": stopConnection.");\r
+ if ( socket != null ) {\r
+ try {\r
+ socket.close();\r
+ } catch (Exception ex) {\r
+ }\r
+ socket = null;\r
+// alive = false;\r
+// if (!pool.idleClientRemove(this)) {\r
+// pool.clientFinished(this);\r
+// }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the thread powering that client.\r
+ * @return A Thread instance, or <strong>null</strong>.\r
+ */\r
+\r
+ protected Thread getThread() {\r
+ return thread;\r
+ }\r
+\r
+ /**\r
+ * Client implementation - The current connection is idle.\r
+ * The client is about to wait for the next request from the net, mark\r
+ * it as idle to make it a candidate for persistent connection closing.\r
+ * @return A boolean, if <strong>true</strong> our client factory wants\r
+ * us to stop right now, in order to handle some other connection.\r
+ */\r
+\r
+ protected boolean idleConnection() {\r
+ synchronized (state) {\r
+ if ( trace )\r
+ System.out.println(this+": idleConnection.");\r
+ idle = true;\r
+ return ! pool.notifyIdle(this);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Client implementation - The current connection is in use.\r
+ * A request is about to be processed, mark that connection as used, to\r
+ * remove it from the idle state.\r
+ */\r
+\r
+ protected void usedConnection() {\r
+ synchronized (state) {\r
+ if ( trace )\r
+ System.out.println(this+": usedConnection.");\r
+ idle = false;\r
+ pool.notifyUse(this) ;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * SocketClientFactory interface - Bind the socket to this client.\r
+ * Binding a socket to a client triggers the processing of the underlying\r
+ * connection. It is assumed that the client was ready to handle a new \r
+ * connection before this method was called.\r
+ * @param socket The socket this client should now handle.\r
+ */\r
+\r
+ protected synchronized void bind(Socket socket) {\r
+ done = false;\r
+ ServerInterface server = getServer();\r
+ if ( trace )\r
+ System.out.println(this+": bind.");\r
+ this.socket = socket ;\r
+ try {\r
+// socket.setSoTimeout(server.getRequestTimeOut());\r
+ socket.setSoTimeout(pool.timeout);\r
+ } catch (SocketException ex) { \r
+ if (trace)\r
+ ex.printStackTrace(); \r
+ server.errlog("Unable to set socket timeout!");\r
+ } \r
+ this.idle = false;\r
+ bindcount++;\r
+ pool.run(this);\r
+ }\r
+\r
+ /**\r
+ * SocketClientFactory interface - Unbind this client.\r
+ * This client is handling an idle connection, unbind it to make\r
+ * it free for handling some other more buzy connection.\r
+ */\r
+\r
+ protected synchronized void unbind() {\r
+ if ( trace )\r
+ System.out.println(this+": unbind.");\r
+ interruptConnection(true);\r
+ }\r
+\r
+ /**\r
+ * SocketClientFactory interface - Kill this client.\r
+ * The clean way for our client factory to shut us down unconditionally.\r
+ * This will free all resources acquired by this client, stop the current\r
+ * connection processing if needed, and terminate the underlying thread.\r
+ */\r
+\r
+ protected synchronized void kill(boolean now) {\r
+ if ( trace )\r
+ System.out.println(this+": kill.");\r
+ alive = false;\r
+ interruptConnection(now);\r
+ }\r
+\r
+ /**\r
+ * Get the total number of times this client was bound to a socket.\r
+ * @return An integer, indicatingthe number of bind calls on this client.\r
+ */\r
+\r
+ public final int getBindCount() {\r
+ return bindcount;\r
+ }\r
+\r
+ /**\r
+ * Create an empty client, that will be ready to work.\r
+ * The created client will run and wait for it to be <code>bind</code>\r
+ * to some socket before proceeding.\r
+ * @param server The server to which this client is attached.\r
+ * @param id The client identifier.\r
+ * @see org.w3c.jigsaw.http.Client\r
+ * @see org.w3c.jigsaw.http.ClientFactory\r
+ */\r
+\r
+ protected SocketClient(httpd server,\r
+ SocketClientFactory pool,\r
+ SocketClientState state) {\r
+ initialize(server, state.id);\r
+ this.socket = null ;\r
+ this.pool = pool;\r
+ this.state = state;\r
+ this.alive = true;\r
+ }\r
+\r
+}\r