001: /*
002: * Copyright (c) 2001 by Matt Welsh and The Regents of the University of
003: * California. All rights reserved.
004: *
005: * Permission to use, copy, modify, and distribute this software and its
006: * documentation for any purpose, without fee, and without written agreement is
007: * hereby granted, provided that the above copyright notice and the following
008: * two paragraphs appear in all copies of this software.
009: *
010: * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
011: * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
012: * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
013: * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
014: *
015: * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
016: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
017: * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
018: * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
019: * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
020: *
021: * Authors: Eric Wagner <eric@xcf.berkeley.edu>
022: * Matt Welsh <mdw@cs.berkeley.edu>
023: */
024:
025: package com.rimfaxe.webserver.seda;
026:
027: import seda.apps.Haboob.hdapi.*;
028:
029: import seda.apps.Haboob.*;
030: import seda.apps.Haboob.http.*;
031: import seda.sandStorm.api.*;
032: import seda.sandStorm.core.*;
033: import seda.sandStorm.lib.http.*;
034: import seda.sandStorm.lib.aDisk.*;
035: import seda.util.*;
036: import java.io.*;
037: import java.util.*;
038:
039: public class DynamicHttp implements EventHandlerIF, HaboobConst {
040:
041: private static final boolean DEBUG = false;
042:
043: // Whether to close the HTTP connection after each request
044: private static final boolean CLOSE_CONNECTION = false;
045:
046: // Whether each URL should be handled by its own stage
047: private static final boolean SEPARATE_STAGES = true;
048:
049: private SinkIF mysink;
050: private static ConfigDataIF config;
051: private static SinkIF mainsink;
052: private static Hashtable handlerCache, stageCache;
053: private String myurl;
054:
055: public DynamicHttp() {
056: myurl = null;
057: }
058:
059: private DynamicHttp(String myurl) {
060: this .myurl = myurl;
061: }
062:
063: public void init(ConfigDataIF config) throws Exception {
064: this .config = config;
065: mysink = config.getStage().getSink();
066:
067: if (myurl == null) {
068: mainsink = mysink;
069: handlerCache = new Hashtable();
070: stageCache = new Hashtable();
071: } else {
072: //System.out.println("DynamicHttp handlerStage ["+myurl+"]: Started");
073: }
074: }
075:
076: public void destroy() {
077: }
078:
079: /**
080: * Handle the given request, passing it to the appropriate handler
081: * (and stage, if necessary). Returns true if the request can be
082: * processed, or false if the request was not for a dynamic URL.
083: */
084: public static boolean handleRequest(httpRequest req)
085: throws Exception {
086: HaboobStats.numRequests++;
087: String url = req.getURL();
088:
089: //System.out.println("DynamicHttp: handle "+url);
090:
091: boolean isStatic = false;
092:
093: String classname = "com.rimfaxe.webserver.seda.SedaHandler";
094: try {
095: handlerPool pool = (handlerPool) handlerCache
096: .get(classname);
097:
098: httpRequestHandlerIF handler = null;
099:
100: if (pool == null) {
101: handler = new com.rimfaxe.webserver.seda.SedaHandler();
102: } else {
103: handler = pool.getHandler();
104: }
105:
106: isStatic = handler.isCacheable(req);
107:
108: } catch (Exception e) {
109: System.out.println("" + e);
110: isStatic = false;
111: }
112:
113: if (isStatic)
114: return false;
115:
116: if (SEPARATE_STAGES) {
117: SinkIF thesink;
118: synchronized (stageCache) {
119: thesink = (SinkIF) stageCache.get(url);
120: if (thesink == null)
121: thesink = makeStage(url);
122: }
123: thesink.enqueue(req);
124: } else {
125: mainsink.enqueue(req);
126: }
127: return true;
128: }
129:
130: public void handleEvent(QueueElementIF item) {
131: if (DEBUG) {
132: if (myurl == null)
133: System.err.println("DynamicHttp: GOT QEL: " + item);
134: else
135: System.err.println("DynamicHttp [" + myurl
136: + "]: GOT QEL: " + item);
137: }
138:
139: if (item instanceof httpRequest) {
140: httpRequest req = (httpRequest) item;
141: try {
142: doRequest(req);
143: } catch (Exception e) {
144: com.rimfaxe.webserver.ErrorLog.log("DynamicHttp", 170,
145: "Internal error", "" + req + "\n" + e);
146:
147: HttpSend
148: .sendResponse(new httpResponder(
149: new httpInternalServerErrorResponse(
150: req, e,
151: "DynamicHttp.handleEvent()"),
152: req, true));
153: }
154:
155: } else {
156: System.err
157: .println("DynamicHttp: Don't know what to do with "
158: + item);
159: }
160: }
161:
162: public void handleEvents(QueueElementIF items[]) {
163: for (int i = 0; i < items.length; i++) {
164: handleEvent(items[i]);
165: }
166: }
167:
168: private void doRequest(httpRequest req) {
169: String url;
170: String classname;
171:
172: url = req.getURL();
173:
174: classname = "com.rimfaxe.webserver.seda.SedaHandler";
175:
176: StringBuffer error_log = new StringBuffer();
177:
178: try {
179:
180: handlerPool pool;
181:
182: synchronized (this ) {
183:
184: pool = (handlerPool) handlerCache.get(classname);
185: if (pool == null) {
186:
187: try {
188:
189: pool = new handlerPool(classname);
190: if (DEBUG) {
191: System.err
192: .println("DynamicHttp: Loaded class "
193: + classname
194: + " for url "
195: + url);
196: }
197: } catch (ClassNotFoundException cnfe) {
198: com.rimfaxe.webserver.ErrorLog.log(
199: "DynamicHttp", 226, "Internal error",
200: "" + req + "\n" + cnfe);
201:
202: HttpSend
203: .sendResponse(new httpResponder(
204: new httpInternalServerErrorResponse(
205: req, cnfe,
206: "DynamicHttp.doRequest() - pool class"),
207: req, true));
208: return;
209: }
210:
211: handlerCache.put(classname, pool);
212: }
213: }
214:
215: httpRequestHandlerIF handler = pool.getHandler();
216:
217: httpResponse resp;
218:
219: resp = handler.handleRequest(req, error_log);
220: //resp = handler.handleRequest(req);
221:
222: resp.setServerPort(req.getServerPort());
223:
224: boolean shouldClose = CLOSE_CONNECTION;
225: if (req.getHttpVer() != req.HTTPVER_11)
226: shouldClose = true;
227:
228: httpResponder respd = new httpResponder(resp, req,
229: shouldClose);
230: HttpSend.sendResponse(respd);
231: pool.doneWithHandler(handler);
232:
233: //System.out.println("DynamicHttp : "+error_log+"\n"+req+"\n");
234:
235: } catch (Exception e) {
236: com.rimfaxe.webserver.ErrorLog.log("DynamicHttp", 170,
237: "Internal error", "" + req + "\n" + e + "\n"
238: + error_log + "\n");
239:
240: HttpSend.sendResponse(new httpResponder(
241: new httpInternalServerErrorResponse(req, e,
242: "DynamicHttp.doRequest()"), req, true));
243: return;
244: }
245: }
246:
247: class handlerPool {
248: Class theclass;
249: Vector pool;
250:
251: handlerPool(String classname) throws ClassNotFoundException {
252: this .theclass = Class.forName(classname);
253: this .pool = new Vector();
254: }
255:
256: httpRequestHandlerIF getHandler()
257: throws InstantiationException, IllegalAccessException {
258: httpRequestHandlerIF handler;
259: synchronized (pool) {
260: if (pool.size() == 0) {
261: handler = (httpRequestHandlerIF) theclass
262: .newInstance();
263: } else {
264: handler = (httpRequestHandlerIF) pool.remove(pool
265: .size() - 1);
266: }
267: }
268: return handler;
269: }
270:
271: void doneWithHandler(httpRequestHandlerIF handler) {
272: synchronized (pool) {
273: pool.addElement(handler);
274: }
275: }
276: }
277:
278: private static SinkIF makeStage(String url) throws Exception {
279: StageIF thestage;
280: thestage = config.getManager()
281: .createStage("DynamicHttp [" + url + "]",
282: new DynamicHttp(url), null);
283: stageCache.put(url, thestage.getSink());
284: return thestage.getSink();
285: }
286:
287: }
|