001: /*
002: * CoadunationLib: The coaduntion implementation library.
003: * Copyright (C) 2006 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * HttpRequestManager.java
020: *
021: * This object is responsible for queuing the http requests.
022: */
023:
024: // the package path
025: package com.rift.coad.lib.httpd;
026:
027: // java imports
028: import java.util.Vector;
029:
030: // log 4 j imports
031: import org.apache.log4j.Logger;
032:
033: // coadunation imports
034: import com.rift.coad.lib.thread.BasicThread;
035: import com.rift.coad.lib.thread.CoadunationThreadGroup;
036: import com.rift.coad.lib.thread.ThreadStateMonitor;
037: import com.rift.coad.lib.security.ThreadsPermissionContainer;
038: import com.rift.coad.lib.configuration.Configuration;
039: import com.rift.coad.lib.configuration.ConfigurationFactory;
040:
041: /**
042: * This object is responsible for queuing the http requests.
043: *
044: * @author Brett Chaldecott
045: */
046: public class HttpRequestManager {
047:
048: // the http request queue
049: public class HttpRequestQueue {
050: // the classes private member variables
051: private Vector requestQueue = new Vector();
052:
053: /**
054: * The constructor of the http request queue.
055: */
056: public HttpRequestQueue() {
057:
058: }
059:
060: /**
061: * This method adds a new request to the request queue.
062: *
063: *
064: * @param requestInterface The reference to the http service handler object.
065: * @exception HttpdException
066: */
067: public synchronized void pushRequest(
068: RequestInterface requestInterface)
069: throws HttpdException {
070: processorPoolManager.notifyThread();
071: requestQueue.add(requestInterface);
072: }
073:
074: /**
075: * This method will pop a request of the queue.
076: */
077: public synchronized RequestInterface popRequest() {
078: if (requestQueue.size() == 0) {
079: return null;
080: }
081: RequestInterface requestInterface = (RequestInterface) requestQueue
082: .get(0);
083: requestQueue.remove(0);
084: return requestInterface;
085: }
086:
087: /**
088: * This method returns the size of the http request manager.
089: *
090: * @return The size of the http request manager.
091: */
092: public synchronized int size() {
093: return requestQueue.size();
094: }
095: }
096:
097: /**
098: * This thread is responsible controlling the http processing required by
099: * clients.
100: */
101: public class HttpProcessor extends BasicThread {
102:
103: // The classes private member variables
104: private ThreadStateMonitor threadStateMonitor = new ThreadStateMonitor();
105:
106: /**
107: * The constructor of the http processor.
108: */
109: public HttpProcessor() throws Exception {
110:
111: }
112:
113: /**
114: * This method replaces the run method in the BasicThread.
115: *
116: * @exception Exception
117: */
118: public void process() throws Exception {
119: log.debug("Process.");
120: while (threadStateMonitor.isTerminated() == false) {
121: log.debug("Wait for request.");
122: if (processorPoolManager.monitor() == false) {
123: break;
124: }
125: log.debug("Get a request.");
126: RequestInterface requestInterface = requestQueue
127: .popRequest();
128: if (requestInterface != null) {
129: try {
130: log.info("Process a new http request.");
131: requestInterface.handleRequest();
132: } catch (Exception ex) {
133: log.error("Failed to process an HTTP request ["
134: + ex.getMessage() + "].", ex);
135: } finally {
136: requestInterface.destroy();
137: }
138: }
139: }
140: log.debug("Http Processor exiting.");
141: }
142:
143: /**
144: * This method will be implemented by child objects to terminate the
145: * processing of this thread.
146: */
147: public void terminate() {
148: log.debug("Terminate called on Http Processor");
149: threadStateMonitor.terminate(true);
150: }
151: }
152:
153: /**
154: * This object is responsible for controlling the processors. It
155: */
156: public class ProcessorPoolManager {
157:
158: // the private member variables
159: private boolean running = true;
160: private CoadunationThreadGroup threadGroup = null;
161: private int min = 0;
162: private int max = 0;
163: private int currentSize = 0;
164: private int waitingThreads = 0;
165: private int requestCount = 0;
166: private String username = null;
167:
168: /**
169: * The constructor of the thread group object.
170: *
171: * @param threadGroup The reference to the thread group.
172: * @param min The minimum value.
173: * @param max The maximum value.
174: * @param username The guest username.
175: */
176: public ProcessorPoolManager(CoadunationThreadGroup threadGroup,
177: int min, int max, String username)
178: throws HttpdException {
179: try {
180: this .threadGroup = threadGroup.createThreadGroup();
181: this .min = min;
182: this .max = max;
183: this .username = username;
184: } catch (Exception ex) {
185: throw new HttpdException(
186: "Failed to instanciate the processor pool manager : "
187: + ex.getMessage(), ex);
188: }
189: }
190:
191: /**
192: * This method terminates the waiting threads
193: */
194: public void shutdown() {
195: synchronized (this ) {
196: running = false;
197: notifyAll();
198: }
199: log.debug("Terminate the thread group");
200: threadGroup.terminate();
201: }
202:
203: /**
204: * This method will notify a waiting thread if one is available
205: * otherwise it will instanciate a new one.
206: */
207: public synchronized void notifyThread() throws HttpdException {
208: if (running) {
209: requestCount++;
210: if (waitingThreads > 0) {
211: log.debug("Notify a waiting thread 2");
212: notify();
213: } else if (currentSize < max) {
214: try {
215: log.debug("Add a thread");
216: // instanciate the deployment thread
217: HttpProcessor httpProcessor = new HttpProcessor();
218: threadGroup.addThread(httpProcessor, username);
219: httpProcessor.start();
220: currentSize++;
221: } catch (Exception ex) {
222: throw new HttpdException(
223: "Failed create a thread to process task : "
224: + ex.getMessage(), ex);
225: }
226: }
227: } else {
228: throw new HttpdException(
229: "Shut Down can handle not more requests");
230: }
231: }
232:
233: /**
234: * This method will be called a thread to either wait untill there are
235: * requests, get an exit notice if not require any more or start
236: * processing.
237: *
238: * @return TRUE if processing is required, FALSE if the thread must exit.
239: */
240: public synchronized boolean monitor() {
241: if (running == false) {
242: currentSize--;
243: return false;
244: } else if (requestCount > 0) {
245: requestCount--;
246: return true;
247: } else if (currentSize > min) {
248: currentSize--;
249: return false;
250: }
251: try {
252: waitingThreads++;
253: wait();
254: waitingThreads--;
255: } catch (Exception ex) {
256: // do nothing
257: }
258: return running;
259: }
260: }
261:
262: // class constants
263: private final static String MIN_KEY = "pool_min";
264: private final static long MIN_DEFAULT = 10;
265: private final static String MAX_KEY = "pool_max";
266: private final static long MAX_DEFAULT = 20;
267:
268: // static member variables
269: private Logger log = Logger.getLogger(HttpRequestManager.class
270: .getName());
271:
272: // the privat emember variables
273: private Configuration configuration = null;
274: private HttpRequestQueue requestQueue = new HttpRequestQueue();
275: private ProcessorPoolManager processorPoolManager = null;
276:
277: /**
278: * Creates a new instance of HttpRequestManager
279: *
280: *
281: * @param threadGroup The reference to the thread group object.
282: * @exception HttpdException
283: */
284: public HttpRequestManager(CoadunationThreadGroup threadGroup)
285: throws HttpdException {
286: try {
287: configuration = ConfigurationFactory.getInstance()
288: .getConfig(this .getClass());
289: processorPoolManager = new ProcessorPoolManager(
290: threadGroup, (int) configuration.getLong(MIN_KEY,
291: MIN_DEFAULT), (int) configuration.getLong(
292: MAX_KEY, MAX_DEFAULT), configuration
293: .getString(HttpDaemon.USERNAME_KEY));
294: } catch (Exception ex) {
295: throw new HttpdException(
296: "Failed to instanciate the http request manager : "
297: + ex.getMessage(), ex);
298: }
299: }
300:
301: /**
302: * This method stores the http service handler requests.
303: *
304: *
305: * @param requestInterface The reference to the new request to add.
306: * @exception HttpdException
307: */
308: public void addRequest(RequestInterface requestInterface)
309: throws HttpdException {
310: requestQueue.pushRequest(requestInterface);
311: }
312:
313: /**
314: * This mehtod will shut down this object
315: */
316: public void shutdown() {
317: processorPoolManager.shutdown();
318: }
319: }
|