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.</br> * It is a singleton, and the algorithm is encapsulated. * * @author Zenny Chen * */ publicclass 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 */ privatestatic AppletContainer applet_container =null; /** *//** * the total number of requests */ privatevolatileint 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 */ publicstaticsynchronized 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 */ publicsynchronizedvoid 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 */ publicsynchronized 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 * */ publicvoid 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. */ publicboolean isEmpty() ...{ return container.isEmpty(); } /** *//** * Increase the total number of requests * */ publicsynchronizedvoid increaseRequest() ...{ total_request++; } /** *//** * Decrease the total number of requests * */ publicsynchronizedvoid 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.</br> * This class only can be accessed by ServerFactory class. * * @author Zenny Chen * */ class SocketMonitor implements Runnable ...{ /** *//** * The number of objects it can hold. */ privatestaticfinalint 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. */ privatestatic SocketMonitor monitor=null; /** *//** * * As a singleton, the constructor cannot be accessed. */ private SocketMonitor() ...{ startMonitor(); } /** *//** * The only method to get the object. * * @return the monitor */ synchronizedstatic 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. * */ synchronizedvoid 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.<br> * It is running forever unitl the server(Apache for example) * is closed. */ publicvoid 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. */ privatesynchronized ServerFactory digestSocket() ...{ if(list.size() !=0) ...{ return list.remove(0); } returnnull; } /** *//** * Start the monitor's running thead. * */ private final void startMonitor() ...{ Thread thread =new Thread(this); thread.start(); } } class CommunicationProtocol ...{ staticfinal String OK_RESPONSE ="OK"; staticfinal String NG_RESPONSE ="NG"; } /** *//** * This class is used to encapsulate the socket server object.</br> * Maybe the class name is not quite proper, but now I don't wanna alter it.</br> * * @author Zenny Chen * */ publicclass ServerFactory implements Runnable...{ /** *//** * This lock is used to synchronize the threads that come from * different clients. */ privatestaticvolatile Boolean lock =false; /** *//** * port number.</br> * Maybe a dynamic port number is better. Hope the port is not used * by other tasks. */ privatestaticfinalint PORT =8079; /** *//** * server socket connection time out. */ privatestaticfinalint SOCKET_TIMEOUT =3000; /** *//** * the number of retries when the connection is time out. */ privatestaticfinalint TIMES_OF_TIMEOUT =10; /** *//** * the server socket reference</br> * It is created in this class. */ private ServerSocket server =null; private AppletContainer container =null; /** *//** * This flag is used to delay the main process. */ privatevolatileboolean mayReturn =false; /** *//** * reference to a socket monitor object. */ private SocketMonitor monitor =null; /** *//** * used to count the remaining times for retries. */ privateint n_remainingTimeouts = TIMES_OF_TIMEOUT; /** *//** * Close the server socket. * */ privatevoid 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. */ publicvoid beginCommunication(boolean ifWait) ...{ Thread thread =new Thread(this); thread.start(); if(ifWait ==false) return; while(!mayReturn); mayReturn =false; } /** *//** * Serverfactory's running method. */ publicsynchronizedvoid 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(); } } } }