KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > net > server > Server


1 package com.quadcap.net.server;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.IOException JavaDoc;
42
43 import java.util.Hashtable JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.Properties JavaDoc;
46
47 import java.net.ServerSocket JavaDoc;
48
49 import com.quadcap.util.collections.ArrayQueue;
50 import com.quadcap.util.collections.IntMap;
51
52 /**
53  * A server has a set of workers, a context, and an acceptor. Workers
54  * are created on demand, up to a configurable maximum.
55  *
56  * @author Stan Bailes
57  */

58 public class Server {
59     Class JavaDoc workerClass;
60     Object JavaDoc workerLock = new Object JavaDoc();
61     Object JavaDoc context;
62     ThreadGroup JavaDoc threads;
63     IntMap allWorkers;
64     ArrayQueue workers;
65     int numWorkers = 0;
66     int maxWorkers = 128;
67     long shutdownInterval = 2000L;
68     String JavaDoc name;
69
70     /*{com.quadcap.net.server.Server.xml}
71      * <config-var>
72      * <config-name>maxWorkers</config-name>
73      * <config-dflt>64</config-dflt>
74      * <config-desc>QWS uses a thread-pool architecture; new worker threads are
75      * created on demand to satisfy load, up to a a configurable
76      * maximum number, specified by this configuration parameter.</config-desc>
77      * </config-var>
78      *
79      * <config-var>
80      * <config-name>name</config-name>
81      * <config-dflt><i>none</i></config-dflt>
82      * <config-desc>Specify the name of this server.</config-desc>
83      * </config-var>
84      *
85      * <config-var>
86      * <config-name>workerClass</config-name>
87      * <config-dflt><i>none</i></config-dflt>
88      * <config-desc>Class to instantiate to handle requests</config-desc>
89      * </config-var>
90      *
91      * <config-var>
92      * <config-name>shutdownInterval</config-name>
93      * <config-dflt>2000</config-dflt>
94      * <config-desc>Graceful delay on shutdown</config-desc>
95      * </config-var>
96      *
97      * <config-var>
98      * <config-name>port</config-name>
99      * <config-dflt><i>none</i></config-dflt>
100      * <config-desc>TCP Port to accept connections from</config-desc>
101      * </config-var>
102      *
103      * <config-var>
104      * <config-name>queueDepth</config-name>
105      * <config-dflt>16</config-dflt>
106      * <config-desc>TCP listen queue depth</config-desc>
107      * </config-var>
108      */

109     public Server(Properties JavaDoc props, Object JavaDoc context)
110         throws ClassNotFoundException JavaDoc
111     {
112         this.context = context;
113         this.workerClass = Class.forName(props.getProperty("workerClass"));
114
115         int max = Integer.parseInt(props.getProperty("maxWorkers", "64"));
116         this.workers = new ArrayQueue(max);
117         this.allWorkers = new IntMap(max / 3);
118         this.name = props.getProperty("name", "server");
119         this.threads = new ThreadGroup JavaDoc(name);
120         this.shutdownInterval =
121             Long.parseLong(props.getProperty("shutdownInterval", "2000"));
122         
123     }
124
125     public ThreadGroup JavaDoc getThreadGroup() {
126         return threads;
127     }
128     
129     public void startAcceptor(Properties JavaDoc props) throws IOException JavaDoc {
130         int port = Integer.parseInt(props.getProperty("port"));
131         int queueDepth =
132             Integer.parseInt(props.getProperty("queueDepth", "16"));
133         Acceptor acceptor = new Acceptor(this, port, queueDepth);
134         Thread JavaDoc t = new Thread JavaDoc(threads, acceptor);
135         t.start();
136     }
137
138     // XXX This implementation doesn't ensure fairness
139
public Worker getIdleWorker() throws Exception JavaDoc {
140         synchronized (workerLock) {
141             while (true) {
142                 Worker w = (Worker)workers.popFront();
143                 if (w != null) return w;
144
145                 if (numWorkers < maxWorkers) {
146                     return newWorker();
147                 } else {
148                     try {
149                         workerLock.wait();
150                     } catch (InterruptedException JavaDoc ee) {
151                     }
152                 }
153             }
154         }
155     }
156
157     public int getIdleWorkers(Worker[] workerv) throws Exception JavaDoc {
158         int cnt = 0;
159         synchronized (workerLock) {
160             for (; cnt < workerv.length; cnt++) {
161                 Worker w = (Worker)workers.popFront();
162                 if (w != null) {
163                     workerv[cnt] = w;
164                 } else {
165                     if (numWorkers < maxWorkers) {
166                         workerv[cnt] = newWorker();
167                     } else if (cnt > 0) {
168                         break;
169                     } else {
170                         try {
171                             workerLock.wait();
172                         } catch (InterruptedException JavaDoc ee) {
173                         }
174                     }
175                 }
176             }
177         }
178         return cnt;
179     }
180
181     public void returnIdleWorker(Worker w) {
182         synchronized (workerLock) {
183             workers.pushFront(w);
184             workerLock.notifyAll();
185         }
186     }
187
188     public void workerDone(Worker w) {
189         allWorkers.remove(w.getId());
190         workerLock.notifyAll();
191     }
192
193     public Worker newWorker() throws Exception JavaDoc {
194         Worker w = (Worker)workerClass.newInstance();
195         w.init(this, context, name);
196         allWorkers.put(w.getId(), w);
197         new Thread JavaDoc(threads, w).start();
198         return w;
199     }
200
201     public void stop() {
202         Iterator JavaDoc iter = allWorkers.keys();
203         while (iter.hasNext()) {
204             int id = ((Integer JavaDoc)iter.next()).intValue();
205             Worker w = (Worker)allWorkers.get(id);
206             w.stop();
207         }
208         try { Thread.sleep(shutdownInterval); } catch (Throwable JavaDoc t) {}
209
210         if (threads.activeCount() > 0) {
211             Thread JavaDoc[] ts = new Thread JavaDoc[threads.activeCount()];
212             int cnt = threads.enumerate(ts);
213             for (int i = 0; i < cnt; i++) {
214                 Thread JavaDoc t = ts[i];
215                 if (!t.isInterrupted()) {
216                     t.interrupt();
217                 }
218             }
219             try { Thread.sleep(shutdownInterval); } catch (Throwable JavaDoc t) {}
220             cnt = threads.enumerate(ts);
221             for (int i = 0; i < cnt; i++) {
222                 Thread JavaDoc t = ts[i];
223                 try {
224                     t.join(shutdownInterval/10);
225                 } catch (Throwable JavaDoc th) {
226                 } finally {
227                     try {
228                         t.stop();
229                     } catch (Throwable JavaDoc th2) {
230                     }
231                 }
232             }
233         }
234     }
235 }
236
Popular Tags