Quadcap Embeddable Server

com/quadcap/net/server/Server.java

Go to the documentation of this file.
00001 package com.quadcap.net.server; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.IOException; 00042 00043 import java.util.Hashtable; 00044 import java.util.Iterator; 00045 import java.util.Properties; 00046 00047 import java.net.ServerSocket; 00048 00049 import com.quadcap.util.collections.ArrayQueue; 00050 import com.quadcap.util.collections.IntMap; 00051 00052 /** 00053 * A server has a set of workers, a context, and an acceptor. Workers 00054 * are created on demand, up to a configurable maximum. 00055 * 00056 * @author Stan Bailes 00057 */ 00058 public class Server { 00059 Class workerClass; 00060 Object workerLock = new Object(); 00061 Object context; 00062 ThreadGroup threads; 00063 IntMap allWorkers; 00064 ArrayQueue workers; 00065 int numWorkers = 0; 00066 int maxWorkers = 128; 00067 long shutdownInterval = 2000L; 00068 String name; 00069 00070 /*{com.quadcap.net.server.Server.xml} 00071 * <config-var> 00072 * <config-name>maxWorkers</config-name> 00073 * <config-dflt>64</config-dflt> 00074 * <config-desc>QWS uses a thread-pool architecture; new worker threads are 00075 * created on demand to satisfy load, up to a a configurable 00076 * maximum number, specified by this configuration parameter.</config-desc> 00077 * </config-var> 00078 * 00079 * <config-var> 00080 * <config-name>name</config-name> 00081 * <config-dflt><i>none</i></config-dflt> 00082 * <config-desc>Specify the name of this server.</config-desc> 00083 * </config-var> 00084 * 00085 * <config-var> 00086 * <config-name>workerClass</config-name> 00087 * <config-dflt><i>none</i></config-dflt> 00088 * <config-desc>Class to instantiate to handle requests</config-desc> 00089 * </config-var> 00090 * 00091 * <config-var> 00092 * <config-name>shutdownInterval</config-name> 00093 * <config-dflt>2000</config-dflt> 00094 * <config-desc>Graceful delay on shutdown</config-desc> 00095 * </config-var> 00096 * 00097 * <config-var> 00098 * <config-name>port</config-name> 00099 * <config-dflt><i>none</i></config-dflt> 00100 * <config-desc>TCP Port to accept connections from</config-desc> 00101 * </config-var> 00102 * 00103 * <config-var> 00104 * <config-name>queueDepth</config-name> 00105 * <config-dflt>16</config-dflt> 00106 * <config-desc>TCP listen queue depth</config-desc> 00107 * </config-var> 00108 */ 00109 public Server(Properties props, Object context) 00110 throws ClassNotFoundException 00111 { 00112 this.context = context; 00113 this.workerClass = Class.forName(props.getProperty("workerClass")); 00114 00115 int max = Integer.parseInt(props.getProperty("maxWorkers", "64")); 00116 this.workers = new ArrayQueue(max); 00117 this.allWorkers = new IntMap(max / 3); 00118 this.name = props.getProperty("name", "server"); 00119 this.threads = new ThreadGroup(name); 00120 this.shutdownInterval = 00121 Long.parseLong(props.getProperty("shutdownInterval", "2000")); 00122 00123 } 00124 00125 public ThreadGroup getThreadGroup() { 00126 return threads; 00127 } 00128 00129 public void startAcceptor(Properties props) throws IOException { 00130 int port = Integer.parseInt(props.getProperty("port")); 00131 int queueDepth = 00132 Integer.parseInt(props.getProperty("queueDepth", "16")); 00133 Acceptor acceptor = new Acceptor(this, port, queueDepth); 00134 Thread t = new Thread(threads, acceptor); 00135 t.start(); 00136 } 00137 00138 // XXX This implementation doesn't ensure fairness 00139 public Worker getIdleWorker() throws Exception { 00140 synchronized (workerLock) { 00141 while (true) { 00142 Worker w = (Worker)workers.popFront(); 00143 if (w != null) return w; 00144 00145 if (numWorkers < maxWorkers) { 00146 return newWorker(); 00147 } else { 00148 try { 00149 workerLock.wait(); 00150 } catch (InterruptedException ee) { 00151 } 00152 } 00153 } 00154 } 00155 } 00156 00157 public int getIdleWorkers(Worker[] workerv) throws Exception { 00158 int cnt = 0; 00159 synchronized (workerLock) { 00160 for (; cnt < workerv.length; cnt++) { 00161 Worker w = (Worker)workers.popFront(); 00162 if (w != null) { 00163 workerv[cnt] = w; 00164 } else { 00165 if (numWorkers < maxWorkers) { 00166 workerv[cnt] = newWorker(); 00167 } else if (cnt > 0) { 00168 break; 00169 } else { 00170 try { 00171 workerLock.wait(); 00172 } catch (InterruptedException ee) { 00173 } 00174 } 00175 } 00176 } 00177 } 00178 return cnt; 00179 } 00180 00181 public void returnIdleWorker(Worker w) { 00182 synchronized (workerLock) { 00183 workers.pushFront(w); 00184 workerLock.notifyAll(); 00185 } 00186 } 00187 00188 public void workerDone(Worker w) { 00189 allWorkers.remove(w.getId()); 00190 workerLock.notifyAll(); 00191 } 00192 00193 public Worker newWorker() throws Exception { 00194 Worker w = (Worker)workerClass.newInstance(); 00195 w.init(this, context, name); 00196 allWorkers.put(w.getId(), w); 00197 new Thread(threads, w).start(); 00198 return w; 00199 } 00200 00201 public void stop() { 00202 Iterator iter = allWorkers.keys(); 00203 while (iter.hasNext()) { 00204 int id = ((Integer)iter.next()).intValue(); 00205 Worker w = (Worker)allWorkers.get(id); 00206 w.stop(); 00207 } 00208 try { Thread.sleep(shutdownInterval); } catch (Throwable t) {} 00209 00210 if (threads.activeCount() > 0) { 00211 Thread[] ts = new Thread[threads.activeCount()]; 00212 int cnt = threads.enumerate(ts); 00213 for (int i = 0; i < cnt; i++) { 00214 Thread t = ts[i]; 00215 if (!t.isInterrupted()) { 00216 t.interrupt(); 00217 } 00218 } 00219 try { Thread.sleep(shutdownInterval); } catch (Throwable t) {} 00220 cnt = threads.enumerate(ts); 00221 for (int i = 0; i < cnt; i++) { 00222 Thread t = ts[i]; 00223 try { 00224 t.join(shutdownInterval/10); 00225 } catch (Throwable th) { 00226 } finally { 00227 try { 00228 t.stop(); 00229 } catch (Throwable th2) { 00230 } 00231 } 00232 } 00233 } 00234 } 00235 }