import java.net.*;
import java.io.*;

public class PoolServerBase extends Thread {
    // client
    protected Socket socket;
    // linked list of threads
    static PoolServerBase head=null;
    protected PoolServerBase next=null;

   // start server with number of threads
    static protected boolean init(Class clobj,int threads) {
      try {
        for (int i=0; i<threads; i++) {
          PoolServerBase thread = (PoolServerBase)clobj.newInstance();
          thread.next=head;
          head=thread;     
	  thread.start();    
          }
        }
      catch (Exception e) { return false; }
      return true;
      }
    
  // add a thread to the list
    static synchronized protected void addToList(PoolServerBase me) {
      me.next=head;
      head=me;
      }
      
  // hold thread until client arrives
    synchronized protected void waitForSignal() {
        try {
          wait();
          } 
        catch (InterruptedException e) { }
      }           

 // main routine that schedules threads
    public void run() {
      while (true) {
        waitForSignal();
        doClientProcessing();
        addToList(this);
        }
      }

 // Start a thread for a client
    synchronized protected void handleClient(Socket s) {
      socket=s;
      notify();
      }
      
    

    // Here is the code that does the work
    // Presumably you'll override this in the subclass
    protected void doClientProcessing() {
        try {
          String s = "I'm a test server. Goodbye";
          s+="Thread: " + this.toString();
          socket.getOutputStream().write(s.getBytes());
          sleep(10000);  // simulate processing
          s="Complete";
          socket.getOutputStream().write(s.getBytes());
          socket.close();
          }
        catch (Exception e) {
          System.out.println(e);
          }
        }

// Test for an empty list
    static synchronized protected boolean listEmpty() {
       return head==null;
       }
      
// assign a thread to a client
   static protected void assignThread(Socket sock) {
       PoolServerBase t=head;
       head=head.next;
       t.socket=sock;
       synchronized (t) { 
         t.notify();
         }
      }


// Start up the server
    static public void startServer(int port) {
	ServerSocket ssock;
	Socket sock;
        try {
	    ssock=new ServerSocket(port);
	    while (true) {
		Socket esock=null;
		try {
		    esock=ssock.accept();
// wait for non-empty thread list
                    while (listEmpty()) yield();
                    assignThread(esock);
		} catch (Exception e) { 
		    try { esock.close(); } catch (Exception ec) {}
		}
	    }
	} catch (IOException e) {
	}
	// if we return something is wrong!
    }


// Very simple test main
    static public void main(String args[]) {
        init(PoolServerBase.class,3);
	System.out.println("Starting server on port 808");
	startServer(808);
      }
    }
