KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.*;
18 import java.net.*;
19
20 import org.quickserver.net.*;
21 //v1.1
22
import org.quickserver.net.qsadmin.*;
23 //v1.2
24
import java.util.logging.*;
25 //v1.3
26
import org.quickserver.util.pool.*;
27 import org.quickserver.util.pool.thread.*;
28 import org.apache.commons.pool.*;
29 import org.quickserver.util.xmlreader.*;
30 import org.quickserver.sql.*;
31 //v1.3.1
32
import java.util.*;
33 //v1.3.2
34
import org.quickserver.util.*;
35 import java.util.regex.*;
36 //v1.3.3
37
import org.quickserver.security.*;
38 //v1.4.0
39
import javax.net.ssl.*;
40 import javax.net.*;
41 import java.security.*;
42 import java.security.cert.*;
43 import org.quickserver.util.io.*;
44 //v1.4.5
45
import java.nio.*;
46 import java.nio.channels.*;
47 import org.quickserver.net.server.impl.*;
48
49 /**
50  * Main class of QuickServer library. This class is used to create
51  * multi client servers quickly.
52  * <p>
53  * Ones a client is connected, it creates {@link ClientHandler} object,
54  * which is run using any thread available from the pool of threads
55  * maintained by {@link org.quickserver.util.pool.thread.ClientPool}, which
56  * handles the client. <br/>
57  * QuickServer divides the application logic of its developer over eight
58  * class, <br>
59  * <ul>
60  * <li>ClientEventHandler<br>
61  * &nbsp;Handles client events [Optional Class].
62  * <li>ClientCommandHandler [#]<br>
63  * &nbsp;Handles client character/string commands.
64  * <li>ClientObjectHandler [#]<br>
65  * &nbsp;Handles client interaction - Object commands.
66  * <li>ClientBinaryHandler [#]<br>
67  * &nbsp;Handles client interaction - binary data.
68  * <li>ClientWriteHandler [Optional Class]<br>
69  * &nbsp;Handles client interaction - writing data (Only used in non-blocking mode).
70  * <li>ClientAuthenticationHandler [Optional Class]<br>
71  * &nbsp;Used to Authencatet a client.
72  * <li>ClientData [Optional Class]<br>
73  * &nbsp;Client data carrier (support class)
74  * <li>ClientExtendedEventHandler [Optional Class]<br>
75  * &nbsp;Handles extended client events.
76  * </ul>
77  *
78  * [#] = Any one of these have to be set based on default DataMode for input.
79  * The default DataMode for input is String so if not changes you will
80  * have to set ClientCommandHandler.
81  * </p>
82  * <p>
83  * Eg:
84  * <code><BLOCKQUOTE><pre>
85 package echoserver;
86
87 import org.quickserver.net.*;
88 import org.quickserver.net.server.*;
89
90 import java.io.*;
91
92 public class EchoServer {
93     public static void main(String args[]) {
94         String cmdHandle = "echoserver.EchoCommandHandler";
95     
96         QuickServer myServer = new QuickServer();
97         myServer.setClientCommandHandler(cmdHandle);
98         myServer.setPort(4123);
99         myServer.setName(Echo Server v1.0");
100         try {
101             myServer.startServer();
102         } catch(AppException e) {
103             System.err.println("Error in server : "+e);
104             e.printStackTrace();
105         }
106     }
107 }
108 </pre></BLOCKQUOTE></code></p>
109  *
110  * @version 1.4.7
111  * @author Akshathkumar Shetty
112  */

113 public class QuickServer implements Runnable JavaDoc, Service, Cloneable JavaDoc, Serializable {
114     //Some variable are not initialised to any value because the
115
//default java value was desired initial value.
116

117     //'dev ' = development build not yet final
118
//'beta' = test build all features
119
private final static String JavaDoc VER = "1.4.7";//change also in QSAdminMain
120
private final static String JavaDoc NEW_LINE = "\r\n";
121
122     static {
123         System.out.print("Loading QuickServer v"+getVersion()+" ");
124     }
125
126     private String JavaDoc serverBanner;
127
128     private String JavaDoc clientAuthenticationHandlerString; //v1.4.6
129
private String JavaDoc clientEventHandlerString; //v1.4.6
130
private String JavaDoc clientExtendedEventHandlerString; //v1.4.6
131
private String JavaDoc clientCommandHandlerString;
132     private String JavaDoc clientObjectHandlerString; //v1.2
133
private String JavaDoc clientBinaryHandlerString; //v1.4
134
private String JavaDoc clientWriteHandlerString; //v1.4.5
135
private String JavaDoc clientDataString;
136     
137     private Authenticator authenticator;
138     private ClientAuthenticationHandler clientAuthenticationHandler; //v1.4.6
139
private ClientEventHandler clientEventHandler; //v1.4.6
140
private ClientExtendedEventHandler clientExtendedEventHandler; //v1.4.6
141
private ClientCommandHandler clientCommandHandler;
142     private ClientObjectHandler clientObjectHandler; //v1.2
143
private ClientBinaryHandler clientBinaryHandler; //v1.4
144
private ClientWriteHandler clientWriteHandler; //v1.4.5
145
private ClientData clientData;
146     protected Class JavaDoc clientDataClass;
147
148     private int serverPort = 9876;
149     private Thread JavaDoc t; //Main thread
150
private ServerSocket server;
151     private String JavaDoc serverName = "QuickServer";
152     private long maxConnection = -1;
153     private int socketTimeout = 60 * 1000; //1 min socket timeout
154
private String JavaDoc maxConnectionMsg = "-ERR Server Busy. Max Connection Reached";
155     private String JavaDoc timeoutMsg = "-ERR Timeout";
156     private String JavaDoc maxAuthTryMsg = "-ERR Max Auth Try Reached";
157     private int maxAuthTry = 5; //v1.2
158

159     static {
160         System.out.print(".");
161     }
162
163     //--v1.1
164
private InetAddress ipAddr;
165     private boolean stopServer;
166     private Object JavaDoc[] storeObjects;
167     private QSAdminServer adminServer;
168
169     //--v1.2
170
//Logger for QuickServer
171
private static final Logger logger = Logger.getLogger(QuickServer.class.getName());
172     //Logger for the application using this QuickServer
173
private Logger appLogger;
174
175     //for Service interface
176
private long suspendMaxConnection; //backup
177
private String JavaDoc suspendMaxConnectionMsg; //backup
178
private int serviceState = Service.UNKNOWN;
179
180     static {
181         System.out.print(".");
182     }
183
184     //--v1.3
185
private QuickServerConfig config = new QuickServerConfig();
186     private String JavaDoc consoleLoggingformatter;
187     private String JavaDoc consoleLoggingLevel = "INFO";
188     private ClientPool pool;
189     private ObjectPool clientHandlerPool;
190     private ObjectPool clientDataPool;
191     private DBPoolUtil dBPoolUtil;
192
193     //--v1.3.1
194
private String JavaDoc loggingLevel = "INFO";
195
196     //--v1.3.2
197
private boolean skipValidation = false;
198     private boolean communicationLogging = true;
199
200     //--v1.3.3
201
private String JavaDoc securityManagerClass;
202     private AccessConstraintConfig accessConstraintConfig;
203     private ClassLoader JavaDoc classLoader;
204     private String JavaDoc applicationJarPath;
205     private ServerHooks serverHooks;
206     private ArrayList listOfServerHooks;
207
208     static {
209         System.out.print(".");
210     }
211     
212     //--v1.4.0
213
private Secure secure;
214     private BasicServerConfig basicConfig = config;
215     private SSLContext sslc;
216     private KeyManager km[] = null;
217     private TrustManager tm[] = null;
218     private boolean runningSecure = false;
219     private SecureStoreManager secureStoreManager = null;
220     
221     private Exception JavaDoc exceptionInRun = null;
222
223     //--v1.4.5
224
private ServerSocketChannel serverSocketChannel;
225     private Selector selector;
226     private boolean blockingMode = true;
227     private ObjectPool byteBufferPool;
228     private java.util.Date JavaDoc lastStartTime;
229     private ClientIdentifier clientIdentifier;
230     private GhostSocketReaper ghostSocketReaper;
231     private PoolManager poolManager;
232     private QSObjectPoolMaker qsObjectPoolMaker;
233
234     //--v1.4.6
235
private DataMode defaultDataModeIN = DataMode.STRING;
236     private DataMode defaultDataModeOUT = DataMode.STRING;
237
238     //-v1.4.7
239
private Throwable JavaDoc serviceError;
240     private Map registerChannelRequestMap;
241
242     static {
243         System.out.println(" Done");
244         //should be commented if not a patch release
245
//System.out.println("[Includes patch(#): t=152&p=532]");
246
//should be commented if not a dev release
247
//System.out.println("[Dev Build Date: Saturday, October 29, 2005]");
248
}
249     
250     /** Returns the version of the library. */
251     public static final String JavaDoc getVersion() {
252         return VER;
253     }
254
255     /**
256      * Returns the numerical version of the library.
257      * @since 1.2
258      */

259     public static final float getVersionNo() {
260         return getVersionNo(VER);
261     }
262
263     /**
264      * Returns the numerical version of the library.
265      * @since 1.4.5
266      */

267     public static final float getVersionNo(String JavaDoc ver) {
268         //String ver = getVersion();
269
float version = 0;
270         int i = ver.indexOf(" "); //check if beta
271
if(i == -1)
272             i = ver.length();
273         ver = ver.substring(0, i);
274         
275         i = ver.indexOf("."); //check for sub version
276
if(i!=-1) {
277             int j = ver.indexOf(".", i);
278             if(j!=-1) {
279                 ver = ver.substring(0, i)+"."+
280                     MyString.replaceAll(ver.substring(i+1), ".", "");
281             }
282         }
283
284         try {
285             version = Float.parseFloat(ver);
286         } catch(NumberFormatException JavaDoc e) {
287             throw new RuntimeException JavaDoc("Corrupt QuickServer");
288         }
289         return version;
290     }
291
292     /**
293      * Returns the new line string used by QuickServer.
294      * @since 1.2
295      */

296     public static String JavaDoc getNewLine() {
297         return NEW_LINE;
298     }
299
300     /**
301      * Returns the Server name : port of the QuickServer.
302      */

303     public String JavaDoc toString() {
304         return serverName + " : " + getPort();
305     }
306
307     /**
308      * Creates a new server without any configuration.
309      * Make sure you configure the QuickServer, before
310      * calling startServer()
311      * @see org.quickserver.net.server.ClientEventHandler
312      * @see org.quickserver.net.server.ClientCommandHandler
313      * @see org.quickserver.net.server.ClientObjectHandler
314      * @see org.quickserver.net.server.ClientBinaryHandler
315      * @see org.quickserver.net.server.ClientWriteHandler
316      * @see org.quickserver.net.server.ClientAuthenticationHandler
317      * @see org.quickserver.net.server.ClientHandler
318      * @see #configQuickServer
319      * @see #initService
320      * @see #setPort
321      * @see #setClientCommandHandler
322      * @since 1.2
323      */

324     public QuickServer() {
325     }
326
327     /**
328      * Creates a new server with the specified
329      * <code>commandHandler</code> has it {@link ClientCommandHandler}.
330      * @param commandHandler the fully qualified name of the
331      * desired class that implements {@link ClientCommandHandler}
332      *
333      * @see org.quickserver.net.server.ClientCommandHandler
334      * @see org.quickserver.net.server.ClientAuthenticationHandler
335      * @see org.quickserver.net.server.ClientHandler
336      * @see #setPort
337      */

338     public QuickServer(String JavaDoc commandHandler) {
339         setClientCommandHandler(commandHandler);
340     }
341
342     /**
343      * Creates a new server at <code>port</code> with the specified
344      * <code>commandHandler</code> has it {@link ClientCommandHandler}.
345      *
346      * @param commandHandler fully qualified name of the class that
347      * implements {@link ClientCommandHandler}
348      * @param port to listen on.
349      *
350      * @see org.quickserver.net.server.ClientCommandHandler
351      * @see org.quickserver.net.server.ClientAuthenticationHandler
352      * @see org.quickserver.net.server.ClientHandler
353      */

354     public QuickServer(String JavaDoc commandHandler,int port) {
355         this(commandHandler); //send to another constructor
356
setPort(port);
357     }
358
359     /**
360      * Starts the QuickServer.
361      *
362      * @exception org.quickserver.net.AppException
363      * if Server already running or if it could not load the classes
364      * [ClientCommandHandler, ClientAuthenticationHandler, ClientData].
365      * @see #startService
366      */

367     public void startServer() throws AppException {
368         logger.fine("Starting "+getName());
369
370         if(isClosed() == false) {
371             logger.warning("Server "+getName()+" already running.");
372             throw new AppException("Server "+getName()+" already running.");
373         }
374         
375         if(serverBanner == null) {
376             serverBanner = "\n-------------------------------" +
377                            "\n Name : " + getName() +
378                            "\n Port : " + getPort() +
379                            "\n-------------------------------\n";
380             logger.finest("Default Server Banner Generated");
381         }
382         try {
383             loadApplicationClasses();
384
385             //load class from Advanced Settings
386
Class JavaDoc clientIdentifierClass =
387                 getClass(getBasicConfig().getAdvancedSettings().getClientIdentifier(), true);
388             clientIdentifier = (ClientIdentifier)
389                 clientIdentifierClass.newInstance();
390             clientIdentifier.setQuickServer(QuickServer.this);
391
392             //load class from ObjectPoolConfig
393
Class JavaDoc poolManagerClass =
394                 getClass(getBasicConfig().getObjectPoolConfig().getPoolManager(), true);
395             poolManager = (PoolManager) poolManagerClass.newInstance();
396
397             //load class QSObjectPoolMaker
398
Class JavaDoc qsObjectPoolMakerClass = getClass(
399                 getBasicConfig().getAdvancedSettings().getQSObjectPoolMaker(), true);
400             qsObjectPoolMaker = (QSObjectPoolMaker) qsObjectPoolMakerClass.newInstance();
401
402             loadServerHooksClasses();
403             processServerHooks(ServerHook.PRE_STARTUP);
404             
405             if(getSecure().isLoad()==true)
406                 loadSSLContext(); //v1.4.0
407

408             loadBusinessLogic();
409         } catch(ClassNotFoundException JavaDoc e) {
410             logger.severe("Could not load class/s : " + e.getMessage());
411             throw new AppException("Could not load class/s : " + e.getMessage());
412         } catch(InstantiationException JavaDoc e) {
413             logger.severe("Could not instantiate class/s : " + e.getMessage());
414             throw new AppException("Could not instantiate class/s : "+e.getMessage());
415         } catch(IllegalAccessException JavaDoc e) {
416             logger.severe("Illegal access to class/s : " + e.getMessage());
417             throw new AppException("Illegal access to class/s : " + e.getMessage());
418         } catch(IOException e) {
419             logger.severe("IOException : " + e.getMessage());
420             logger.fine("StackTrace:\n"+MyString.getStackTrace(e));
421             throw new AppException("IOException : " + e.getMessage());
422         } catch(Exception JavaDoc e) {
423             logger.severe("Exception : " + e.getMessage());
424             logger.fine("StackTrace:\n"+MyString.getStackTrace(e));
425             throw new AppException("Exception : " + e);
426         }
427
428         //v1.3.3
429
if(getSecurityManagerClass()!=null) {
430             System.setSecurityManager(getSecurityManager());
431         }
432         
433         blockingMode = getBasicConfig().getServerMode().getBlocking();
434
435         setServiceState(Service.INIT);
436         t = new Thread JavaDoc(this, "QuickServer - "+getName());
437         t.start();
438
439         do {
440             Thread.yield();
441         } while(getServiceState()==Service.INIT);
442
443         if(getServiceState()!=Service.RUNNING) {
444             if(exceptionInRun!=null)
445                 throw new AppException("Could not start server "+getName()
446                     +"! Details: "+exceptionInRun);
447             else
448                 throw new AppException("Could not start server "+getName());
449         }
450         lastStartTime = new java.util.Date JavaDoc();
451         logger.fine("Started "+getName()+", Date: "+lastStartTime);
452     }
453
454     /**
455      * Stops the QuickServer.
456      *
457      * @exception org.quickserver.net.AppException
458      * if could not stop server
459      * @since 1.1
460      * @see #stopService
461      */

462     public void stopServer() throws AppException {
463         processServerHooks(ServerHook.PRE_SHUTDOWN);
464         logger.warning("Stopping "+getName());
465         stopServer = true;
466         Socket death = null;
467         if(isClosed()==true) {
468             logger.warning("Server "+getName()+" is not running!");
469             throw new AppException("Server "+getName()+" is not running!");
470         }
471         try {
472             if(getBlockingMode()==true) {
473                 if(getSecure().isEnable()==false) {
474                     death = new Socket(server.getInetAddress(),
475                         server.getLocalPort());
476                     death.getInputStream().read();
477                     death.close();
478                 } else {
479                     death = getSSLSocketFactory().createSocket(
480                         server.getInetAddress(), server.getLocalPort());
481                     Thread.currentThread().sleep(100);
482                     death.close();
483                 }
484             }
485
486             if(serverSocketChannel!=null) {
487                 serverSocketChannel.close();
488             }
489
490         } catch(IOException e){
491             logger.fine("IOError stopping "+getName()+": "+e);
492         } catch(Exception JavaDoc e){
493             logger.warning("Error stopping "+getName()+": "+e);
494             throw new AppException("Error in stopServer "+getName()+": "+e);
495         }
496
497         for(int i=0;getServiceState()!=Service.STOPPED;i++) {
498             try {
499                 Thread.sleep(60);
500             } catch(Exception JavaDoc e) {
501                 logger.warning("Error waiting for "+getName()+" to fully stop. Error: "+e);
502             }
503             if(i>1000) {
504                 logger.severe("Server was not stopped even after 10sec.. will terminate now.");
505                 System.exit(-1);
506             }
507         }
508         if(adminServer==null || getQSAdminServer().getServer()!=this) {
509             //so this is not qsadmin
510
setClassLoader(null);
511         }
512         logger.info("Stopped "+getName());
513     }
514
515     /**
516      * Restarts the QuickServer.
517      *
518      * @exception org.quickserver.net.AppException
519      * if could not stop server or if it could not start the server.
520      * @since 1.2
521      */

522     public void restartServer() throws AppException {
523         stopServer();
524         startServer();
525     }
526
527     /**
528      * Returns the name of the QuickServer. Default is 'QuickServer'.
529      * @see #setName
530      */

531     public String JavaDoc getName() {
532         return serverName;
533     }
534     /**
535      * Sets the name for the QuickServer
536      * @param name for the QuickServer
537      * @see #getName
538      */

539     public void setName(String JavaDoc name) {
540         serverName = name;
541         logger.finest("Set to : "+name);
542     }
543
544     /**
545      * Returns the Server Banner of the QuickServer
546      * @see #setServerBanner
547      */

548     public String JavaDoc getServerBanner() {
549         return serverBanner;
550     }
551     /**
552      * Sets the serverBanner for the QuickServer
553      * that will be displayed on the standard output [console]
554      * when server starts. <br>&nbsp;<br>
555      * To set welcome message to your client
556      * {@link ClientEventHandler#gotConnected}
557      * @param banner for the QuickServer
558      * @see #getServerBanner
559      */

560     public void setServerBanner(String JavaDoc banner) {
561         serverBanner = banner;
562         logger.finest("Set to : "+banner);
563     }
564
565     /**
566      * Sets the port for the QuickServer to listen on.
567      * If not set, it will run on Port 9876
568      * @param port to listen on.
569      * @see #getPort
570      */

571     public void setPort(int port) {
572         if(port<0) {
573             throw new IllegalArgumentException JavaDoc("Port number can not be less than 0!");
574         }
575         serverPort=port;
576         logger.finest("Set to "+port);
577     }
578     /**
579      * Returns the port for the QuickServer.
580      * @see #setPort
581      */

582     public int getPort() {
583         if(isClosed()==false) {
584             return server.getLocalPort();
585         }
586
587         if(getSecure().isEnable()==false) {
588             return serverPort;
589         } else {
590             int _port = getSecure().getPort();
591             if(_port == -1)
592                 return serverPort;
593             else
594                 return _port;
595         }
596     }
597
598     /**
599      * Sets the ClientCommandHandler class that interacts with
600      * client sockets.
601      * @param handler the fully qualified name of the class that
602      * implements {@link ClientCommandHandler}
603      * @see #getClientCommandHandler
604      */

605     public void setClientCommandHandler(String JavaDoc handler) {
606         clientCommandHandlerString = handler;
607         logger.finest("Set to "+handler);
608     }
609     /**
610      * Returns the ClientCommandHandler class that interacts with
611      * client sockets.
612      * @see #setClientCommandHandler
613      * @since 1.1
614      */

615     public String JavaDoc getClientCommandHandler() {
616         return clientCommandHandlerString;
617     }
618
619     /**
620      * Sets the ClientAuthenticationHandler class that
621      * handles the authentication of a client.
622      * @param authenticator the fully qualified name of the class
623      * that implements {@link ClientAuthenticationHandler}.
624      * @see #getClientAuthenticationHandler
625      * @since 1.4.6
626      */

627     public void setClientAuthenticationHandler(String JavaDoc authenticator) {
628         clientAuthenticationHandlerString = authenticator;
629         logger.finest("Set to "+authenticator);
630     }
631     /**
632      * Returns the ClientAuthenticationHandler class that
633      * handles the authentication of a client.
634      * @see #setClientAuthenticationHandler
635      * @since 1.4.6
636      */

637     public String JavaDoc getClientAuthenticationHandler() {
638         return clientAuthenticationHandlerString;
639     }
640
641     /**
642      * Sets the Authenticator class that
643      * handles the authentication of a client.
644      * @param authenticator the fully qualified name of the class
645      * that implements {@link Authenticator} or {@link ClientAuthenticationHandler}.
646      * @see #getAuthenticator
647      * @deprecated since 1.4.6 use setClientAuthenticationHandler
648      * @since 1.3
649      */

650     public void setAuthenticator(String JavaDoc authenticator) {
651         clientAuthenticationHandlerString = authenticator;
652         logger.finest("Set to "+authenticator);
653     }
654     /**
655      * Returns the Authenticator class that
656      * handles the authentication of a client.
657      * @see #setAuthenticator
658      * @deprecated since 1.4.6 use getClientAuthenticationHandler
659      * @since 1.3
660      */

661     public String JavaDoc getAuthenticator() {
662         return clientAuthenticationHandlerString;
663     }
664
665     /**
666      * Sets the ClientData class that carries client data.
667      * @param data the fully qualified name of the class that
668      * extends {@link ClientData}.
669      * @see #getClientData
670      */

671     public void setClientData(String JavaDoc data) {
672         this.clientDataString = data;
673         logger.finest("Set to "+data);
674     }
675     /**
676      * Returns the ClientData class string that carries client data
677      * @return the fully qualified name of the class that
678      * implements {@link ClientData}.
679      * @see #setClientData
680      */

681     public String JavaDoc getClientData() {
682         return clientDataString;
683     }
684
685     /**
686      * Sets the client socket's timeout.
687      * @param time client socket timeout in milliseconds.
688      * @see #getTimeout
689      */

690     public void setTimeout(int time) {
691         if(time>0)
692             socketTimeout = time;
693         else
694             socketTimeout = 0;
695         logger.finest("Set to "+socketTimeout);
696     }
697     /**
698      * Returns the Client socket timeout in milliseconds.
699      * @see #setTimeout
700      */

701     public int getTimeout() {
702         return socketTimeout;
703     }
704
705     /**
706      * Sets max allowed login attempts.
707      * @since 1.2
708      * @see #getMaxAuthTry
709      */

710     public void setMaxAuthTry(int authTry) {
711         maxAuthTry = authTry;
712         logger.finest("Set to "+authTry);
713     }
714     /**
715      * Returns max allowed login attempts. Default is <code>5</code>.
716      * @since 1.2
717      * @see #setMaxAuthTry
718      */

719     public int getMaxAuthTry() {
720         return maxAuthTry;
721     }
722
723     /**
724      * Sets message to be displayed when maximum allowed login
725      * attempts has reached.
726      * Default is : -ERR Max Auth Try Reached
727      * @see #getMaxAuthTryMsg
728      */

729     public void setMaxAuthTryMsg(String JavaDoc msg) {
730         maxAuthTryMsg = msg;
731         logger.finest("Set to "+msg);
732     }
733     /**
734      * Returns message to be displayed when maximum allowed login
735      * attempts has reached.
736      * @see #getMaxAuthTryMsg
737      */

738     public String JavaDoc getMaxAuthTryMsg() {
739         return maxAuthTryMsg;
740     }
741
742     /**
743      * Sets timeout message.
744      * Default is : -ERR Timeout
745      * @see #getTimeoutMsg
746      */

747     public void setTimeoutMsg(String JavaDoc msg) {
748         timeoutMsg = msg;
749         logger.finest("Set to "+msg);
750     }
751     /**
752      * Returns timeout message.
753      * @see #setTimeoutMsg
754      */

755     public String JavaDoc getTimeoutMsg() {
756         return timeoutMsg;
757     }
758
759     private TheClient initTheClient() {
760         TheClient theClient = new TheClient();
761         theClient.setServer(QuickServer.this);
762         theClient.setTimeoutMsg(getTimeoutMsg());
763         theClient.setMaxAuthTry(getMaxAuthTry()); //v1.2
764
theClient.setMaxAuthTryMsg(getMaxAuthTryMsg());
765         
766         theClient.setClientEventHandler(clientEventHandler);
767         theClient.setClientExtendedEventHandler(clientExtendedEventHandler); //v1.4.6
768
theClient.setClientCommandHandler(clientCommandHandler);
769         theClient.setClientObjectHandler(clientObjectHandler); //v1.2
770
theClient.setClientBinaryHandler(clientBinaryHandler); //v1.4
771
theClient.setClientWriteHandler(clientWriteHandler); //v1.4.5
772
theClient.setAuthenticator(authenticator); //v1.3
773
theClient.setClientAuthenticationHandler(clientAuthenticationHandler); //v1.4.6
774
theClient.setTimeout(socketTimeout);
775         theClient.setMaxConnectionMsg(maxConnectionMsg);
776         theClient.setCommunicationLogging(getCommunicationLogging()); //v1.3.2
777
return theClient;
778     }
779
780     public void run() {
781         exceptionInRun = null;
782         TheClient theClient = initTheClient();
783         try {
784             stopServer = false;
785
786             closeAllPools();
787             initAllPools();
788             
789             makeServerSocket();
790             System.out.println(serverBanner); //print banner
791
setServiceState(Service.RUNNING); //v1.2
792

793             processServerHooks(ServerHook.POST_STARTUP); //v1.3.3
794
if(getBlockingMode()==false) {
795                 runNonBlocking(theClient);
796                 if(stopServer==true) {
797                     logger.finest("Closing selector for "+getName());
798                     selector.close();
799                 }
800                 return;
801             } else {
802                 runBlocking(theClient);
803             }
804         } catch(BindException e) {
805             exceptionInRun = e;
806             logger.severe(getName()+" BindException for Port "+getPort()+" @ "+
807                 getBindAddr().getHostAddress()+" : "+e.getMessage());
808         } catch(javax.net.ssl.SSLException e) {
809             exceptionInRun = e;
810             logger.severe("SSLException "+e);
811             logger.fine("StackTrace:\n"+MyString.getStackTrace(e));
812         } catch(IOException e) {
813             exceptionInRun = e;
814             logger.severe("IOError "+e);
815             logger.fine("StackTrace:\n"+MyString.getStackTrace(e));
816         } catch(Exception JavaDoc e) {
817             exceptionInRun = e;
818             logger.severe("Error "+e);
819             logger.fine("StackTrace:\n"+MyString.getStackTrace(e));
820         } finally {
821             if(getBlockingMode()==true) {
822                 logger.warning("Closing "+getName());
823                 try {
824                     if(isClosed()==false) {
825                         server.close();
826                     }
827                 } catch(Exception JavaDoc e){
828                     throw new RuntimeException JavaDoc(e);
829                 }
830                 server = null;
831                 serverSocketChannel = null;
832
833                 setServiceState(Service.STOPPED);
834                 logger.warning("Closed "+getName());
835
836                 processServerHooks(ServerHook.POST_SHUTDOWN);
837             } else if(getBlockingMode()==false && exceptionInRun!=null) {
838                 logger.warning("Closing "+getName()+" - Had Error: "+exceptionInRun);
839                 try {
840                     if(isClosed()==false) {
841                         if(serverSocketChannel!=null)
842                             serverSocketChannel.close();
843                         if(server!=null)
844                             server.close();
845                     }
846                 } catch(Exception JavaDoc e){
847                     throw new RuntimeException JavaDoc(e);
848                 }
849
850                 server = null;
851                 serverSocketChannel = null;
852
853                 setServiceState(Service.STOPPED);
854                 logger.warning("Closed "+getName());
855
856                 processServerHooks(ServerHook.POST_SHUTDOWN);
857             }
858         }
859     } //end of run
860

861     /**
862      * Sets the maximum number of client connection allowed.
863      * @since 1.1
864      * @see #getMaxConnection
865      */

866     public void setMaxConnection(long maxConnection) {
867         if(getServiceState()==Service.SUSPENDED)
868             suspendMaxConnection = maxConnection;
869         else
870             this.maxConnection = maxConnection;
871         logger.finest("Set to "+maxConnection);
872     }
873     /**
874      * Returns the maximum number of client connection allowed.
875      * @since 1.1
876      * @see #setMaxConnection
877      */

878     public long getMaxConnection() {
879         return maxConnection;
880     }
881
882     /**
883      * Returns number of clients connected.
884      * @since 1.1
885      */

886     public long getClientCount() {
887         if(clientHandlerPool != null) {
888             try {
889                 return getClientHandlerPool().getNumActive();
890             } catch(Exception JavaDoc e) {
891                 return 0;
892             }
893         }
894         return 0;
895     }
896
897     /**
898      * Sets the message to be sent to any new client connected after
899      * maximum client connection has reached.
900      * Default is : <code>-ERR Server Busy. Max Connection Reached</code>
901      * @since 1.1
902      * @see #getMaxConnectionMsg
903      */

904     public void setMaxConnectionMsg(String JavaDoc maxConnectionMsg) {
905         if(getServiceState() == Service.SUSPENDED)
906             suspendMaxConnectionMsg = maxConnectionMsg;
907         else
908             this.maxConnectionMsg = maxConnectionMsg;
909         logger.finest("Set to "+maxConnectionMsg);
910     }
911     /**
912      * Returns the message to be sent to any new client connected
913      * after maximum client connection has reached.
914      * @since 1.1
915      * @see #setMaxConnectionMsg
916      */

917     public String JavaDoc getMaxConnectionMsg() {
918         return maxConnectionMsg;
919     }
920
921     /**
922      * Sets the Ip address to bind to.
923      * @param bindAddr argument can be used on a multi-homed host for a
924      * QuickServer that will only accept connect requests to one
925      * of its addresses. If not set, it will default accepting
926      * connections on any/all local addresses.
927      * @exception java.net.UnknownHostException if no IP address for
928      * the host could be found
929      * @since 1.1
930      * @see #getBindAddr
931      */

932     public void setBindAddr(String JavaDoc bindAddr)
933             throws UnknownHostException {
934         ipAddr = InetAddress.getByName(bindAddr);
935         logger.finest("Set to "+bindAddr);
936     }
937     /**
938      * Returns the IP address binding to.
939      * @since 1.1
940      * @see #setBindAddr
941      */

942     public InetAddress getBindAddr() {
943         if(ipAddr==null) {
944             try {
945                 ipAddr = InetAddress.getByName("0.0.0.0");
946             } catch(Exception JavaDoc e){
947                 logger.warning("Unable to create default ip(0.0.0.0) : "+e);
948                 throw new RuntimeException JavaDoc("Error: Unable to find servers own ip : "+e);
949             }
950         }
951         return ipAddr;
952     }
953
954     /**
955      * Sets the store of objects to QuickServer, it is an array of objects
956      * that main program or the class that created QuickServer passes to
957      * the QuickServer.
958      * @param storeObjects array of objects
959      * @see #getStoreObjects
960      * @since 1.1
961      */

962     public void setStoreObjects(Object JavaDoc[] storeObjects) {
963         this.storeObjects = storeObjects;
964     }
965
966     /**
967      * Returns store of objects from QuickServer, if nothing was set will
968      * return <code>null</code>.
969      * @see #setStoreObjects
970      * @since 1.1
971      */

972     public Object JavaDoc[] getStoreObjects() {
973         return storeObjects;
974     }
975
976     /**
977      * Set the port to run QSAdminServer on.
978      * @since 1.2
979      */

980     public void setQSAdminServerPort(int port) {
981         getQSAdminServer().getServer().setPort(port);
982     }
983     /**
984      * Returns the port to run QSAdminServer on.
985      * @since 1.2
986      */

987     public int getQSAdminServerPort() {
988         return getQSAdminServer().getServer().getPort();
989     }
990
991     /**
992      * Set the ClientAuthenticationHandler class of
993      * QSAdminServer that handles the authentication of a client.
994      * @since 1.2
995      */

996     public void setQSAdminServerAuthenticator(String JavaDoc authenticator) {
997         getQSAdminServer().getServer().setClientAuthenticationHandler(authenticator);
998     }
999     /**
1000     * Returns the Authenticator or ClientAuthenticationHandler class of
1001     * QSAdminServer that handles the authentication of a client.
1002     * @since 1.2
1003     */

1004    public String JavaDoc getQSAdminServerAuthenticator() {
1005        return getQSAdminServer().getServer().getAuthenticator();
1006    }
1007
1008    /**
1009     * Starts QSAdminServer for this QuickServer.
1010     * @see org.quickserver.net.qsadmin.QSAdminServer
1011     * @param authenticator sets the ClientAuthenticationHandler class that
1012     * handles the authentication of a client,
1013     * if null uses {@link org.quickserver.net.qsadmin.Authenticator}.
1014     * @param port to run QSAdminServer on
1015     * @exception org.quickserver.net.AppException
1016     * if Server already running or if it could not load the classes
1017     * [ClientCommandHandler, ClientAuthenticationHandler, ClientData].
1018     * @since 1.1
1019     */

1020    public void startQSAdminServer(int port, String JavaDoc authenticator)
1021            throws AppException {
1022        getQSAdminServer().setClientAuthenticationHandler(authenticator);
1023        getQSAdminServer().startServer(port);
1024    }
1025    /**
1026     * Starts QSAdminServer for this QuickServer.
1027     * @see org.quickserver.net.qsadmin.QSAdminServer
1028     * @since 1.2
1029     */

1030    public void startQSAdminServer() throws AppException {
1031        getQSAdminServer().startServer();
1032    }
1033
1034    /**
1035     * Returns {@link QSAdminServer} associated with this QuickServer
1036     * @since 1.1
1037     */

1038    public QSAdminServer getQSAdminServer() {
1039        if(adminServer==null)
1040            adminServer = new QSAdminServer(QuickServer.this);
1041        return adminServer;
1042    }
1043
1044    /**
1045     * Sets {@link QSAdminServer} associated with this QuickServer
1046     * @since 1.3.3
1047     */

1048    public void setQSAdminServer(QSAdminServer adminServer) {
1049        if(adminServer==null)
1050            this.adminServer = adminServer;
1051    }
1052
1053    /**
1054     * Returns the closed state of the QuickServer Socket.
1055     * @since 1.1
1056     */

1057    public boolean isClosed() {
1058        if(server==null)
1059            return true;
1060        return server.isClosed();
1061    }
1062
1063    /**
1064     * Returns the application logger associated with QuickServer.
1065     * If it was not set will return QuickServer's own logger.
1066     * @since 1.2
1067     */

1068    public Logger getAppLogger() {
1069        if(appLogger!=null)
1070            return appLogger;
1071        return logger;
1072    }
1073    /**
1074     * Sets the application logger associated with QuickServer
1075     * @since 1.2
1076     */

1077    public void setAppLogger(Logger appLogger) {
1078        this.appLogger = appLogger;
1079    }
1080
1081    /**
1082     * Sets the ClientObjectHandler class that interacts with
1083     * client sockets to handle java objects.
1084     * @param handler object the fully qualified name of the class that
1085     * implements {@link ClientObjectHandler}
1086     * @see #getClientObjectHandler
1087     * @since 1.2
1088     */

1089    public void setClientObjectHandler(String JavaDoc handler) {
1090        clientObjectHandlerString = handler;
1091        logger.finest("Set to "+handler);
1092    }
1093    /**
1094     * Returns the ClientObjectHandler class that interacts with
1095     * client sockets.
1096     * @see #setClientObjectHandler
1097     * @since 1.2
1098     */

1099    public String JavaDoc getClientObjectHandler() {
1100        return clientObjectHandlerString;
1101    }
1102
1103    /**
1104     * Sets the console log handler formatter.
1105     * @param formatter fully qualified name of the class that implements
1106     * {@link java.util.logging.Formatter}
1107     * @since 1.2
1108     */

1109    public void setConsoleLoggingFormatter(String JavaDoc formatter)
1110            throws ClassNotFoundException JavaDoc, InstantiationException JavaDoc,
1111                IllegalAccessException JavaDoc {
1112        if(formatter==null)
1113            return;
1114        consoleLoggingformatter = formatter;
1115
1116        Formatter conformatter =
1117            (Formatter) getClass(formatter, true).newInstance();
1118        Logger jdkLogger = Logger.getLogger("");
1119        Handler[] handlers = jdkLogger.getHandlers();
1120        for(int index = 0; index < handlers.length; index++ ) {
1121            if(ConsoleHandler.class.isInstance(handlers[index])) {
1122                handlers[index].setFormatter(conformatter);
1123            }
1124        }
1125        logger.finest("Set to "+formatter);
1126    }
1127
1128    /**
1129     * Gets the console log handler formatter.
1130     * @since 1.3
1131     */

1132    public String JavaDoc getConsoleLoggingFormatter() {
1133        return consoleLoggingformatter;
1134    }
1135
1136    /**
1137     * Sets the console log handler formater to
1138     * {@link org.quickserver.util.logging.MiniFormatter}
1139     * @since 1.2
1140     */

1141    public void setConsoleLoggingToMini() {
1142        try {
1143            setConsoleLoggingFormatter("org.quickserver.util.logging.MiniFormatter");
1144        } catch(Exception JavaDoc e) {
1145            logger.warning("Setting to logging.MiniFormatter : "+e);
1146        }
1147    }
1148
1149    /**
1150     * Sets the console log handler formater to
1151     * {@link org.quickserver.util.logging.MicroFormatter}
1152     * @since 1.2
1153     */

1154    public void setConsoleLoggingToMicro() {
1155        try {
1156            setConsoleLoggingFormatter("org.quickserver.util.logging.MicroFormatter");
1157        } catch(Exception JavaDoc e) {
1158            logger.warning("Setting to MicroFormatter : "+e);
1159        }
1160    }
1161
1162    /**
1163     * Sets the console log handler level.
1164     * @since 1.2
1165     */

1166    public void setConsoleLoggingLevel(Level level) {
1167        Logger rlogger = Logger.getLogger("");
1168        Handler[] handlers = rlogger.getHandlers();
1169        for(int index = 0; index < handlers.length; index++ ) {
1170            if(ConsoleHandler.class.isInstance(handlers[index])) {
1171                handlers[index].setLevel(level);
1172            }
1173        }
1174        if(level==Level.SEVERE)
1175            consoleLoggingLevel = "SEVERE";
1176        else if(level==Level.WARNING)
1177            consoleLoggingLevel = "WARNING";
1178        else if(level==Level.INFO)
1179            consoleLoggingLevel = "INFO";
1180        else if(level==Level.CONFIG)
1181            consoleLoggingLevel = "CONFIG";
1182        else if(level==Level.FINE)
1183            consoleLoggingLevel = "FINE";
1184        else if(level==Level.FINER)
1185            consoleLoggingLevel = "FINER";
1186        else if(level==Level.FINEST)
1187            consoleLoggingLevel = "FINEST";
1188        else
1189            consoleLoggingLevel = "UNKNOWN";
1190
1191        logger.fine("Set to "+level);
1192    }
1193
1194    /**
1195     * Gets the console log handler level.
1196     * @since 1.3
1197     */

1198    public String JavaDoc getConsoleLoggingLevel() {
1199        return consoleLoggingLevel;
1200    }
1201
1202    /**
1203     * Sets the level for all log handlers.
1204     * @since 1.3.1
1205     */

1206    public void setLoggingLevel(Level level) {
1207        Logger rlogger = Logger.getLogger("");
1208        Handler[] handlers = rlogger.getHandlers();
1209        for(int index = 0; index < handlers.length; index++ ) {
1210          handlers[index].setLevel(level);
1211        }
1212
1213        if(level==Level.SEVERE)
1214            loggingLevel = "SEVERE";
1215        else if(level==Level.WARNING)
1216            loggingLevel = "WARNING";
1217        else if(level==Level.INFO)
1218            loggingLevel = "INFO";
1219        else if(level==Level.CONFIG)
1220            loggingLevel = "CONFIG";
1221        else if(level==Level.FINE)
1222            loggingLevel = "FINE";
1223        else if(level==Level.FINER)
1224            loggingLevel = "FINER";
1225        else if(level==Level.FINEST)
1226            loggingLevel = "FINEST";
1227        else
1228            loggingLevel = "UNKNOWN";
1229
1230        consoleLoggingLevel = loggingLevel;
1231
1232        logger.fine("Set to "+level);
1233    }
1234
1235    //*** Start of Service interface methods
1236
/**
1237     * Returns service error if any.
1238     * @since 1.4.7
1239     */

1240    public Throwable JavaDoc getServiceError() {
1241        return serviceError;
1242    }
1243
1244    /**
1245     * Initialise and create the service.
1246     * @param param of the xml configuration file.
1247     * @since 1.2
1248     */

1249    public synchronized boolean initService(Object JavaDoc param[]) {
1250        serviceError = null;
1251        try {
1252            initServer(param);
1253        } catch(Exception JavaDoc e) {
1254            serviceError = e;
1255            return false;
1256        }
1257        return true;
1258    }
1259
1260    /**
1261     * Initialise and create the service.
1262     * @param qsConfig QuickServerConfig object.
1263     * @since 1.4.6
1264     */

1265    public synchronized boolean initService(QuickServerConfig qsConfig) {
1266        serviceError = null;
1267        try {
1268            initServer(qsConfig);
1269        } catch(Exception JavaDoc e) {
1270            serviceError = e;
1271            return false;
1272        }
1273        return true;
1274    }
1275    
1276    /**
1277     * Start the service.
1278     * @return true if serivce was stopped from Running state.
1279     * @since 1.2
1280     */

1281    public boolean startService() {
1282        serviceError = null;
1283        if(getServiceState() == Service.RUNNING)
1284            return false;
1285        try {
1286            startServer();
1287        } catch(AppException e) {
1288            serviceError = e;
1289            return false;
1290        }
1291        return true;
1292    }
1293
1294    /**
1295     * Stop the service.
1296     * @return true if serivce was stopped from Running state.
1297     * @since 1.2
1298     */

1299    public boolean stopService() {
1300        serviceError = null;
1301        if(getServiceState() == Service.STOPPED)
1302            return false;
1303        try {
1304            stopServer();
1305            clearAllPools();
1306        } catch(AppException e) {
1307            serviceError = e;
1308            return false;
1309        } catch(Exception JavaDoc e) {
1310            serviceError = e;
1311            return false;
1312        }
1313        return true;
1314    }
1315
1316    /**
1317     * Suspends the service.
1318     * @return true if service was suspended from resumed state.
1319     * @since 1.2
1320     */

1321    public boolean suspendService() {
1322        serviceError = null;
1323        if(getServiceState() == Service.RUNNING) {
1324            suspendMaxConnection = maxConnection;
1325            suspendMaxConnectionMsg = maxConnectionMsg;
1326            maxConnection = 0;
1327            maxConnectionMsg = "Service is suspended.";
1328            setServiceState(Service.SUSPENDED);
1329            logger.info("Service "+getName()+" is suspended.");
1330            return true;
1331        }
1332        return false;
1333    }
1334    /**
1335     * Resume the service.
1336     * @return true if service was resumed from suspended state.
1337     * @since 1.2
1338     */

1339    public boolean resumeService() {
1340        serviceError = null;
1341        if(getServiceState() == Service.SUSPENDED) {
1342            maxConnection = suspendMaxConnection;
1343            maxConnectionMsg = suspendMaxConnectionMsg;
1344            setServiceState(Service.RUNNING);
1345            logger.info("Service "+getName()+" resumed.");
1346            return true;
1347        }
1348        return false;
1349    }
1350    /**
1351     * Information about the service.
1352     * @since 1.2
1353     */

1354    public String JavaDoc info() {
1355        serviceError = null;
1356        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1357        buf.append(getName()+"\n");
1358        buf.append(getBindAddr().getHostAddress()+" "+getPort()+"\n");
1359        return buf.toString();
1360    }
1361    // *** End of Service interface methods
1362

1363    /**
1364     * Initialise and create the server.
1365     * @param param of the xml configuration file.
1366     * @exception AppException if QuickServerConfig creation failed from the xml config file.
1367     * @since 1.4.7
1368     */

1369    public synchronized void initServer(Object JavaDoc param[]) throws AppException {
1370        QuickServerConfig qsConfig = null;
1371        try {
1372            qsConfig = ConfigReader.read( (String JavaDoc)param[0]);
1373        } catch(Exception JavaDoc e) {
1374            logger.severe("Could not init server from xml file "+
1375                (new File((String JavaDoc)param[0]).getAbsolutePath())+" : " +e);
1376            throw new AppException("Could not init server from xml file",e);
1377        }
1378        initServer(qsConfig);
1379    }
1380
1381    /**
1382     * Initialise and create the service.
1383     * @param qsConfig QuickServerConfig object.
1384     * @since 1.4.7
1385     */

1386    public synchronized void initServer(QuickServerConfig qsConfig) throws AppException {
1387        setConfig(qsConfig);
1388        try {
1389            configQuickServer();
1390
1391            loadApplicationClasses();
1392
1393            //start InitServerHooks
1394
InitServerHooks ish = getConfig().getInitServerHooks();
1395            if(ish!=null) {
1396                Iterator iterator = ish.iterator();
1397                String JavaDoc initServerHookClassName = null;
1398                Class JavaDoc initServerHookClass = null;
1399                InitServerHook initServerHook = null;
1400                while(iterator.hasNext()) {
1401                    initServerHookClassName = (String JavaDoc)iterator.next();
1402                    initServerHookClass = getClass(initServerHookClassName, true);
1403                    initServerHook = (InitServerHook) initServerHookClass.newInstance();
1404
1405                    logger.info("Loaded init server hook: " + initServerHookClassName);
1406                    logger.fine("Init server hook info: " + initServerHook.info());
1407                    initServerHook.handleInit(QuickServer.this);
1408                }
1409            }
1410        } catch(Exception JavaDoc e) {
1411            logger.severe("Could not load init server hook: " +e);
1412            logger.warning("StackTrace:\n"+MyString.getStackTrace(e));
1413            throw new AppException("Could not load init server hook",e);
1414        }
1415        setServiceState(Service.INIT);
1416        logger.finest("\r\n"+MyString.getSystemInfo(getVersion()));
1417    }
1418
1419    /**
1420     * Returns the state of the process
1421     * As any constant of {@link Service} interface.
1422     * @since 1.2
1423     */

1424    public int getServiceState() {
1425        return serviceState;
1426    }
1427    /**
1428     * Sets the state of the process
1429     * As any constant of {@link Service} interface.
1430     * @since 1.2
1431     */

1432    public void setServiceState(int state) {
1433        serviceState = state;
1434    }
1435
1436    private void configConsoleLoggingLevel(QuickServer qs, String JavaDoc temp) {
1437        if(temp.equals("SEVERE"))
1438            qs.setConsoleLoggingLevel(Level.SEVERE);
1439        else if(temp.equals("WARNING"))
1440            qs.setConsoleLoggingLevel(Level.WARNING);
1441        else if(temp.equals("INFO"))
1442            qs.setConsoleLoggingLevel(Level.INFO);
1443        else if(temp.equals("CONFIG"))
1444            qs.setConsoleLoggingLevel(Level.CONFIG);
1445        else if(temp.equals("FINE"))
1446            qs.setConsoleLoggingLevel(Level.FINE);
1447        else if(temp.equals("FINER"))
1448            qs.setConsoleLoggingLevel(Level.FINER);
1449        else if(temp.equals("FINEST"))
1450            qs.setConsoleLoggingLevel(Level.FINEST);
1451        else
1452            logger.warning("unknown level "+temp);
1453    }
1454    
1455    /**
1456     * Configures QuickServer based on the passed QuickServerConfig object.
1457     * @since 1.2
1458     */

1459    public void configQuickServer(QuickServerConfig config) throws Exception JavaDoc {
1460        QuickServer qs = QuickServer.this;
1461        qs.setConfig(config); //v1.3
1462
qs.setBasicConfig(config);
1463        String JavaDoc temp = config.getConsoleLoggingLevel();
1464        configConsoleLoggingLevel(qs, temp);
1465        temp = null;
1466        
1467        qs.setConsoleLoggingFormatter(config.getConsoleLoggingFormatter());
1468
1469        qs.setName(config.getName());
1470        qs.setPort(config.getPort());
1471        qs.setClientEventHandler(config.getClientEventHandler());
1472        qs.setClientCommandHandler(config.getClientCommandHandler());
1473        if(config.getAuthenticator()!=null)
1474            qs.setAuthenticator(config.getAuthenticator()); //v1.3
1475
else if(config.getClientAuthenticationHandler()!=null)
1476            qs.setClientAuthenticationHandler(config.getClientAuthenticationHandler()); //v1.4.6
1477
qs.setClientObjectHandler(config.getClientObjectHandler());
1478        qs.setClientBinaryHandler(config.getClientBinaryHandler());//v1.4
1479
qs.setClientWriteHandler(config.getClientWriteHandler());//v1.4.5
1480
qs.setClientData(config.getClientData());
1481        qs.setClientExtendedEventHandler(config.getClientExtendedEventHandler());
1482        qs.setDefaultDataMode(config.getDefaultDataMode());//v1.4.6
1483
qs.setServerBanner(config.getServerBanner());
1484        qs.setTimeout(config.getTimeout());
1485        qs.setMaxAuthTry(config.getMaxAuthTry());
1486        qs.setMaxAuthTryMsg(config.getMaxAuthTryMsg());
1487        qs.setTimeoutMsg(config.getTimeoutMsg());
1488        qs.setMaxConnection(config.getMaxConnection());
1489        qs.setMaxConnectionMsg(config.getMaxConnectionMsg());
1490        qs.setBindAddr(config.getBindAddr());
1491        //v1.3.2
1492
qs.setCommunicationLogging(config.getCommunicationLogging());
1493        //v1.3.3
1494
qs.setSecurityManagerClass(config.getSecurityManagerClass());
1495        qs.setAccessConstraintConfig(config.getAccessConstraintConfig());
1496        temp = config.getApplicationJarPath();
1497        if(temp!=null) {
1498            File ajp = new File(temp);
1499            if(ajp.isAbsolute()==false) {
1500                temp = config.getConfigFile();
1501                ajp = new File(temp);
1502                temp = ajp.getParent() + File.separatorChar +
1503                    config.getApplicationJarPath();
1504                config.setApplicationJarPath(temp);
1505                temp = null;
1506            }
1507            qs.setApplicationJarPath(config.getApplicationJarPath());
1508            //set path also to QSAdmin
1509
if(config.getQSAdminServerConfig() != null ) {
1510                getQSAdminServer().getServer().setApplicationJarPath(
1511                    config.getApplicationJarPath());
1512            }
1513        }
1514        qs.setServerHooks(config.getServerHooks());
1515        qs.setSecure(config.getSecure());
1516    }
1517
1518    /**
1519     * Configures QSAdminServer based on the passed QuickServerConfig object.
1520     * @since 1.2
1521     */

1522    public void configQuickServer(QSAdminServerConfig config)
1523            throws Exception JavaDoc {
1524        QuickServer qs = getQSAdminServer().getServer();
1525        qs.setBasicConfig(config);
1526        
1527        //set the Logging Level to same as main QS
1528
String JavaDoc temp = getConsoleLoggingLevel();//config.getConsoleLoggingLevel();
1529
configConsoleLoggingLevel(qs, temp);
1530        
1531        //set the Logging Formatter to same as main QS
1532
//qs.setConsoleLoggingFormatter(config.getConsoleLoggingFormatter());
1533
qs.setConsoleLoggingFormatter(getConsoleLoggingFormatter());
1534        
1535        qs.setClientEventHandler(config.getClientEventHandler());//v1.4.6
1536
qs.setClientCommandHandler(config.getClientCommandHandler());
1537        qs.setName(config.getName());
1538        qs.setPort(config.getPort());
1539        if(config.getAuthenticator()!=null)
1540            qs.setAuthenticator(config.getAuthenticator()); //v1.3
1541
else if(config.getClientAuthenticationHandler()!=null)
1542            qs.setClientAuthenticationHandler(config.getClientAuthenticationHandler()); //v1.4.6
1543
qs.setClientObjectHandler(config.getClientObjectHandler());
1544        qs.setClientBinaryHandler(config.getClientBinaryHandler());//v1.4
1545
qs.setClientWriteHandler(config.getClientWriteHandler());//v1.4.5
1546
qs.setClientData(config.getClientData());
1547        qs.setClientExtendedEventHandler(config.getClientExtendedEventHandler());//v1.4.6
1548
qs.setDefaultDataMode(config.getDefaultDataMode());//v1.4.6
1549
qs.setServerBanner(config.getServerBanner());
1550        qs.setTimeout(config.getTimeout());
1551        qs.setMaxAuthTry(config.getMaxAuthTry());
1552        qs.setMaxAuthTryMsg(config.getMaxAuthTryMsg());
1553        qs.setTimeoutMsg(config.getTimeoutMsg());
1554        qs.setMaxConnection(config.getMaxConnection());
1555        qs.setMaxConnectionMsg(config.getMaxConnectionMsg());
1556        qs.setBindAddr(config.getBindAddr());
1557        //v1.3.2
1558
qs.setCommunicationLogging(config.getCommunicationLogging());
1559        getQSAdminServer().setCommandPlugin(config.getCommandPlugin());
1560        //v1.3.2
1561
if(config.getCommandShellEnable().equals("true"))
1562            getQSAdminServer().setShellEnable(true);
1563        getQSAdminServer().setPromptName(config.getCommandShellPromptName());
1564        //v1.3.3
1565
qs.setAccessConstraintConfig(config.getAccessConstraintConfig());
1566        qs.setServerHooks(config.getServerHooks());
1567        qs.setSecure(config.getSecure());
1568    }
1569
1570    /**
1571     * Configures QSAdminServer and QuickServer based on the
1572     * internal QuickServerConfig object.
1573     * @since 1.3
1574     */

1575    public void configQuickServer() throws Exception JavaDoc {
1576        configQuickServer(getConfig());
1577        if(getConfig().getQSAdminServerConfig() != null ) {
1578            configQuickServer(getConfig().getQSAdminServerConfig());
1579        }
1580    }
1581
1582    /**
1583     * Usage: QuickServer [-options]<br/>
1584     * Where options include:<br/>
1585     * -about Opens About Dialogbox<br/>
1586     * -load <xml_config_file> [options] Loads the server from xml file.
1587     * where options include:
1588     * -fullXML2File <new_file_name>
1589     */

1590    public static void main(String JavaDoc args[]) {
1591        try {
1592            if(args.length >= 1) {
1593                if(args[0].equals("-about")) {
1594                    org.quickserver.net.server.gui.About.main(null);
1595                } else if(args[0].equals("-load") && args.length>=2) {
1596                    QuickServer qs = QuickServer.load(args[1]);
1597                    if(qs!=null) handleOptions(args, qs);
1598                } else {
1599                    System.out.println(printUsage());
1600                }
1601            } else {
1602                System.out.println(printUsage());
1603                org.quickserver.net.server.gui.About.showAbout();
1604            }
1605        } catch(Exception JavaDoc e) {
1606            e.printStackTrace();
1607        }
1608    }
1609
1610    /**
1611     * Loads the server from the xml file name passed.
1612     * @since 1.4.7
1613     */

1614    public static QuickServer load(String JavaDoc xml) throws AppException {
1615        QuickServer qs = new QuickServer();
1616        Object JavaDoc config[] = new Object JavaDoc[] {xml};
1617        qs.initServer(config);
1618        qs.startServer();
1619        if(qs.getConfig().getQSAdminServerConfig()!= null) {
1620            qs.startQSAdminServer();
1621        }
1622        return qs;
1623    }
1624    
1625    /** Prints usage */
1626    private static String JavaDoc printUsage() {
1627        StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1628        sb.append("QuickServer - Java library/framework for creating robust multi-client TCP servers.\n");
1629        sb.append("Copyright (C) QuickServer.org\n\n");
1630        sb.append("Usage: QuickServer [-options]\n");
1631        sb.append("Where options include:\n");
1632        sb.append(" -about\t"+"Opens About Dialog box\n");
1633        sb.append(" -load <xml_config_file> [load-options]\t"+"Loads the server from xml file.\n");
1634        sb.append(" Where load-options include:\n");
1635        sb.append(" -fullXML2File <file_name>\t"+"Dumps the Full XML configuration of the QuickServer loaded.\n");
1636        return sb.toString();
1637    }
1638
1639    private static void handleOptions(String JavaDoc args[], QuickServer quickserver) {
1640        if(args.length<3) return;
1641
1642        if(args[2].equals("-fullXML2File") && args.length>=4) {
1643            File file = new File(args[3]);
1644            logger.info("Writing full xml configuration to file: "+file.getAbsolutePath());
1645            try {
1646                TextFile.write(file, quickserver.getConfig().toXML(null));
1647            } catch(Exception JavaDoc e) {
1648                logger.warning("Error writing full xml configuration: "+e);
1649            }
1650        }
1651    }
1652
1653    /**
1654     * Cleans all Object and Thread pools
1655     * @since 1.3
1656     */

1657    public void clearAllPools() throws Exception JavaDoc {
1658        try {
1659            if(pool!=null)
1660                getClientPool().clear();
1661            if(clientHandlerPool!=null)
1662                getClientHandlerPool().clear();
1663            if(getClientDataPool()!=null)
1664                getClientDataPool().clear();
1665            if(getDBPoolUtil()!=null)
1666                getDBPoolUtil().clean();
1667            if(byteBufferPool!=null)
1668                getByteBufferPool().clear();
1669        } catch(Exception JavaDoc e) {
1670            logger.warning("Error: "+e);
1671            throw e;
1672        }
1673    }
1674
1675    /**
1676     * Closes all Object and Thread pools
1677     * @since 1.3
1678     */

1679    public void closeAllPools() throws Exception JavaDoc {
1680        if(pool==null && clientHandlerPool==null && getClientDataPool()==null &&
1681                getDBPoolUtil()==null && byteBufferPool==null) {
1682            return;
1683        }
1684        logger.fine("Closing pools for "+getName());
1685        try {
1686            if(pool!=null && PoolHelper.isPoolOpen(getClientPool().getObjectPool())) {
1687                logger.finer("Closing ClientThread pool.");
1688                getClientPool().close();
1689            }
1690            if(clientHandlerPool!=null && PoolHelper.isPoolOpen(getClientHandlerPool())) {
1691                logger.finer("Closing ClientHandler pool.");
1692                getClientHandlerPool().close();
1693            }
1694            if(getClientDataPool()!=null && PoolHelper.isPoolOpen(getClientDataPool())) {
1695                logger.finer("Closing ClientData pool.");
1696                getClientDataPool().close();
1697            }
1698            if(getDBPoolUtil()!=null) {
1699                logger.finer("Closing DB pool.");
1700                getDBPoolUtil().clean();
1701            }
1702            if(byteBufferPool!=null && PoolHelper.isPoolOpen(getByteBufferPool())) {
1703                logger.finer("Closing ByteBuffer pool.");
1704                getByteBufferPool().close();
1705            }
1706            logger.fine("Closed pools for "+getName());
1707        } catch(Exception JavaDoc e) {
1708            logger.warning("Error closing pools for "+getName()+": "+e);
1709            throw e;
1710        }
1711    }
1712
1713    /**
1714     * Initialise all Object and Thread pools.
1715     * @since 1.3
1716     */

1717    public void initAllPools() throws Exception JavaDoc {
1718        logger.fine("Creating pools");
1719        if(getBlockingMode()==false) {
1720            makeByteBufferPool(getBasicConfig().getObjectPoolConfig().getByteBufferObjectPoolConfig());
1721        }
1722        
1723        makeClientPool(getBasicConfig().getObjectPoolConfig().getThreadObjectPoolConfig());
1724        
1725        makeClientHandlerPool(
1726            getBasicConfig().getObjectPoolConfig().getClientHandlerObjectPoolConfig());
1727        
1728        //check if client data is poolable
1729
if(clientDataClass!=null) {
1730            try {
1731                clientData = (ClientData)clientDataClass.newInstance();
1732                if(PoolableObject.class.isInstance(clientData)==true) {
1733                    PoolableObject po = (PoolableObject)clientData;
1734                    if( po.isPoolable()==true) {
1735                        makeClientDataPool(po.getPoolableObjectFactory(),
1736                            getBasicConfig().getObjectPoolConfig().getClientDataObjectPoolConfig() );
1737                    } else {
1738                        clientDataPool = null;
1739                        logger.fine("ClientData is not poolable!");
1740                    }
1741                }
1742            } catch(Exception JavaDoc e) {
1743                logger.warning("Error: "+e);
1744                throw e;
1745            }
1746        }
1747
1748        try {
1749            makeDBObjectPool();
1750        } catch(Exception JavaDoc e) {
1751            logger.warning("Error in makeDBObjectPool() : "+e);
1752            logger.fine("StackTrace:\n"+MyString.getStackTrace(e));
1753            throw e;
1754        }
1755        logger.fine("Created pools");
1756    }
1757
1758
1759    /**
1760     * Returns {@link org.quickserver.util.pool.thread.ClientPool} class that
1761     * managing the pool of threads for handling clients.
1762     * @exception IllegalStateException if pool is not created yet.
1763     * @since 1.3
1764     */

1765    public ClientPool getClientPool() {
1766        if(pool==null)
1767            throw new IllegalStateException JavaDoc("No ClientPool available yet!");
1768        return pool;
1769    }
1770
1771    /**
1772     * Makes the pool of ClientHandler
1773     * @since 1.3
1774     */

1775    private void makeClientHandlerPool(PoolConfig opConfig) throws Exception JavaDoc {
1776        logger.finer("Creating ClientHandler pool");
1777        PoolableObjectFactory factory = new ClientHandlerObjectFactory(getBlockingMode());
1778        clientHandlerPool = poolManager.makeClientHandlerPool(factory, opConfig);
1779        poolManager.initPool(clientHandlerPool, opConfig);
1780        clientHandlerPool = makeQSObjectPool(clientHandlerPool);
1781        clientIdentifier.setClientHandlerPool((QSObjectPool)clientHandlerPool);
1782    }
1783
1784    /**
1785     * Returns ObjectPool of {@link org.quickserver.net.server.ClientHandler}
1786     * class.
1787     * @exception IllegalStateException if pool is not created yet.
1788     * @since 1.3
1789     */

1790    public ObjectPool getClientHandlerPool() {
1791        if(clientHandlerPool==null)
1792            throw new IllegalStateException JavaDoc("No ClientHandler Pool available yet!");
1793        return clientHandlerPool;
1794    }
1795
1796    
1797    /**
1798     * Sets the confiuration of the QuickServer.
1799     * @since 1.3
1800     */

1801    public void setConfig(QuickServerConfig config) {
1802        this.config = config;
1803    }
1804
1805    /**
1806     * Returns the confiuration of the QuickServer.
1807     * @since 1.3
1808     */

1809    public QuickServerConfig getConfig() {
1810        return config;
1811    }
1812
1813    /**
1814     * Makes the pool of ClientData
1815     * @since 1.3
1816     */

1817    private void makeClientDataPool(PoolableObjectFactory factory,
1818            PoolConfig opConfig) throws Exception JavaDoc {
1819        logger.finer("Creating ClientData pool");
1820        clientDataPool = poolManager.makeClientDataPool(factory, opConfig);
1821        poolManager.initPool(clientDataPool, opConfig);
1822        clientDataPool = makeQSObjectPool(clientDataPool);
1823    }
1824
1825    /**
1826     * Returns ObjectPool of {@link org.quickserver.net.server.ClientData}
1827     * class. If ClientData was not poolable will return null.
1828     * @since 1.3
1829     */

1830    public ObjectPool getClientDataPool() {
1831        return clientDataPool;
1832    }
1833
1834    /**
1835     * Returns {@link org.quickserver.sql.DBPoolUtil} object if
1836     * {@link org.quickserver.util.xmlreader.DBObjectPoolConfig} was set.
1837     * @return DBPoolUtil object if object could be loaded, else will return <code>null</code>
1838     * @since 1.3
1839     */

1840    public DBPoolUtil getDBPoolUtil() {
1841        return dBPoolUtil;
1842    }
1843    /**
1844     * Sets {@link org.quickserver.util.xmlreader.DBObjectPoolConfig}
1845     * @since 1.3
1846     */

1847    public void setDBObjectPoolConfig(DBObjectPoolConfig dBObjectPoolConfig) {
1848        getConfig().setDBObjectPoolConfig(dBObjectPoolConfig);
1849    }
1850
1851    /**
1852     * Makes the pool of Database Objects
1853     * @since 1.3
1854     */

1855    private void makeDBObjectPool() throws Exception JavaDoc {
1856        if(getConfig().getDBObjectPoolConfig()!=null) {
1857            logger.fine("Creating DBObject Pool");
1858            //logger.finest("Got:\n"+getConfig().getDBObjectPoolConfig().toXML(null));
1859
Class JavaDoc dbPoolUtilClass = getClass(
1860                getConfig().getDBObjectPoolConfig().getDbPoolUtil(), true);
1861            dBPoolUtil = (DBPoolUtil) dbPoolUtilClass.newInstance();
1862            dBPoolUtil.setDatabaseConnections(
1863                getConfig().getDBObjectPoolConfig().getDatabaseConnectionSet().iterator());
1864            dBPoolUtil.initPool();
1865        }
1866    }
1867
1868    /**
1869     * Tries to find the Client by the Id passed.
1870     * <p>
1871     * Note: This command is an expensive so do use it limitedly and
1872     * cache the returned object. But before you start sending message to the
1873     * cached object do validate that ClientHandler with you is currently
1874     * connected and is pointing to the same clinet has it was before.
1875     * This can be done as follows. <pre>
1876    foundClientHandler.isConnected(); //this method will through SocketException if not connected
1877    Date newTime = foundClientHandler.getClientConnectedTime();
1878    if(oldCachedTime!=newTime) {
1879        //Client had disconnected and ClientHandler was reused for
1880        //someother client, so write code to again find ur client
1881        foundClientHandler = handler.getServer().findFirstClientById("friendsid");
1882        ...
1883    }</pre>
1884     * </p>
1885     * @see ClientIdentifiable
1886     * @return ClientHandler object if client was found else <code>null</code>
1887     * @since 1.3.1
1888     */

1889    public ClientHandler findFirstClientById(String JavaDoc id) {
1890        return clientIdentifier.findFirstClientById(id);
1891    }
1892
1893    /**
1894     * Returns an iterator containing all the
1895     * {@link org.quickserver.net.server.ClientHandler} that
1896     * are currently handling clients.
1897     * It is recommended not to change the collection under an iterator.
1898     *
1899     * It is imperative that the user manually synchronize on the returned collection
1900     * when iterating over it:
1901     * <code><pre>
1902   Eg:
1903
1904    ClientData foundClientData = null;
1905    Object syncObj = quickserver.getClientIdentifier().getObjectToSynchronize();
1906    synchronized(syncObj) {
1907        Iterator iterator = quickserver.findAllClient();
1908        while(iterator.hasNext()) {
1909            foundClientHandler = (ClientHandler) iterator.next();
1910            ....
1911        }
1912    }
1913
1914    //OR
1915
1916    ClientData foundClientData = null;
1917    ClientIdentifier clientIdentifier = quickserver.getClientIdentifier();
1918    synchronized(clientIdentifier.getObjectToSynchronize()) {
1919        Iterator iterator = clientIdentifier.findAllClient();
1920        while(iterator.hasNext()) {
1921            foundClientHandler = (ClientHandler) iterator.next();
1922            ....
1923        }
1924    }
1925   </code></pre>
1926     * @since 1.3.1
1927     */

1928    public Iterator findAllClient() {
1929        return clientIdentifier.findAllClient();
1930    }
1931
1932    /**
1933     * Tries to find the Client by the matching pattern passed to the Id.
1934     * <p>
1935     * Note: This command is an expensive so do use it limitedly and
1936     * cache the returned object. But before you start sending message to the
1937     * cached object do validate that ClientHandler with you is currently
1938     * connected and is pointing to the same clinet has it was before.
1939     * This can be done as follows. <pre>
1940    foundClientHandler.isConnected(); //this method will through SocketException if not connected
1941    Date newTime = foundClientHandler.getClientConnectedTime();
1942    if(oldCachedTime!=newTime) {
1943        //Client had disconnected and ClientHandler was reused for
1944        //someother client, so write code to again find ur client
1945        foundClientHandler = handler.getServer().findFirstClientById("friendsid");
1946        ...
1947    }</pre>
1948     * </p>
1949     * @see ClientIdentifiable
1950     * @return ClientHandler object if client was found else <code>null</code>
1951     * @since 1.3.2
1952     */

1953    public Iterator findAllClientById(String JavaDoc pattern) {
1954        return clientIdentifier.findAllClientById(pattern);
1955    }
1956
1957    /**
1958     * Tries to find the Client by the Key passed.
1959     * <p>
1960     * Note: This command is an expensive so do use it limitedly and
1961     * cache the returned object. But before you start sending message to the
1962     * cached object do validate that ClientHandler with you is currently
1963     * connected and is pointing to the same clinet has it was before.
1964     * This can be done as follows. <pre>
1965    foundClientHandler.isConnected(); //this method will through SocketException if not connected
1966    Date newTime = foundClientHandler.getClientConnectedTime();
1967    if(oldCachedTime!=newTime) {
1968        //Client had disconnected and ClientHandler was reused for
1969        //someother client, so write code to again find ur client
1970        foundClientHandler = handler.getServer().findClientByKey("friendskey");
1971        ...
1972    }</pre>
1973     * </p>
1974     * @see ClientIdentifiable
1975     * @return ClientHandler object if client was found else <code>null</code>
1976     * @since 1.3.1
1977     */

1978    public ClientHandler findClientByKey(String JavaDoc key) {
1979        return clientIdentifier.findClientByKey(key);
1980    }
1981
1982    /**
1983     * Tries to find the Client by the matching pattern passed to the key.
1984     * <p>
1985     * Note: This command is an expensive so do use it limitedly and
1986     * cache the returned object. But before you start sending message to the
1987     * cached object do validate that ClientHandler with you is currently
1988     * connected and is pointing to the same clinet has it was before.
1989     * This can be done as follows. <pre>
1990    foundClientHandler.isConnected(); //this method will through SocketException if not connected
1991    Date newTime = foundClientHandler.getClientConnectedTime();
1992    if(oldCachedTime!=newTime) {
1993        //Client had disconnected and ClientHandler was reused for
1994        //some other client, so write code to again find ur client
1995        foundClientHandler = handler.getServer().findFirstClientByKey("friendsid");
1996        ...
1997    }</pre>
1998     * </p>
1999     * @see ClientIdentifiable
2000     * @return ClientHandler object if client was found else <code>null</code>
2001     * @since 1.4
2002     */

2003    public Iterator findAllClientByKey(String JavaDoc pattern) {
2004        return clientIdentifier.findAllClientByKey(pattern);
2005    }
2006
2007    /**
2008     * Sets next client has a trusted client.
2009     * <p>This will skip any authentication and will not set any timout.</p>
2010     * @since 1.3.2
2011     */

2012    public void nextClientIsTrusted() {
2013        setSkipValidation(true);
2014    }
2015    /**
2016     * @since 1.3.2
2017     */

2018    private boolean getSkipValidation() {
2019        return skipValidation;
2020    }
2021    /**
2022     * @since 1.3.2
2023     */

2024    private synchronized void setSkipValidation(boolean validation) {
2025        skipValidation = validation;
2026    }
2027
2028    /**
2029     * Sets the communication logging flag.
2030     * @see #getCommunicationLogging
2031     * @since 1.3.2
2032     */

2033    public void setCommunicationLogging(boolean communicationLogging) {
2034        this.communicationLogging = communicationLogging;
2035    }
2036    /**
2037     * Returns the communication logging flag.
2038     * @see #setCommunicationLogging
2039     * @since 1.3.2
2040     */

2041    public boolean getCommunicationLogging() {
2042        return communicationLogging;
2043    }
2044
2045    /**
2046     * Sets the SecurityManager class
2047     * @param securityManagerClass the fully qualified name of the class
2048     * that extends {@link java.lang.SecurityManager}.
2049     * @see #getSecurityManagerClass
2050     * @since 1.3.3
2051     */

2052    public void setSecurityManagerClass(String JavaDoc securityManagerClass) {
2053        if(securityManagerClass!=null)
2054            this.securityManagerClass = securityManagerClass;
2055    }
2056    /**
2057     * Returns the SecurityManager class
2058     * @see #setSecurityManagerClass
2059     * @since 1.3.3
2060     */

2061    public String JavaDoc getSecurityManagerClass() {
2062        return securityManagerClass;
2063    }
2064
2065    public SecurityManager JavaDoc getSecurityManager() throws AppException {
2066        if(getSecurityManagerClass()==null)
2067            return null;
2068        SecurityManager JavaDoc sm = null;
2069        try {
2070            sm = (SecurityManager JavaDoc)
2071                getClass(getSecurityManagerClass(), true).newInstance();
2072        } catch(ClassNotFoundException JavaDoc e) {
2073            throw new AppException(e.getMessage());
2074        } catch(InstantiationException JavaDoc e) {
2075            throw new AppException(e.getMessage());
2076        } catch(IllegalAccessException JavaDoc e) {
2077            throw new AppException(e.getMessage());
2078        }
2079        return sm;
2080    }
2081
2082    /**
2083     * Sets the Access constraints
2084     * @since 1.3.3
2085     */

2086    public void setAccessConstraintConfig(
2087            AccessConstraintConfig accessConstraintConfig) {
2088        this.accessConstraintConfig = accessConstraintConfig;
2089    }
2090    /**
2091     * Returns Access constraints if present else <code>null</code>.
2092     * @since 1.3.3
2093     */

2094    public AccessConstraintConfig getAccessConstraintConfig() {
2095        return accessConstraintConfig;
2096    }
2097
2098    /**
2099     * Sets the classloader to be used to load the dynamicaly resolved
2100     * classes
2101     * @since 1.3.3
2102     */

2103    public void setClassLoader(ClassLoader JavaDoc classLoader) {
2104        this.classLoader = classLoader;
2105        Thread.currentThread().setContextClassLoader(classLoader);
2106    }
2107
2108    /**
2109     * Gets the classloader used to load the dynamicaly resolved
2110     * classes.
2111     * @since 1.4.6
2112     */

2113    public ClassLoader JavaDoc getClassLoader() {
2114        return classLoader;
2115    }
2116
2117    /**
2118     * Utility method to load a class
2119     * @since 1.3.3
2120     */

2121     public Class JavaDoc getClass(String JavaDoc name, boolean reload)
2122            throws ClassNotFoundException JavaDoc {
2123        if(name==null) throw new IllegalArgumentException JavaDoc("Class name can't be null!");
2124        logger.finest("Class: "+name+", reload: "+reload);
2125        if(reload==true && classLoader!=null) {
2126            return classLoader.loadClass(name);
2127        } else if(reload==true && classLoader==null && this.getClass().getClassLoader()!=null) {
2128            return this.getClass().getClassLoader().loadClass(name);
2129        } else if(reload==false && classLoader!=null) {
2130            return Class.forName(name, true, classLoader);
2131        } else /*if(reload==false && classLoader==null)*/ {
2132            return Class.forName(name, true, this.getClass().getClassLoader());
2133        }
2134     }
2135
2136     /**
2137     * Sets the applications jar/s path. This can be either absolute or
2138     * relative(to config file) path to the jar file or the directory containing
2139     * the jars needed by the application.
2140     * @see #getApplicationJarPath
2141     * @since 1.3.3
2142     */

2143    protected void setApplicationJarPath(String JavaDoc applicationJarPath) {
2144        this.applicationJarPath = applicationJarPath;
2145    }
2146
2147    /**
2148     * Returns the applications jar/s path. This can be either absolute or
2149     * relative(to config file) path to the jar file or the directory containing the
2150     * jars needed by the application.
2151     * @see #setApplicationJarPath
2152     * @since 1.3.3
2153     */

2154    public String JavaDoc getApplicationJarPath() {
2155        return applicationJarPath;
2156    }
2157
2158    /**
2159     * Sets the ServerHooks
2160     * @since 1.3.3
2161     */

2162    public void setServerHooks(ServerHooks serverHooks) {
2163        this.serverHooks = serverHooks;
2164    }
2165    /**
2166     * Returns ServerHooks if present else <code>null</code>.
2167     * @since 1.3.3
2168     */

2169    public ServerHooks getServerHooks() {
2170        if(serverHooks==null)
2171            serverHooks = new ServerHooks();
2172        return serverHooks;
2173    }
2174
2175    /**
2176     * @since 1.3.3
2177     */

2178    private void loadServerHooksClasses() {
2179        if(getServerHooks()==null) return;
2180        listOfServerHooks = new ArrayList();
2181        ServerHook serverHook = null;
2182        String JavaDoc serverHookClassName = null;
2183        Class JavaDoc serverHookClass = null;
2184
2185        //add system hooks
2186
serverHook = new GhostSocketReaper();
2187        serverHook.initHook(QuickServer.this);
2188        listOfServerHooks.add(serverHook);
2189        ghostSocketReaper = (GhostSocketReaper) serverHook;
2190
2191        //add user hooks if any
2192
Iterator iterator = getServerHooks().iterator();
2193        while(iterator.hasNext()) {
2194            serverHookClassName = (String JavaDoc)iterator.next();
2195            try {
2196                serverHookClass = getClass(serverHookClassName, true);
2197                serverHook = (ServerHook)serverHookClass.newInstance();
2198                serverHook.initHook(QuickServer.this);
2199                listOfServerHooks.add(serverHook);
2200                logger.info("Loaded server hook: " + serverHookClassName);
2201                logger.fine("Server hook info: " + serverHook.info());
2202            } catch(Exception JavaDoc e) {
2203                logger.warning("Could not load server hook ["+serverHookClassName+"]: " + e);
2204                logger.fine("StackTrace:\n"+MyString.getStackTrace(e));
2205            }
2206        }//end of while
2207
}
2208
2209    /**
2210     * @since 1.3.3
2211     */

2212    private void processServerHooks(int event) {
2213        if(listOfServerHooks==null) {
2214            logger.warning("listOfServerHooks was null!");
2215            return;
2216        }
2217        ServerHook serverHook = null;
2218        boolean result = false;
2219        Iterator iterator = listOfServerHooks.iterator();
2220
2221        String JavaDoc hooktype = "UNKNOWN";
2222        switch(event) {
2223            case ServerHook.PRE_STARTUP: hooktype="PRE_STARTUP";break;
2224            case ServerHook.POST_STARTUP: hooktype="POST_STARTUP";break;
2225            case ServerHook.PRE_SHUTDOWN: hooktype="PRE_SHUTDOWN";break;
2226            case ServerHook.POST_SHUTDOWN: hooktype="POST_SHUTDOWN";break;
2227        }
2228        
2229        while(iterator.hasNext()) {
2230            serverHook = (ServerHook)iterator.next();
2231            try {
2232                result = serverHook.handleEvent(event);
2233            } catch(Exception JavaDoc e) {
2234                result = false;
2235                logger.warning("Error invoking "+hooktype+" hook ["+
2236                    serverHook.getClass().getName()+"]: " + e.getMessage());
2237            }
2238            logger.fine("Invoked "+hooktype+" hook ["+
2239                serverHook.getClass().getName()+"] was: "+result);
2240        }
2241    }
2242
2243    /**
2244     * Creates and returns a copy of this object.
2245     * @since 1.3.3
2246     */

2247    public Object JavaDoc clone() {
2248        Object JavaDoc object = null;
2249        try {
2250            object = super.clone();
2251            QuickServer _qs = (QuickServer) object;
2252            _qs.setQSAdminServer( new QSAdminServer(_qs) );
2253        } catch(CloneNotSupportedException JavaDoc e) {
2254            logger.warning("Error cloning : "+e);//should not happ
2255
}
2256        return object;
2257    }
2258
2259    /**
2260     * Sets the Secure setting for QuickServer
2261     * @since 1.4.0
2262     */

2263    public void setSecure(Secure secure) {
2264        this.secure = secure;
2265    }
2266    /**
2267     * Returns Secure setting for QuickServer
2268     * @since 1.4.0
2269     */

2270    public Secure getSecure() {
2271        if(secure==null) secure = new Secure();
2272        return secure;
2273    }
2274
2275    /**
2276     * <p>Returns if the server is running in Secure mode [SSL or TLS].</p>
2277     * @since 1.4.0
2278     */

2279    public boolean isRunningSecure() {
2280        return runningSecure;
2281    }
2282
2283    /**
2284     * <p>Sets the server mode if its running in Secure mode [SSL or TLS].</p>
2285     * @since 1.4.0
2286     */

2287    public void setRunningSecure(boolean runningSecure) {
2288        this.runningSecure = runningSecure;
2289    }
2290
2291    private File makeAbsoluteToConfig(String JavaDoc fileName) {
2292        Assertion.affirm(fileName!=null, "FileName can't be null");
2293        return ConfigReader.makeAbsoluteToConfig(fileName, getConfig());
2294    }
2295
2296    /**
2297     * Returns a ServerSocket object to be used for listening.
2298     * @since 1.4.0
2299     */

2300    protected void makeServerSocket()
2301            throws BindException, IOException {
2302        server = null;
2303        logger.finest("Binding "+getName()+" to IP: "+getBindAddr());
2304        InetSocketAddress bindAddress =
2305            new InetSocketAddress(getBindAddr(), getPort());
2306
2307        try {
2308            NetworkInterface ni = NetworkInterface.getByInetAddress(getBindAddr());
2309            if(ni!=null) {
2310                logger.fine("NetworkInterface: "+ni);
2311            }
2312        } catch(Exception JavaDoc igrnore) {/*ignore*/}
2313          catch(Error JavaDoc igrnore) {/*ignore*/}
2314        
2315
2316        if(getSecure().isEnable()==false) {
2317            logger.fine("Making a normal ServerSocket for "+getName());
2318            setRunningSecure(false);
2319            
2320            if(getBlockingMode()==false) {
2321                //for non-blocking
2322
serverSocketChannel = ServerSocketChannel.open();
2323                server = serverSocketChannel.socket();
2324                server.bind(bindAddress,
2325                    getBasicConfig().getAdvancedSettings().getBacklog());
2326            } else {
2327                //for blocking
2328
server = new ServerSocket(getPort(), getBasicConfig().getAdvancedSettings().getBacklog(), getBindAddr());
2329            }
2330        } else {
2331            logger.fine("Making a secure ServerSocket for "+getName());
2332            try {
2333                ServerSocketFactory ssf =
2334                    getSSLContext().getServerSocketFactory();
2335                SSLServerSocket serversocket = (SSLServerSocket)
2336                    ssf.createServerSocket(getPort(),
2337                    getBasicConfig().getAdvancedSettings().getBacklog(),
2338                    getBindAddr());
2339                serversocket.setNeedClientAuth(secure.isClientAuthEnable());
2340                setRunningSecure(true);
2341
2342                secureStoreManager.logSSLServerSocketInfo(serversocket);
2343
2344                server = serversocket;
2345                serverSocketChannel = server.getChannel();
2346                if(serverSocketChannel==null && getBlockingMode()==false) {
2347                    logger.warning("Secure Server does not support Channel! So will run in blocking mode.");
2348                    blockingMode = true;
2349                }
2350            } catch(NoSuchAlgorithmException e) {
2351                logger.warning("NoSuchAlgorithmException : "+e);
2352                throw new IOException("Error creating secure socket : "+e.getMessage());
2353            } catch(KeyManagementException e) {
2354                logger.warning("KeyManagementException : "+e);
2355                throw new IOException("Error creating secure socket : "+e.getMessage());
2356            }
2357        }
2358
2359        server.setReuseAddress(true);
2360
2361        if(getBlockingMode()==false) {
2362            logger.fine("Server Mode "+getName()+" - Non Blocking");
2363            if(selector==null || selector.isOpen()==false) {
2364                logger.finest("Opening new selector");
2365                selector = Selector.open();
2366            } else {
2367                logger.finest("Reusing selector: "+selector);
2368            }
2369            serverSocketChannel.configureBlocking(false);
2370            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
2371            selector.wakeup();
2372        } else {
2373            logger.fine("Server Mode "+getName()+" - Blocking");
2374        }
2375    }
2376
2377    /**
2378     * Sets the basic confiuration of the QuickServer.
2379     * @since 1.4.0
2380     */

2381    public void setBasicConfig(BasicServerConfig basicConfig)
2382            throws Exception JavaDoc {
2383        Assertion.affirm(basicConfig!=null, "BasicServerConfig can't be null");
2384        this.basicConfig = basicConfig;
2385    }
2386
2387    /**
2388     * Returns the basic confiuration of the QuickServer.
2389     * @since 1.4.0
2390     */

2391    public BasicServerConfig getBasicConfig() {
2392        return basicConfig;
2393    }
2394
2395    /**
2396     * Loads the <code>SSLContext</code> from Secure configuring if set.
2397     * @see #setSecure
2398     * @since 1.4.0
2399     */

2400    public void loadSSLContext() throws IOException {
2401        if(getSecure().isLoad()==false) {
2402            throw new IllegalStateException JavaDoc("Secure setting is not yet enabled for loading!");
2403        }
2404        logger.info("Loading Secure Context..");
2405        km = null;
2406        tm = null;
2407        try {
2408            String JavaDoc ssManager = "org.quickserver.security.SecureStoreManager";
2409            if(getSecure().getSecureStore()!=null)
2410                ssManager = getSecure().getSecureStore().getSecureStoreManager();
2411
2412            Class JavaDoc secureStoreManagerClass = getClass(ssManager, true);
2413
2414            secureStoreManager = (SecureStoreManager) secureStoreManagerClass.newInstance();
2415
2416            km = secureStoreManager.loadKeyManagers(getConfig());
2417            logger.fine("KeyManager got");
2418
2419            tm = secureStoreManager.loadTrustManagers(getConfig());
2420            logger.fine("TrustManager got");
2421
2422            sslc = secureStoreManager.getSSLContext(getConfig().getSecure().getProtocol());
2423            sslc.init(km, tm, null);
2424            logger.fine("SSLContext loaded");
2425        } catch(KeyStoreException e) {
2426            logger.warning("KeyStoreException : "+e);
2427            throw new IOException("Error creating secure socket : "+e.getMessage());
2428        } catch(NoSuchAlgorithmException e) {
2429            logger.warning("NoSuchAlgorithmException : "+e);
2430            throw new IOException("Error creating secure socket : "+e.getMessage());
2431        } catch(NoSuchProviderException e) {
2432            logger.warning("NoSuchProviderException : "+e);
2433            throw new IOException("Error creating secure socket : "+e.getMessage());
2434        } catch(UnrecoverableKeyException e) {
2435            logger.warning("UnrecoverableKeyException : "+e);
2436            throw new IOException("Error creating secure socket : "+e.getMessage());
2437        } catch(CertificateException e) {
2438            logger.warning("CertificateException : "+e);
2439            throw new IOException("Error creating secure socket : "+e.getMessage());
2440        } catch(KeyManagementException e) {
2441            logger.warning("KeyManagementException : "+e);
2442            throw new IOException("Error creating secure socket : "+e.getMessage());
2443        } catch(GeneralSecurityException e) {
2444            logger.warning("GeneralSecurityException : "+e);
2445            throw new IOException("Error creating secure socket : "+e.getMessage());
2446        } catch(ClassNotFoundException JavaDoc e) {
2447            logger.warning("ClassNotFoundException : "+e);
2448            throw new IOException("Error creating secure socket : "+e.getMessage());
2449        } catch(InstantiationException JavaDoc e) {
2450            logger.warning("InstantiationException : "+e);
2451            throw new IOException("Error creating secure socket : "+e.getMessage());
2452        } catch(IllegalAccessException JavaDoc e) {
2453            logger.warning("IllegalAccessException : "+e);
2454            throw new IOException("Error creating secure socket : "+e.getMessage());
2455        }
2456    }
2457
2458    /**
2459     * Returns the <code>SSLContext</code> from Secure configuring.
2460     * @see #loadSSLContext
2461     * @since 1.4.0
2462     */

2463    public SSLContext getSSLContext()
2464            throws IOException, NoSuchAlgorithmException,
2465                KeyManagementException {
2466        return getSSLContext(null);
2467    }
2468
2469    /**
2470     * Returns the <code>SSLContext</code> object that implements the specified
2471     * secure socket protocol from Secure configuring.
2472     * @see #loadSSLContext
2473     * @param protocol the standard name of the requested protocol. If <code>null</code> will use the protocol set in secure configuration of the server.
2474     * @throws IOException
2475     * @throws NoSuchAlgorithmException
2476     * @throws KeyManagementException
2477     * @since 1.4.0
2478     */

2479    public SSLContext getSSLContext(String JavaDoc protocol)
2480            throws IOException, NoSuchAlgorithmException,
2481                KeyManagementException {
2482        if(sslc==null) loadSSLContext();
2483        if(protocol!=null && secureStoreManager!=null) {
2484            SSLContext _sslc = secureStoreManager.getSSLContext(protocol);
2485            _sslc.init(km, tm, null);
2486            return _sslc;
2487        }
2488        return sslc;
2489    }
2490
2491    /**
2492     * Returns a SSLSocketFactory object to be used for creating SSLSockets.
2493     * Secure socket protocol will be picked from the Secure configuring.
2494     * @see #setSecure
2495     * @throws IOException
2496     * @throws NoSuchAlgorithmException
2497     * @throws KeyManagementException
2498     * @since 1.4.0
2499     */

2500    public SSLSocketFactory getSSLSocketFactory()
2501            throws IOException, NoSuchAlgorithmException,
2502                KeyManagementException {
2503        if(sslc==null) loadSSLContext();
2504        return secureStoreManager.getSocketFactory(getSSLContext());
2505    }
2506
2507    /**
2508     * Returns a SSLSocketFactory object to be used for creating SSLSockets.
2509     * @see #setSecure
2510     * @param protocol the standard name of the requested protocol. If
2511     * <code>null</code> will use the protocol set in secure configuration
2512     * of the server.
2513     * @throws IOException
2514     * @throws NoSuchAlgorithmException
2515     * @throws KeyManagementException
2516     * @since 1.4.0
2517     */

2518    public SSLSocketFactory getSSLSocketFactory(String JavaDoc protocol)
2519            throws IOException, NoSuchAlgorithmException, KeyManagementException {
2520        if(sslc==null) loadSSLContext();
2521        return secureStoreManager.getSocketFactory(getSSLContext(protocol));
2522    }
2523
2524    /**
2525     * Sets the ClientBinaryHandler class that interacts with
2526     * client sockets to handle binary data.
2527     * @param handler object the fully qualified name of the class that
2528     * implements {@link ClientBinaryHandler}
2529     * @see #getClientBinaryHandler
2530     * @since 1.4
2531     */

2532    public void setClientBinaryHandler(String JavaDoc handler) {
2533        clientBinaryHandlerString = handler;
2534        logger.finest("Set to "+handler);
2535    }
2536    /**
2537     * Returns the ClientBinaryHandler class that interacts with
2538     * client sockets.
2539     * @see #setClientBinaryHandler
2540     * @since 1.4
2541     */

2542    public String JavaDoc getClientBinaryHandler() {
2543        return clientBinaryHandlerString;
2544    }
2545
2546    /**
2547     * Sets the Selector (NIO).
2548     * @since 1.4.5
2549     */

2550    public void setSelector(Selector selector) {
2551        this.selector = selector;
2552    }
2553    /**
2554     * Returns the Selector (NIO),if any.
2555     * @since 1.4.5
2556     */

2557    public Selector getSelector() {
2558        return selector;
2559    }
2560
2561    /**
2562     * Starts server in blocking mode.
2563     * @since 1.4.5
2564     */

2565    private void runBlocking(TheClient theClient) throws Exception JavaDoc {
2566        Socket client = null;
2567        ClientHandler _chPolled = null;
2568        int linger = getBasicConfig().getAdvancedSettings().getSocketLinger();
2569
2570        //long stime = System.currentTimeMillis();
2571
//long etime = System.currentTimeMillis();
2572
while(true) {
2573            //etime = System.currentTimeMillis();
2574
//System.out.println("Time Taken: "+(etime-stime));
2575
client = server.accept();
2576            //stime = System.currentTimeMillis();
2577

2578            if(linger<0) {
2579                client.setSoLinger(false, 0);
2580            } else {
2581                client.setSoLinger(true, linger);
2582            }
2583
2584            if(stopServer) {
2585                //Client connected when server was about to be shutdown.
2586
try {
2587                    client.close();
2588                } catch(Exception JavaDoc e) {}
2589                break;
2590            }
2591
2592            if(checkAccessConstraint(client)==false) {
2593                continue;
2594            }
2595
2596            //Check if max connection has reached
2597
if(getSkipValidation()!=true && maxConnection != -1 &&
2598                    getClientHandlerPool().getNumActive() >= maxConnection) {
2599                theClient.setClientEvent(ClientEvent.MAX_CON_BLOCKING);
2600            } else {
2601                theClient.setClientEvent(ClientEvent.RUN_BLOCKING);
2602            }
2603
2604            theClient.setTrusted(getSkipValidation());
2605            theClient.setSocket(client);
2606            theClient.setSocketChannel(client.getChannel()); //mostly null
2607

2608            if(clientDataClass != null) {
2609                if(getClientDataPool()==null) {
2610                    clientData = (ClientData)clientDataClass.newInstance();
2611                } else {
2612                    clientData = (ClientData)getClientDataPool().borrowObject();
2613                }
2614                theClient.setClientData(clientData);
2615            }
2616
2617            try {
2618                _chPolled = (ClientHandler) getClientHandlerPool().borrowObject();
2619                _chPolled.handleClient(theClient);
2620            } catch(java.util.NoSuchElementException JavaDoc nsee) {
2621                logger.warning("Could not borrow ClientHandler from pool. Error: "+nsee);
2622                logger.warning("Closing Socket ["+client+"] since no ClientHandler available.");
2623                client.close();
2624            }
2625            
2626            if(_chPolled!=null) {
2627                try {
2628                    getClientPool().addClient(_chPolled, true);
2629                } catch(java.util.NoSuchElementException JavaDoc nsee) {
2630                    logger.warning("Could not borrow Thread from pool. Error: "+nsee);
2631                    //logger.warning("Closing Socket ["+client+"] since no Thread available.");
2632
//client.close();
2633
//returnClientHandlerToPool(_chPolled);
2634
}
2635                _chPolled = null;
2636            }
2637            client = null;
2638
2639            //reset it back
2640
setSkipValidation(false);
2641        }//end of loop
2642
}
2643
2644    /**
2645     * Starts server in non-blocking mode.
2646     * @since 1.4.5
2647     */

2648    private void runNonBlocking(TheClient theClient) throws Exception JavaDoc {
2649        int selectCount = 0;
2650        Iterator iterator = null;
2651        SelectionKey key = null;
2652        ServerSocketChannel serverChannel = null;
2653        SocketChannel socketChannel = null;
2654        Socket client = null;
2655        ClientHandler _chPolled = null;
2656        boolean stopServerProcessed = false;
2657        int linger = getBasicConfig().getAdvancedSettings().getSocketLinger();
2658        registerChannelRequestMap = new HashMap();
2659
2660        while(true) {
2661            selectCount = selector.select(500);
2662            //selectCount = selector.select();//for testing
2663

2664            //check for any pending registerChannel req.
2665
synchronized(registerChannelRequestMap) {
2666                if(registerChannelRequestMap.size()>0) {
2667                    RegisterChannelRequest req = null;
2668                    Object JavaDoc hashkey = null;
2669                    iterator = registerChannelRequestMap.keySet().iterator();
2670                    while(iterator.hasNext()) {
2671                        hashkey = iterator.next();
2672                        req = (RegisterChannelRequest) registerChannelRequestMap.get(hashkey);
2673                        req.register(getSelector());
2674                    }
2675                    iterator = null;
2676                    registerChannelRequestMap.clear();
2677                }//if
2678
}//sync
2679

2680            if(stopServer==true && stopServerProcessed==false) {
2681                logger.warning("Closing "+getName());
2682                serverSocketChannel.close();
2683                stopServerProcessed = true;
2684
2685                server = null;
2686                serverSocketChannel = null;
2687
2688                setServiceState(Service.STOPPED);
2689                logger.warning("Closed "+getName());
2690
2691                processServerHooks(ServerHook.POST_SHUTDOWN);
2692            }
2693
2694            if(stopServer==false && stopServerProcessed==true) {
2695                logger.finest("Server must have re-started.. will break");
2696                break;
2697            }
2698
2699            if(selectCount==0 && stopServerProcessed==true) {
2700                java.util.Set JavaDoc keyset = selector.keys();
2701                if(keyset.isEmpty()==true && getClientCount()<=0) {
2702                    break;
2703                } else {
2704                    continue;
2705                }
2706            } else if(selectCount==0) {
2707                continue;
2708            }
2709
2710            iterator = selector.selectedKeys().iterator();
2711            while(iterator.hasNext()) {
2712                key = (SelectionKey) iterator.next();
2713
2714                if(key.isValid()==false) {
2715                    iterator.remove();
2716                    continue;
2717                }
2718                
2719                if(key.isAcceptable() && stopServer==false) {
2720                    logger.finest("Key is Acceptable");
2721                    serverChannel = (ServerSocketChannel) key.channel();
2722                    socketChannel = serverChannel.accept();
2723                    
2724                    if(socketChannel==null) {
2725                        iterator.remove();
2726                        continue;
2727                    }
2728
2729                    client = socketChannel.socket();
2730
2731                    if(linger<0) {
2732                        client.setSoLinger(false, 0);
2733                    } else {
2734                        client.setSoLinger(true, linger);
2735                    }
2736
2737                    if(checkAccessConstraint(client)==false) {
2738                        iterator.remove();
2739                        continue;
2740                    }
2741
2742                    socketChannel.configureBlocking(false);
2743                    theClient.setTrusted(getSkipValidation());
2744                    theClient.setSocket(socketChannel.socket());
2745                    theClient.setSocketChannel(socketChannel);
2746
2747                    if(clientDataClass != null) {
2748                        if(getClientDataPool()==null) {
2749                            clientData = (ClientData)clientDataClass.newInstance();
2750                        } else {
2751                            //borrow a object from pool
2752
clientData = (ClientData)getClientDataPool().borrowObject();
2753                        }
2754                        theClient.setClientData(clientData);
2755                    }
2756
2757                    //Check if max connection has reached
2758
if(getSkipValidation()!=true && maxConnection != -1 &&
2759                            getClientHandlerPool().getNumActive() >= maxConnection) {
2760                        theClient.setClientEvent(ClientEvent.MAX_CON);
2761                    } else {
2762                        theClient.setClientEvent(ClientEvent.ACCEPT);
2763                    }
2764
2765                    try {
2766                        _chPolled = (ClientHandler)getClientHandlerPool().borrowObject();
2767                        logger.finest("Asking "+_chPolled.getName()+" to handle.");
2768                        _chPolled.handleClient(theClient);
2769                    } catch(java.util.NoSuchElementException JavaDoc nsee) {
2770                        logger.warning("Could not borrow ClientHandler Object from pool. Error: "+nsee);
2771                        logger.warning("Closing SocketChannel ["+serverChannel.socket()+"] since no ClientHandler available.");
2772                        socketChannel.close();
2773                    }
2774
2775                    if(_chPolled!=null) {
2776                        try {
2777                            getClientPool().addClient(_chPolled, true);
2778                        } catch(java.util.NoSuchElementException JavaDoc nsee) {
2779                            logger.warning("Could not borrow Thread from pool. Error: "+nsee);
2780                            //logger.warning("Closing SocketChannel ["+serverChannel.socket()+"] since no Thread available.");
2781
//socketChannel.close();
2782
//returnClientHandlerToPool(_chPolled);
2783
}
2784                        _chPolled = null;
2785                    }
2786                    socketChannel = null;
2787                    client = null;
2788                    
2789                    setSkipValidation(false);//reset it back
2790
} else if(key.isValid() && key.isReadable()) {
2791                    boolean addedEvent = false;
2792                    ClientHandler _ch = null;
2793                    try {
2794                        _ch = (ClientHandler)key.attachment();
2795                        logger.finest("Key is Readable, removing OP_READ from interestOps for "+_ch.getName());
2796                        key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
2797                        _ch.addEvent(ClientEvent.READ);addedEvent= true;
2798                        //_ch.setSelectionKey(key);
2799
getClientPool().addClient(_ch);
2800                    } catch(CancelledKeyException cke) {
2801                        logger.fine("Ignored Error - Key was Cancelled: "+cke);
2802                    } catch(java.util.NoSuchElementException JavaDoc nsee) {
2803                        logger.finest("NoSuchElementException: "+nsee);
2804                        if(addedEvent) _ch.removeEvent(ClientEvent.READ);
2805                        continue;//no need to remove the key
2806
}
2807                    _ch = null;
2808                } else if(key.isValid() && key.isWritable()) {
2809                    if(getClientPool().shouldNioWriteHappen()==false) {
2810                        continue; //no need to remove the key
2811
}
2812                    boolean addedEvent = false;
2813                    ClientHandler _ch = null;
2814                    try {
2815                        _ch = (ClientHandler)key.attachment();
2816                        logger.finest("Key is Writable, removing OP_WRITE from interestOps for "+_ch.getName());
2817                        //remove OP_WRITE from interest set
2818
key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
2819                        _ch.addEvent(ClientEvent.WRITE);addedEvent= true;
2820                        //_ch.setSelectionKey(key);
2821
getClientPool().addClient(_ch);
2822                    } catch(CancelledKeyException cke) {
2823                        logger.fine("Ignored Error - Key was Cancelled: "+cke);
2824                    } catch(java.util.NoSuchElementException JavaDoc nsee) {
2825                        logger.finest("NoSuchElementException: "+nsee);
2826                        if(addedEvent) _ch.removeEvent(ClientEvent.WRITE);
2827                        continue;//no need to remove the key
2828
}
2829                    _ch = null;
2830                } else if(stopServer==true && key.isAcceptable()) {
2831                    //we will not accept this key
2832
setSkipValidation(false);//reset it back
2833
} else {
2834                    logger.warning("Unknown key got in SelectionKey: "+key);
2835                }
2836                iterator.remove(); //Remove key
2837

2838                Thread.yield();
2839            } //end of iterator
2840
iterator = null;
2841        }//end of loop
2842
}
2843
2844    private boolean checkAccessConstraint(Socket socket) {
2845        try {
2846            if(getAccessConstraintConfig()!=null) {
2847                getAccessConstraintConfig().checkAccept(socket);
2848            }
2849            return true;
2850        } catch(SecurityException JavaDoc se) {
2851            logger.warning("SecurityException occurred accepting connection : "
2852                +se.getMessage());
2853            return false;
2854        }
2855    }
2856
2857    /**
2858     * Register the given channel for the given operations. This adds the request
2859     * to a list and will be processed after selector select wakes up.
2860     * @return boolean flag to indicate if new entry was added to the list to register.
2861     * @since 1.4.5
2862     */

2863    public boolean registerChannel(SocketChannel channel, int ops, Object JavaDoc att)
2864            throws IOException, ClosedChannelException {
2865        if(getSelector()==null) {
2866            throw new IllegalStateException JavaDoc("Selector is not open!");
2867        }
2868        if(channel==null) {
2869            throw new IllegalArgumentException JavaDoc("Can't register a null channel!");
2870        }
2871
2872        if(channel.isConnected()==false) {
2873            throw new ClosedChannelException();
2874        }
2875        
2876        RegisterChannelRequest req = new RegisterChannelRequest(channel, ops, att);
2877        RegisterChannelRequest reqOld = null;
2878        synchronized(registerChannelRequestMap) {
2879            reqOld = (RegisterChannelRequest) registerChannelRequestMap.get(channel);
2880            if(reqOld==null) {
2881                registerChannelRequestMap.put(channel, req);
2882                getSelector().wakeup();
2883                return true;
2884            } else {
2885                if(reqOld.equals(req)==false) {
2886                    reqOld.setOps(reqOld.getOps() | req.getOps());
2887                    reqOld.setAtt(req.getAtt());
2888                    return true;
2889                }
2890                return false;
2891            }
2892        }
2893        /*
2894        logger.warning("Before register...");
2895        channel.register(getSelector(), ops, att);
2896        logger.warning("Before wakeup and after register...");
2897        getSelector().wakeup();
2898        logger.warning("After wakeup...");
2899        */

2900    }
2901
2902    /**
2903     * Makes the pool of ByteBuffer
2904     * @since 1.4.5
2905     */

2906    private void makeByteBufferPool(PoolConfig opConfig) {
2907        logger.finer("Creating ByteBufferPool pool");
2908
2909        int bufferSize = getBasicConfig().getAdvancedSettings().getByteBufferSize();
2910        boolean useDirectByteBuffer = getBasicConfig().getAdvancedSettings().getUseDirectByteBuffer();
2911        PoolableObjectFactory factory = new ByteBufferObjectFactory(bufferSize, useDirectByteBuffer);
2912
2913        byteBufferPool = poolManager.makeByteBufferPool(factory, opConfig);
2914        poolManager.initPool(byteBufferPool, opConfig);
2915    }
2916
2917    /**
2918     * Returns ObjectPool of java.nio.ByteBuffer class.
2919     * @since 1.4.5
2920     */

2921    public ObjectPool getByteBufferPool() {
2922        return byteBufferPool;
2923    }
2924
2925    /**
2926     * Makes the pool of ByteBuffer
2927     * @since 1.4.5
2928     */

2929    private void makeClientPool(PoolConfig opConfig) throws Exception JavaDoc {
2930        logger.finer("Creating ClientThread pool");
2931        ThreadObjectFactory factory = new ThreadObjectFactory();
2932        ObjectPool objectPool = poolManager.makeClientPool(factory, opConfig);
2933        pool = new ClientPool(makeQSObjectPool(objectPool), opConfig);
2934        factory.setClientPool(pool);
2935        pool.setMaxThreadsForNioWrite(
2936            getBasicConfig().getAdvancedSettings().getMaxThreadsForNioWrite());
2937        poolManager.initPool(objectPool, opConfig);
2938    }
2939
2940    /**
2941     * Sets the ClientWriteHandler class that interacts with
2942     * client sockets to handle data write (only used in non-blocking mode).
2943     * @param handler object the fully qualified name of the class that
2944     * implements {@link ClientWriteHandler}
2945     * @see #getClientWriteHandler
2946     * @since 1.4.5
2947     */

2948    public void setClientWriteHandler(String JavaDoc handler) {
2949        clientWriteHandlerString = handler;
2950        logger.finest("Set to "+handler);
2951    }
2952    /**
2953     * Returns the ClientWriteHandler class that interacts with
2954     * client sockets (only used in non-blocking mode).
2955     * @see #setClientWriteHandler
2956     * @since 1.4.5
2957     */

2958    public String JavaDoc getClientWriteHandler() {
2959        return clientWriteHandlerString;
2960    }
2961
2962    /**
2963     * Returns the date/time when the server was last started.
2964     * @return last started time. Will be <code>null</code> if never started.
2965     * @since 1.4.5
2966     */

2967    public java.util.Date JavaDoc getLastStartTime() {
2968        return lastStartTime;
2969    }
2970
2971    /**
2972     * Sets the debug flag to ByteBufferOutputStream and
2973     * ByteBufferInputStream class that are used in non-blcking mode
2974     * @since 1.4.5
2975     */

2976    public static void setDebugNonBlockingMode(boolean flag) {
2977        org.quickserver.util.io.ByteBufferOutputStream.setDebug(flag);
2978        org.quickserver.util.io.ByteBufferInputStream.setDebug(flag);
2979    }
2980
2981    /**
2982     * Returns the implementation that is used to do Client Identification.
2983     * @since 1.4.5
2984     */

2985    public ClientIdentifier getClientIdentifier() {
2986        return clientIdentifier;
2987    }
2988
2989    /**
2990     * Makes QSObjectPool from ObjectPool
2991     * @since 1.4.5
2992     */

2993    private QSObjectPool makeQSObjectPool(ObjectPool objectPool)
2994            throws Exception JavaDoc {
2995        return (QSObjectPool) qsObjectPoolMaker.getQSObjectPool(objectPool);
2996    }
2997
2998    
2999    /**
3000     * Returns the current blocking mode of the server.
3001     * @since 1.4.6
3002     */

3003    public boolean getBlockingMode() {
3004        return blockingMode;
3005    }
3006
3007    /**
3008     * Loads all the Business Logic class
3009     * @since 1.4.6
3010     */

3011    protected void loadBusinessLogic() throws Exception JavaDoc {
3012        if(clientCommandHandlerString == null &&
3013                clientEventHandlerString == null) {
3014            logger.severe("ClientCommandHandler AND ClientEventHandler was not set.");
3015            throw new AppException("ClientCommandHandler AND ClientEventHandler was not set.");
3016        }
3017
3018        clientCommandHandler = null;
3019        if(clientCommandHandlerString != null) {
3020            logger.finest("Loading ClientCommandHandler class..");
3021            Class JavaDoc clientCommandHandlerClass =
3022                getClass(clientCommandHandlerString, true);
3023            clientCommandHandler = (ClientCommandHandler)
3024                clientCommandHandlerClass.newInstance();
3025        }
3026
3027        boolean setClientCommandHandlerLookup = false;
3028        clientEventHandler = null;
3029        if(clientEventHandlerString==null) {
3030            clientEventHandlerString = "org.quickserver.net.server.impl.DefaultClientEventHandler";
3031            setClientCommandHandlerLookup = true;
3032        }
3033        logger.finest("Loading ClientEventHandler class..");
3034        if(clientEventHandlerString.equals(clientCommandHandlerString) &&
3035                ClientEventHandler.class.isInstance(clientCommandHandler)) {
3036            clientEventHandler = (ClientEventHandler) clientCommandHandler;
3037        } else {
3038            clientEventHandler = (ClientEventHandler)
3039                getClass(clientEventHandlerString, true).newInstance();
3040            if(setClientCommandHandlerLookup) {
3041                ((DefaultClientEventHandler)clientEventHandler).setClientCommandHandler(
3042                    clientCommandHandler);
3043            }
3044        }
3045
3046        clientExtendedEventHandler = null;
3047        if(clientExtendedEventHandlerString != null) {
3048            logger.finest("Loading ClientExtendedEventHandler class..");
3049            if(clientExtendedEventHandlerString.equals(clientCommandHandlerString) &&
3050                    ClientExtendedEventHandler.class.isInstance(clientCommandHandler)) {
3051                clientExtendedEventHandler = (ClientExtendedEventHandler) clientCommandHandler;
3052            } else if(clientExtendedEventHandlerString.equals(clientEventHandlerString) &&
3053                    ClientExtendedEventHandler.class.isInstance(clientEventHandler)) {
3054                clientExtendedEventHandler = (ClientExtendedEventHandler) clientEventHandler;
3055            } else {
3056                Class JavaDoc clientExtendedEventHandlerClass =
3057                    getClass(clientExtendedEventHandlerString, true);
3058                clientExtendedEventHandler = (ClientExtendedEventHandler)
3059                    clientExtendedEventHandlerClass.newInstance();
3060            }
3061        }
3062
3063        clientObjectHandler = null;
3064        if(clientObjectHandlerString != null) {
3065            logger.finest("Loading ClientObjectHandler class..");
3066            if(clientObjectHandlerString.equals(clientCommandHandlerString) &&
3067                    ClientObjectHandler.class.isInstance(clientCommandHandler)) {
3068                clientObjectHandler = (ClientObjectHandler) clientCommandHandler;
3069            } else if(clientObjectHandlerString.equals(clientEventHandlerString) &&
3070                    ClientObjectHandler.class.isInstance(clientEventHandler)) {
3071                clientObjectHandler = (ClientObjectHandler) clientEventHandler;
3072            } else if(clientObjectHandlerString.equals(clientExtendedEventHandlerString) &&
3073                    ClientObjectHandler.class.isInstance(clientExtendedEventHandler)) {
3074                clientObjectHandler = (ClientObjectHandler) clientExtendedEventHandler;
3075            } else {
3076                clientObjectHandler = (ClientObjectHandler)
3077                    getClass(clientObjectHandlerString, true).newInstance();
3078            }
3079        } //end of != null
3080

3081        clientBinaryHandler = null;
3082        if(clientBinaryHandlerString != null) {
3083            logger.finest("Loading ClientBinaryHandler class..");
3084            if(clientBinaryHandlerString.equals(clientCommandHandlerString) &&
3085                    ClientBinaryHandler.class.isInstance(clientCommandHandler)) {
3086                clientBinaryHandler = (ClientBinaryHandler) clientCommandHandler;
3087            } else if(clientBinaryHandlerString.equals(clientEventHandlerString) &&
3088                    ClientBinaryHandler.class.isInstance(clientEventHandler)) {
3089                clientBinaryHandler = (ClientBinaryHandler) clientEventHandler;
3090            } else if(clientBinaryHandlerString.equals(clientExtendedEventHandlerString) &&
3091                    ClientBinaryHandler.class.isInstance(clientExtendedEventHandler)) {
3092                clientBinaryHandler = (ClientBinaryHandler) clientExtendedEventHandler;
3093            } else if(clientBinaryHandlerString.equals(clientObjectHandlerString) &&
3094                    ClientBinaryHandler.class.isInstance(clientObjectHandler)) {
3095                clientBinaryHandler = (ClientBinaryHandler) clientObjectHandler;
3096            } else {
3097                clientBinaryHandler = (ClientBinaryHandler)
3098                    getClass(clientBinaryHandlerString, true).newInstance();
3099            }
3100        } //end of != null
3101

3102        clientWriteHandler = null;
3103        if(clientWriteHandlerString != null) {
3104            logger.finest("Loading ClientWriteHandler class..");
3105            if(clientWriteHandlerString.equals(clientCommandHandlerString) &&
3106                    ClientWriteHandler.class.isInstance(clientCommandHandler)) {
3107                clientWriteHandler = (ClientWriteHandler) clientCommandHandler;
3108            } else if(clientWriteHandlerString.equals(clientEventHandlerString) &&
3109                    ClientWriteHandler.class.isInstance(clientEventHandler)) {
3110                clientWriteHandler = (ClientWriteHandler) clientEventHandler;
3111            } else if(clientWriteHandlerString.equals(clientExtendedEventHandlerString) &&
3112                    ClientWriteHandler.class.isInstance(clientExtendedEventHandler)) {
3113                clientWriteHandler = (ClientWriteHandler) clientExtendedEventHandler;
3114            } else if(clientWriteHandlerString.equals(clientObjectHandlerString) &&
3115                    ClientWriteHandler.class.isInstance(clientObjectHandler)) {
3116                clientWriteHandler = (ClientWriteHandler) clientObjectHandler;
3117            } else if(clientWriteHandlerString.equals(clientBinaryHandlerString) &&
3118                    ClientWriteHandler.class.isInstance(clientBinaryHandler)) {
3119                clientWriteHandler = (ClientWriteHandler) clientBinaryHandler;
3120            } else {
3121                clientWriteHandler = (ClientWriteHandler)
3122                    getClass(clientWriteHandlerString, true).newInstance();
3123            }
3124        } //end of != null
3125

3126        Class JavaDoc authenticatorClass = null;
3127        if(clientAuthenticationHandlerString != null) {
3128            logger.finest("Loading ClientAuthenticationHandler class..");
3129            authenticatorClass = getClass(clientAuthenticationHandlerString, true);
3130        }
3131
3132        if(authenticatorClass!=null) {
3133            Object JavaDoc obj = authenticatorClass.newInstance();
3134
3135            if(ClientAuthenticationHandler.class.isInstance(obj))
3136                clientAuthenticationHandler = (ClientAuthenticationHandler) obj;
3137            else
3138                authenticator = (Authenticator) obj;
3139        }
3140
3141        clientDataClass = null;
3142        if(clientDataString != null) {
3143            logger.finest("Loading ClientData class..");
3144            clientDataClass = getClass(clientDataString, true);
3145        }
3146
3147        Assertion.affirm(clientEventHandler!=null, "ClientEventHandler was not loaded!");
3148    }
3149
3150    /**
3151     * Sets the ClientEventHandler class that gets notified of
3152     * client events.
3153     * @param handler the fully qualified name of the class that
3154     * implements {@link ClientEventHandler}
3155     * @see #getClientEventHandler
3156     * @since 1.4.6
3157     */

3158    public void setClientEventHandler(String JavaDoc handler) {
3159        clientEventHandlerString = handler;
3160        logger.finest("Set to "+handler);
3161    }
3162    /**
3163     * Returns the ClientEventHandler class that gets notified of
3164     * client events.
3165     * @see #setClientEventHandler
3166     * @since 1.4.6
3167     */

3168    public String JavaDoc getClientEventHandler() {
3169        return clientEventHandlerString;
3170    }
3171
3172    /**
3173     * Sets the default {@link DataMode} for the ClientHandler
3174     * @since 1.4.6
3175     */

3176    public void setDefaultDataMode(DataMode dataMode, DataType dataType)
3177            throws IOException {
3178        if(dataType==DataType.IN)
3179            this.defaultDataModeIN = dataMode;
3180        if(dataType==DataType.OUT)
3181            this.defaultDataModeOUT = dataMode;
3182    }
3183    /**
3184     * Sets the default {@link DataMode} for the ClientHandler
3185     * @since 1.4.6
3186     */

3187    public void setDefaultDataMode(DefaultDataMode defaultDataMode)
3188            throws IOException {
3189        defaultDataModeIN = defaultDataMode.getDataMode(DataType.IN);
3190        defaultDataModeOUT = defaultDataMode.getDataMode(DataType.OUT);;
3191    }
3192    /**
3193     * Returns the default {@link DataMode} for the ClientHandler
3194     * @since 1.4.6
3195     */

3196    public DataMode getDefaultDataMode(DataType dataType) {
3197        if(dataType==DataType.IN)
3198            return defaultDataModeIN;
3199        if(dataType==DataType.OUT)
3200            return defaultDataModeOUT;
3201        else
3202            throw new IllegalArgumentException JavaDoc("Unknown DataType: "+dataType);
3203    }
3204
3205    /**
3206     * Sets the ClientExtendedEventHandler class that gets notified of
3207     * extended client events.
3208     * @param handler the fully qualified name of the class that
3209     * implements {@link ClientExtendedEventHandler}
3210     * @see #getClientExtendedEventHandler
3211     * @since 1.4.6
3212     */

3213    public void setClientExtendedEventHandler(String JavaDoc handler) {
3214        clientExtendedEventHandlerString = handler;
3215        logger.finest("Set to "+handler);
3216    }
3217    /**
3218     * Returns the ClientExtendedEventHandler class that gets notified of
3219     * extended client events.
3220     * @see #setClientExtendedEventHandler
3221     * @since 1.4.6
3222     */

3223    public String JavaDoc getClientExtendedEventHandler() {
3224        return clientExtendedEventHandlerString;
3225    }
3226
3227    /**
3228     * If Application Jar Path was set, load the jars
3229     * @since 1.4.6
3230     */

3231    private void loadApplicationClasses() throws Exception JavaDoc {
3232        if(getApplicationJarPath()!=null && getClassLoader()==null) {
3233            setClassLoader(
3234                ClassUtil.getClassLoader(getApplicationJarPath()));
3235            //update qsadmin to use the same
3236
if(adminServer!=null) {
3237                adminServer.getServer().setClassLoader(getClassLoader());
3238            }
3239        }
3240    }
3241}
3242
Popular Tags