@Override
	public void run() {
		System.out.println("Thread "+Thread.currentThread().getId()+" start");
		try {
			BufferedReader in = new BufferedReader( new InputStreamReader( client.getInputStream() ) );  
			PrintStream out = new PrintStream( client.getOutputStream() );
			System.out.println( "I/O setup done" );
			try {
				long before = System.currentTimeMillis();
				while (true) {
					try {
						HttpExchange ex = new HttpExchange(client, serverSocket, in, out);
						if (server.getAuthenticator().authenticate(ex)) {
							executeCommand(ex);
							before = System.currentTimeMillis();
						}
						// stop if thread per resource
						if (!ex.isPersistent())
							break;
					} catch(SocketTimeoutException exception) {
						System.out.println("Client read time out.");
						break;
					} catch (SocketException e) {
						System.out.println("Thread "+Thread.currentThread().getId()+": Interrupted, stop.");
						break;
					} catch (NullPointerException e) {
						long current = System.currentTimeMillis();
						if (current-before>HttpUtility.SocketTimeOut) {
							System.out.println("Client read time out.");
							break;
						}
						// nothing to read yet, try later
						try {
							Thread.sleep(500);
						} catch (InterruptedException e1) {
							System.out.println("Thread "+Thread.currentThread().getId()+": Interrupted, stop.");
							break;
						}
					}
				}
			} finally {
				in.close();
				out.close();
				client.close();
				System.out.println( "A connection is closed." );				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}