这次的服务器端相应代码也是改动比较大,并且也加入了新的类。
这次增加了一个新的Java文件,用于将算法统一化:
package
project.util;

import
java.util.HashMap;



/** */
/**
* This class is used to abstract the data type for algorithm
*
* @author Zenny Chen
*
*/


class
ContainerWrapper
...
{
String value = null;
int count = 0;
}



/** */
/**
* This class is used to store and get the users' requests.
* It is a singleton, and the algorithm is encapsulated.
*
* @author Zenny Chen
*
*/


public
class
AppletContainer
...
{

/** *//**
* a container that stores users' request info
*/
private HashMap<String, ContainerWrapper> container = new HashMap<String, ContainerWrapper>();

/** *//**
* the only instance of this class in an application
*/
private static AppletContainer applet_container = null;

/** *//**
* the total number of requests
*/
private volatile int total_request = 0;

/** *//**
* As a singleton, the constructor cannot be accessed by other classes.
*
*/

private AppletContainer() ...{
}

/** *//**
* As a singleton, there's an only method for other objects to use to create the only
* instance.
* @return the only instance
*/

public static synchronized AppletContainer getInstance() ...{
if(applet_container == null)
applet_container = new AppletContainer();
return applet_container;
}


/** *//**
* add a user's request info
* @param key It will be referred to a string that identifies the request.
* @param value the relevant info
*/

public synchronized void add(String key, String value) ...{

if(container.containsKey(key)) ...{
container.get(key).value = value; // Update the value
container.get(key).count++; // Increase reference count
}

else ...{
ContainerWrapper wrapper = new ContainerWrapper();
wrapper.count = 1;
wrapper.value = value;
container.put(key, wrapper);
}
}

/** *//**
* Get a user's request info
* @param key reference to a particular request
* @return the relevant info
*/

public synchronized String get(String key) ...{
String res = null;

if(container.containsKey(key)) ...{
res = container.get(key).value;
container.get(key).count--;
if(container.get(key).count == 0)
container.remove(key);
}
return res;
}

/** *//**
* clear all the elements of the container
*
*/

public void reset() ...{
if(total_request == 0)
container.clear();
}

/** *//**
* Get whether the container is empy or not.
* @return If the container is empty, return true; Otherwise, return false.
*/

public boolean isEmpty() ...{
return container.isEmpty();
}

/** *//**
* Increase the total number of requests
*
*/

public synchronized void increaseRequest() ...{
total_request++;
}

/** *//**
* Decrease the total number of requests
*
*/

public synchronized void decreaseRequest() ...{
total_request--;
}
}
下面再看看ServerFactory代码:
package
project.util;


import
java.util.ArrayList;
import
java.io.DataInputStream;
import
java.io.DataOutputStream;
import
java.io.IOException;
import
java.net.ServerSocket;
import
java.net.Socket;
import
java.net.SocketTimeoutException;



/** */
/**
*
* SocketMonitor queues the ServerFacotry objects that are timeout
* during serving the network connection and make them respectively
* restart at a proper time.
* This class only can be accessed by ServerFactory class.
*
* @author Zenny Chen
*
*/


class
SocketMonitor
implements
Runnable
...
{

/** *//**
* The number of objects it can hold.
*/
private static final int MAX_THREADS = 255;

/** *//**
* The memory space where it holds the ServerFactory objects.
*/
private ArrayList<ServerFactory> list = new ArrayList<ServerFactory>(MAX_THREADS);

/** *//**
* It is a Singleton.
*/
private static SocketMonitor monitor= null;

/** *//**
*
* As a singleton, the constructor cannot be accessed.
*/

private SocketMonitor() ...{
startMonitor();
}

/** *//**
* The only method to get the object.
*
* @return the monitor
*/

synchronized static SocketMonitor getInstance() ...{
if(monitor == null)
monitor = new SocketMonitor();
return monitor;
}

/** *//**
*
* Add a ServerFactory object that is timeout during running into the
* monitor's queue.
*
* @param s: reference to a ServerFactory object that will be stored.
*
*/

synchronized void addSocket(ServerFactory s) ...{
if(list.size() == MAX_THREADS) {
list.remove(0);
AppletContainer container = AppletContainer.getInstance();
container.decreaseRequest();
}
list.add(s);
}

/** *//**
* This is the monitor's running thread method.
* It is running forever unitl the server(Apache for example)
* is closed.
*/

public void run() ...{

for(;;) ...{

try ...{
Thread.sleep(1000);
}

catch(InterruptedException e) ...{
System.out.println("Sleep Interupted in monitor!");
}
ServerFactory server = digestSocket();
if(server != null)
server.beginCommunication(false);
Thread.yield();
}
}

/** *//**
* Dequeue a monitored object.
*
* @return the ServerFactory object that will be restarted.
*/

private synchronized ServerFactory digestSocket() ...{

if(list.size() != 0) ...{
return list.remove(0);
}
return null;
}

/** *//**
* Start the monitor's running thead.
*
*/

private final void startMonitor() ...{
Thread thread = new Thread(this);
thread.start();
}
}



class
CommunicationProtocol
...
{
static final String OK_RESPONSE = "OK";
static final String NG_RESPONSE = "NG";
}




/** */
/**
* This class is used to encapsulate the socket server object.
* Maybe the class name is not quite proper, but now I don't wanna alter it.
*
* @author Zenny Chen
*
*/


public
class
ServerFactory
implements
Runnable
...
{

/** *//**
* This lock is used to synchronize the threads that come from
* different clients.
*/
private static volatile Boolean lock = false;

/** *//**
* port number.
* Maybe a dynamic port number is better. Hope the port is not used
* by other tasks.
*/
private static final int PORT = 8079;

/** *//**
* server socket connection time out.
*/
private static final int SOCKET_TIMEOUT = 3000;

/** *//**
* the number of retries when the connection is time out.
*/
private static final int TIMES_OF_TIMEOUT = 10;

/** *//**
* the server socket reference
* It is created in this class.
*/
private ServerSocket server = null;
private AppletContainer container = null;

/** *//**
* This flag is used to delay the main process.
*/
private volatile boolean mayReturn = false;

/** *//**
* reference to a socket monitor object.
*/
private SocketMonitor monitor = null;

/** *//**
* used to count the remaining times for retries.
*/
private int n_remainingTimeouts = TIMES_OF_TIMEOUT;

/** *//**
* Close the server socket.
*
*/

private void close() ...{

try ...{
server.close();
server = null;
lock = false;
}

catch(IOException e) ...{
System.out.println("socket server closing error!");
}
}

/** *//**
* constructor
* @param value:the string that'll be output to a specified applet.
*/

public ServerFactory(String func, String value) ...{
//this.value = value;
monitor = SocketMonitor.getInstance();
container = AppletContainer.getInstance();
container.increaseRequest();
container.add(func, value);
}


/** *//**
* Start the server's running thread.
*
* @param ifWait:the flag used to spcify whether the main process
* should be wait or not.
*/

public void beginCommunication(boolean ifWait) ...{
Thread thread = new Thread(this);
thread.start();
if(ifWait == false)
return;
while(!mayReturn);
mayReturn = false;
}

/** *//**
* Serverfactory's running method.
*/

public synchronized void run() ...{

try ...{

for(;;) ...{

while(lock) ...{
Thread.yield();
Thread.sleep(200);
}

synchronized(lock) ...{
if(lock == true)
continue;
lock = true;
break;
}
}
}

catch(InterruptedException e) ...{
System.out.println("Interrupt abnormally broken!");
}
mayReturn = true;

try ...{
System.out.println("Ready to listen!");
server = new ServerSocket(PORT);
server.setSoTimeout(SOCKET_TIMEOUT);
Socket sock = server.accept();
DataInputStream in = new DataInputStream(sock.getInputStream());
DataOutputStream out = new DataOutputStream(sock.getOutputStream());
String value = null, cmd = null;
cmd = in.readUTF();
if(cmd != null)
value = container.get(cmd);

if(value == null) ...{
System.out.println("mismatched!");
out.writeUTF(CommunicationProtocol.NG_RESPONSE);
monitor.addSocket(this);
close();
return;
}
out.writeUTF(CommunicationProtocol.OK_RESPONSE);
out.writeUTF(value);

System.out.println("Data transmitted!");
close();
container.decreaseRequest();
System.out.println("Is the container empty? " + container.isEmpty());
}

catch(IOException e) ...{

if(e instanceof SocketTimeoutException) ...{
System.out.println("Time out!");
if(--n_remainingTimeouts > 0)
monitor.addSocket(this);

else ...{
container.decreaseRequest();
container.reset();
}
close();
}

else ...{
System.out.println("Connecting...");
container.decreaseRequest();
container.reset();
close();
}
}
}
}
而HTMLParser部分代码没有改动,可以参照《(JSP)在文本域中显示超链接——如何使用服务器端代码》。