KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quickserver > net > server > GhostSocketReaper


1 /*
2  * This file is part of the QuickServer library
3  * Copyright (C) QuickServer.org
4  *
5  * Use, modification, copying and distribution of this software is subject to
6  * the terms and conditions of the GNU Lesser General Public License.
7  * You should have received a copy of the GNU LGP License along with this
8  * library; if not, you can download a copy from <http://www.quickserver.org/>.
9  *
10  * For questions, suggestions, bug-reports, enhancement-requests etc.
11  * visit http://www.quickserver.org
12  *
13  */

14
15 package org.quickserver.net.server;
16
17 import java.util.*;
18 import java.io.*;
19 import java.net.*;
20
21 import org.quickserver.net.*;
22 import org.quickserver.util.pool.thread.*;
23 import org.quickserver.util.*;
24 import org.quickserver.net.server.impl.*;
25
26 import java.util.logging.*;
27
28 /**
29  * Class (Server Hook) that closes any dead (ghost) sockets that are no
30  * longer connected or communicating.
31  * <p>
32  * It runs as a daemon thread. This thread will simply return if the socket
33  * timeout is set to &lt;= 0 in QuickServer. It will close any socket that
34  * has not sent in any communication for more than the socket timeout set,
35  * i.e., if socket timeout is set to 1000 miliseconds then
36  * if a client socket has not communicated for more than 1 seconds then this
37  * thread will close the socket and returns the ClientHandler to the pool.
38  * </p>
39  * @author Akshathkumar Shetty
40  * @since 1.3.3
41  */

42 public class GhostSocketReaper extends Thread JavaDoc implements ServerHook {
43     private static Logger logger = Logger.getLogger(GhostSocketReaper.class.getName());
44
45     private long time = 1;
46     private QuickServer quickserver;
47     private volatile boolean stopFlag;
48
49     private long timeOut = 0;
50     private long timeOutDelay = 0;
51     private ClientIdentifier clientIdentifier = null;
52     private List notifiedGhostList = Collections.synchronizedList(new ArrayList());
53     
54     public void initHook(QuickServer quickserver) {
55         this.quickserver = quickserver;
56         clientIdentifier = quickserver.getClientIdentifier();
57     }
58
59     public boolean handleEvent(int event) {
60         if(event==ServerHook.POST_STARTUP) {
61             //logger.finest("Startup Event");
62
setDaemon(true);
63             stopFlag = false;
64             setName("GhostSocketReaper-For-("+quickserver+")");
65             start();
66             return true;
67         } else if(event==ServerHook.POST_SHUTDOWN) {
68             //logger.finest("Shutdown Event");
69
stopFlag = true;
70             return true;
71         }
72         return false;
73     }
74
75     public String JavaDoc info() {
76         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
77         sb.append("GhostSocketReaper - ServerHook");
78         return sb.toString();
79     }
80
81     public void run() {
82         logger.fine("Starting GhostSocketReaper thread - "+quickserver.getName());
83         if(quickserver.getTimeout()<=0) {
84             stopFlag = true;
85             logger.info("Timeout is less than 0, so will exit - "+quickserver.getName());
86             return;
87         }
88         timeOut = quickserver.getTimeout();
89
90         if(quickserver.getBasicConfig().getServerMode().getBlocking()==true)
91             timeOutDelay = 1000; //so that it can use SocketTimeoutException
92

93         List ghostList = new ArrayList();
94         long searchSleepTime = timeOut/2;
95         int failCount = 0;
96         boolean flag = false;
97         while(stopFlag==false) {
98             try {
99                 try {
100                     sleep(searchSleepTime);
101                 } catch(InterruptedException JavaDoc ie) {
102                     logger.warning("InterruptedException : " + ie.getMessage());
103                 }
104
105                 if(failCount<4) {
106                     flag = optimisticGhostSocketsFinder(ghostList);
107                     if(flag==false)
108                         failCount++;
109                     else
110                         failCount = 0;
111                 } else {
112                     syncGhostSocketsFinder(ghostList);
113                     failCount = 0;
114                 }
115                 cleanGhostSockets(ghostList, true);
116                 
117             } catch(Exception JavaDoc e) {
118                 logger.fine("Exception : " + e);
119                 if(Assertion.isEnabled()) {
120                     logger.finest("StackTrace:\n"+MyString.getStackTrace(e));
121                 }
122             }
123         }//end of while
124

125         //wait till all client have disconnected.. then clean the pool
126
while(stopFlag==true) {
127             try {
128                 try {
129                     sleep(searchSleepTime);
130                 } catch(InterruptedException JavaDoc ie) {
131                     logger.warning("InterruptedException : " + ie.getMessage());
132                 }
133
134                 if(quickserver.isClosed()==false) {
135                     break;
136                 }
137
138                 if(quickserver.getClientCount()<=0) {
139                     try {
140                         Thread.yield();
141                         sleep(1000);//lets wait for objects to come back to pool
142
} catch(InterruptedException JavaDoc ie) {
143                         logger.warning("InterruptedException : " + ie.getMessage());
144                     }
145                     quickserver.closeAllPools();
146                     break;
147                 }
148             } catch(Exception JavaDoc e) {
149                 logger.fine("Exception : " + e);
150                 if(Assertion.isEnabled()) {
151                     logger.finest("StackTrace:\n"+MyString.getStackTrace(e));
152                 }
153                 break;
154             }
155         }
156         logger.info("Returning from GhostSocketReaper thread - "+quickserver.getName());
157     }
158
159     private long getCurrentTime() {
160         return new Date().getTime();
161     }
162
163     private boolean optimisticGhostSocketsFinder(List list) {
164         Iterator iterator = null;
165         ClientHandler clientHandler = null;
166         int count = 0;
167         long currentTime = getCurrentTime();
168         try {
169             iterator = clientIdentifier.findAllClient();
170             /*
171             if(iterator.hasNext()) {
172                 logger.finest("ENTER");
173             }
174             */

175
176             while(iterator.hasNext()) {
177                 count++;
178                 if(count==60) {
179                     currentTime = getCurrentTime(); //update time
180
count = 1;
181                 }
182                 clientHandler = (ClientHandler)iterator.next();
183                 
184                 checkClientHandlerForGhostSocket(clientHandler, currentTime, list);
185
186                 if(list.size()>100) {
187                     logger.finest("Found about 100 ghost sockets, lets clean..");
188                     break;
189                 }
190             }//end of while
191
} catch(ConcurrentModificationException e) {
192             //ignore
193
return false;
194         }
195         return true;
196     }
197
198     private void syncGhostSocketsFinder(List list) {
199         Iterator iterator = null;
200         ClientHandler clientHandler = null;
201         int count = 0;
202         long currentTime = getCurrentTime();
203         synchronized(clientIdentifier.getObjectToSynchronize()) {
204             iterator = clientIdentifier.findAllClient();
205             if(iterator.hasNext())
206                 logger.finest("ENTER");
207
208             while(iterator.hasNext()) {
209                 count++;
210                 if(count==60) {
211                     currentTime = getCurrentTime(); //update time
212
count = 1;
213                 }
214                 clientHandler = (ClientHandler)iterator.next();
215                 
216                 checkClientHandlerForGhostSocket(clientHandler, currentTime, list);
217
218                 if(list.size()>100) {
219                     logger.finest("Found about 100 ghost sockets, lets clean..");
220                     break;
221                 }
222             }//end of while
223
}
224     }
225
226     private void cleanGhostSockets(List list, boolean checkTimeout) {
227         long currentTime = getCurrentTime();
228         long commTime = 0;
229         long diff = -1;
230         ClientHandler clientHandler = null;
231
232         int size = list.size();
233         for(int i=0;i<size;i++) {
234             try {
235                 clientHandler = (ClientHandler) list.get(i);
236                 
237                 if(((BasicClientHandler)clientHandler).getWillClean()==true) {
238                     logger.finest("Not closing client "+clientHandler+", WillClean is true");
239                     continue;
240                 }
241                 
242                 if(checkTimeout) {
243                     timeOut = clientHandler.getTimeout()+timeOutDelay;
244                     if(clientHandler.getLastCommunicationTime()!=null) {
245                         commTime = clientHandler.getLastCommunicationTime().getTime();
246                         diff = currentTime-commTime;
247
248                         if(diff < timeOut && clientHandler.isClosed()==false) {
249                             logger.finest("Not closing client "+clientHandler+
250                                 ", must have been reassigned. CommTime(sec): "
251                                 +commTime/1000+", Diff(sec): "+diff/1000);
252                             continue;
253                         }
254                     }
255                 }//end of if checkTimeout
256

257                 if(clientHandler.isClosed()==false) {
258                     logger.finest("Closing client "+clientHandler.getName());
259                     try {
260                         if(clientHandler.hasEvent(ClientEvent.RUN_BLOCKING)==true) {
261                             clientHandler.closeConnection();
262                         } else {
263                             if( ((NonBlockingClientHandler)clientHandler).getThreadAccessCount()!=0 ) {
264                                 clientHandler.closeConnection();
265
266                                 Object JavaDoc obj = clientHandler.getInputStream();
267                                 if(obj!=null) {
268                                     synchronized(obj) {
269                                         clientHandler.getInputStream().notifyAll();
270                                     }
271                                 }
272                             } else {
273                                 clientHandler.addEvent(ClientEvent.CLOSE_CON);
274                                 quickserver.getClientPool().addClient(clientHandler);
275                             }
276                         }
277                     } catch(Exception JavaDoc er) {
278                         logger.fine("Error closing client "+clientHandler);
279                         clientHandler.forceClose();
280                     }
281                 } else {
282                     if(clientHandler.hasEvent(ClientEvent.RUN_BLOCKING)==false) {
283                         logger.finest("Notifying IO of client "+clientHandler);
284                         Object JavaDoc obj = clientHandler.getInputStream();
285                         if(obj==null) continue;
286                         synchronized(obj) {
287                             clientHandler.getInputStream().notifyAll();
288                         }
289                     
290                         logger.finest("Returning objs to pool "+clientHandler);
291                         if(quickserver.getClientDataPool()!=null && clientHandler.getClientData()!=null)
292                             quickserver.getClientDataPool().returnObject(clientHandler.getClientData());
293
294                         logger.finest(Thread.currentThread().getName()+" returning "+getName());
295                         quickserver.getClientHandlerPool().returnObject(clientHandler);
296                     } else {
297                         logger.finest("Skipping closed "+clientHandler+" since in blocking mode.. this should clean up it self.");
298                     }
299                 }
300             } catch(Exception JavaDoc ee) {
301                 logger.fine("Exception forcing the close : " + ee);
302                 if(Assertion.isEnabled()) {
303                     logger.finest("StackTrace:\n"+MyString.getStackTrace(ee));
304                 }
305             }
306         }//end of for
307
list.clear();
308     }
309
310     private void checkClientHandlerForGhostSocket(ClientHandler clientHandler,
311             long currentTime, List list) {
312         if(clientHandler==null)
313             return;
314
315
316         if(clientHandler.isOpen()==false) {
317             logger.finest("Not connected .. so returning ClientData and ClientHandler objects for : "+clientHandler);
318             list.add(clientHandler);
319             return;
320         }
321         
322         if(clientHandler.getTimeout()<=0) {
323             //logger.finest("ClientHandler's timeout is <=0, so skipping.");
324
return;
325         }
326
327         if(clientHandler.getLastCommunicationTime()==null) return;
328
329         long commTime = clientHandler.getLastCommunicationTime().getTime();
330         long diff = currentTime-commTime;
331
332         long timeOut = clientHandler.getTimeout()+timeOutDelay;
333         if(diff >= timeOut) {
334             logger.finest("Closable client "+clientHandler+", Time diff(sec) : " +
335                 diff/1000);
336             list.add(clientHandler);
337         }
338     }
339 }
340
Popular Tags