KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > barracuda > core > event > ApplicationGateway


1 /*
2  * Copyright (C) 2003 Christian Cryder [christianc@granitepeaks.com]
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * $Id: ApplicationGateway.java,v 1.51 2004/02/01 05:16:27 christianc Exp $
19  */

20 package org.enhydra.barracuda.core.event;
21
22 import java.io.*;
23 import java.lang.reflect.*;
24 import java.util.*;
25 import javax.servlet.*;
26 import javax.servlet.http.*;
27
28 import org.apache.log4j.*;
29
30 import org.enhydra.barracuda.core.comp.scripting.*;
31 import org.enhydra.barracuda.core.event.events.*;
32 import org.enhydra.barracuda.core.helper.servlet.*;
33 import org.enhydra.barracuda.core.view.*;
34 import org.enhydra.barracuda.plankton.*;
35 import org.enhydra.barracuda.plankton.data.*;
36 import org.enhydra.barracuda.plankton.exceptions.*;
37 import org.enhydra.barracuda.plankton.http.URLRewriter;
38 import org.enhydra.barracuda.plankton.http.ServletUtil;
39
40 /**
41  * <p>The application gateway is responsible for a number of things.
42  *
43  * <ol>
44  * <li>It acts as a gateway servlet for all event handlers in this
45  * application.</li>
46  *
47  * <li>It defines and instantiates a number of entities needed to
48  * dispatch events (EventBroker, EventPool, DispatcherFactory, etc)</li>
49  *
50  * <li>It defines which event extension we are using</li>
51  *
52  * <li>It registers all EventGateways, and any local Event interests</li>
53  *
54  * <li>It performs the initial mapping of HTTPRequests to Events for this
55  * particular domain </li>
56  * </ol>
57  *
58  * <p>Consequently, if you want to use the Barracuda event model, this
59  * is the class that really kicks it all off. You must either extend this
60  * class OR use the DefaultApplicationAssembler in order to specify that
61  * this servlet handles all event requests for an application. This will
62  * allow the system to convert requests to events and dispatch them through
63  * the EventBroker to any listeners within EventGateways that have registered
64  * interest with the broker.
65  *
66  * <p>This class should be the first servlet loaded in your web.xml file.
67  *
68  * <p>For an example of how to do this, look at
69  * <strong>org.enhydra.barracuda.examples.ex1.SampleApplicationGateway</strong>
70  *
71  * <p>You might also want to look at the <a HREF="sm_barracuda_event.gif">UML Class
72  * diagram of the Event model classes.</a>
73  *
74  * @author Christian Cryder <christianc@granitepeaks.com>
75  * @author Diez Roggisch <diez.roggisch@artnology.com>
76  * @author Jacob Kjome <hoju@visi.com>
77  * @version %I%, %G%
78  * @since 1.0
79  */

80 public class ApplicationGateway extends HttpServlet implements EventGateway {
81
82     private static final Class JavaDoc CLASS = ApplicationGateway.class;
83     private static final Logger logger = Logger.getLogger(CLASS);
84     private static final Logger orLogger = Logger.getLogger(CLASS.getName()+"_ORStackTrace");
85
86     //public vars
87
//...configuration constants (set through ObjectRepositoryAssembler)
88
public static boolean USE_EVENT_POOLING = true; //use event pooling?
89
public static boolean RESPOND_WITH_404 = false; //respond with a 404 if the event being dispatched is invalid //csc_100603_1
90
public static RequestWrapper REQUEST_WRAPPER = null; //dbr_021602
91
public static ResponseWrapper RESPONSE_WRAPPER = null; //csc_010404_1
92
public static String JavaDoc LR_OVERRIDE_KEY = "$lr_override"; //(String) - if this key = true in the request, the LongRunning interface will be ignored (makes it easy to override LongRunning with certain URL configurations)
93
public static int LR_DEBUG = 0; //0=normal, 1=allow resize on frames, 2=turn off the check redirect frame (useful for debugging)
94

95     //...configuration constants (set through servlet init params)
96
private static final String JavaDoc APPLICATION_ASSEMBLER = "ApplicationAssembler";
97     private static final String JavaDoc ASSEMBLY_DESCRIPTOR = "AssemblyDescriptor";
98     private static final String JavaDoc SAX_PARSER = "SAXParser";
99
100     //...LocalObjectRepository constants (available for apps to access)
101
public static final String JavaDoc HTTP_SERVLET_REQUEST = CLASS+".HttpServletRequest"; //(HttpServletReques)
102
public static final String JavaDoc HTTP_SERVLET_RESPONSE = CLASS+".HttpServletResponse"; //(HttpServletResponse)
103
public static final String JavaDoc THREAD_POOL = CLASS+".ThreadPool"; //(ThreadPool)
104

105     //...EventContext constants (available for apps to access)
106
public static final String JavaDoc TARGET_EVENT_NAME = CLASS+".TargetEventName"; //(String)
107
public static final String JavaDoc EXTERNAL_CONTEXT_OBJ_NAME = CLASS+".ExternalContextObjName"; //(Object)
108

109
110     //req params
111
public static final String JavaDoc LONG_RUNNING_ID = "$lrid"; //(String)
112

113
114
115
116
117
118
119
120     //private vars
121
private EventBroker masterEventBroker = null;
122     private EventPool masterEventPool = null;
123     private static long uid = System.currentTimeMillis();
124     private static final String JavaDoc LONG_RUNNING_RESPONSE_INDICATOR = "$is_lr_resp"; //csc_010404_1
125
protected EventGateway eventGateway = (EventGateway) Classes.newInstance(A_Classes.DEFAULT_EVENT_GATEWAY); //csc_060903_3
126
protected List gateways = null;
127     protected boolean virgin = true; //true after init before any requests handled - added mostly because log4j stuff in init() method is all going to log, rather than console - csc
128

129
130
131     /**
132      * Public noargs constructor
133      */

134     public ApplicationGateway() {
135         logger.info("Instantiating "+this);
136     }
137
138
139     //--------------- User Configurable Methods ------------------
140
/**
141      * <p>Perform any local initialization (this is where you should
142      * add any other known EventGateways)
143      */

144     public void initializeLocal() {
145     }
146
147     /**
148      * <p>Perform any local initialization (this is where you should
149      * add any other known EventGateways)
150      *
151      * @param iconfig the ServletConfig object used to configure this servlet
152      * @deprecated If your code is still attempting to extend this old method
153      * signature, you need to change it to use initializeLocal() instead.
154      * If you still need to get a reference to the servlet config, just
155      * call 'this.getServletConfig()'. This method is now final so that
156      * code which might still be using it will no longer compile.
157      */

158     public final void initializeLocal(ServletConfig iconfig) throws ServletException {
159     }
160
161     /**
162      * <p>Perform any local cleanup (this is where you should
163      * remove any known EventGateways)
164      */

165     public void destroyLocal() {
166     }
167
168     /**
169      * <p>Provide an instance of the specific EventBroker we want to use.
170      * Override this method if you'd like to use something other than
171      * the DefaultEventBroker.
172      *
173      * @return a new instance of the EventBroker
174      */

175     public EventBroker getNewEventBrokerInstance() {
176         if (logger.isDebugEnabled()) logger.debug("instantiating DefaultEventBroker");
177         return new DefaultEventBroker(getDispatcherFactory(), getEventExtension());
178     }
179
180     /**
181      * <p>Provide an instance of the specific EventPool we want to use.
182      * Override this method if you'd like to use something other than
183      * the DefaultEventPool.
184      *
185      * @return a new instance of the EventPool.
186      */

187 //csc_060903_1_start
188
/*
189     public EventPool getNewEventPoolInstance() {
190         if (logger.isDebugEnabled()) logger.debug("instantiating DefaultEventPool");
191         return new DefaultEventPool();
192     }
193 */

194 //csc_060903_1_end
195

196     /**
197      * <p>Provide an instance of the specific DispatchQueue we want to use.
198      * Override this method if you'd like to use something other than
199      * the DefaultDispatchQueue.
200      *
201      * @return a new instance of the DispatchQueue.
202      */

203     public DispatchQueue getNewDispatchQueueInstance() {
204         if (logger.isDebugEnabled()) logger.debug("instantiating DefaultDispatchQueue");
205         return new DefaultDispatchQueue(true);
206     }
207
208     /**
209      * <p>Provide an instance of the specific EventDispatcher we want to use.
210      * Override this method if you'd like to use something other than
211      * DefaultEventBroker.
212      *
213      * @return a new instance of the DispatcherFactory
214      */

215     public DispatcherFactory getDispatcherFactory() {
216         if (logger.isDebugEnabled()) logger.debug("instantiating DefaultDispatcherFactory");
217         return new DefaultDispatcherFactory();
218     }
219
220     /**
221      * <p>Indicate which event extension we are handling. By default the gateway
222      * handles extensions of <strong>.event</strong>. If you wish to handle
223      * a different function you should override this method to return the
224      * value defined in the web.xml file.
225      *
226      * @return a string defining the event extension handled by this servlet
227      */

228     public String JavaDoc getEventExtension() {
229         return ".event";
230     }
231
232     /**
233      * <p>Handle the default HttpRequest. It will probably be rare for
234      * developers to override this.
235      *
236      * <p>Basically, this method receives a request and attempts to map it
237      * to a valid HttpRequestEvent. If the event is invalid, or if the
238      * event is NOT an instance of HttpRequestEvent, then we simply create
239      * a new instance of HttpRequestEvent and dispatch that instead. This
240      * is a very important feature, because it allows us to define events
241      * which are not accessible to the outside world -- the gateway will
242      * only dispatch HttpRequest events, so you define your publically
243      * accessible API by creating an event hierarchy that extends from
244      * the HttpRequestEvent object.
245      *
246      * <p>Once we have a valid event, we dispatch it. In this case (because this
247      * is an Http gateway) we must have a response, so if we catch an
248      * UnhandledEventException, we will generate a default error message and
249      * return.
250      *
251      * @param req the servlet request
252      * @param resp the servlet response
253      * @throws ServletException
254      * @throws IOException
255      */

256     public void handleDefault(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
257         handleDefaultExt(req, resp, null);
258     }
259
260     /**
261      * <p>Handle the default HttpRequest with the ability to add the provided
262      * object into the context. It will probably be rare for
263      * developers to override this.
264      *
265      * <p>Basically, this method receives a request and attempts to map it
266      * to a valid HttpRequestEvent. If the event is invalid, or if the
267      * event is NOT an instance of HttpRequestEvent, then we simply create
268      * a new instance of HttpRequestEvent and dispatch that instead. This
269      * is a very important feature, because it allows us to define events
270      * which are not accessible to the outside world -- the gateway will
271      * only dispatch HttpRequest events, so you define your publically
272      * accessible API by creating an event hierarchy that extends from
273      * the HttpRequestEvent object.
274      *
275      * <p>Once we have a valid event, we dispatch it. In this case (because this
276      * is an Http gateway) we must have a response, so if we catch an
277      * UnhandledEventException, we will generate a default error message and
278      * return.
279      *
280      * @param req the servlet request
281      * @param resp the servlet response
282      * @param externalContextObj object to put into the context
283      * @throws ServletException
284      * @throws IOException
285      */

286     public void handleDefaultExt(HttpServletRequest req, HttpServletResponse resp, Object JavaDoc externalContextObj) throws ServletException, IOException {
287         String JavaDoc ourl = req.getRequestURL().toString();
288         String JavaDoc oqstr = req.getQueryString();
289         long bmillis = 0;
290         long smillis = 0;
291         long emillis = 0;
292         if (virgin) {
293             if (logger.isInfoEnabled()) {
294                 logger.info("\n\n\n\n\n\n"+
295                             "=======================================\n"+
296                             "ApplicationGateway servlet was reloaded\n"+
297                             "=======================================");
298             }
299             virgin = false;
300         }
301         if (logger.isInfoEnabled()) bmillis = System.currentTimeMillis();
302         if (logger.isInfoEnabled()) {
303             logger.info("\n\n\n"+
304                         "--------------------------------------------------------------------------\n"+
305                         "Handling incoming HTTP request: "+ourl+(oqstr!=null ? "?"+oqstr : "")+"\n"+
306                         "--------------------------------------------------------------------------");
307         }
308         BaseEvent event = null;
309
310
311         //start by getting the event broker and pool. We get local copies so
312
//that if these constant vaules change while we're mid-method, it's not a problem
313
EventBroker eventBroker = getEventBroker();
314         EventPool eventPool = getEventPool();
315         ViewCapabilities vc = new ViewCapabilities(req, resp);
316         DefaultEventContext context = null;
317         HttpServletResponse oresp = null;
318         DeferredResponseWrapper dresp = null;
319 //System.out.println("incoming url:"+ourl);
320
//System.out.println("query string:"+oqstr);
321
String JavaDoc uri = req.getRequestURI();
322         String JavaDoc lrid = req.getParameter(LONG_RUNNING_ID);
323         boolean lrOverride = ("true".equalsIgnoreCase(req.getParameter(LR_OVERRIDE_KEY)));
324         boolean useEventPool = USE_EVENT_POOLING;
325         boolean eventCameFromPool = false;
326         boolean allowEventAliasing = true; //just do it always
327
String JavaDoc target = null;
328
329         try {
330             //set up the Session ObjectRepository
331
ObjectRepository.setupSessionRepository(req); //csc_022101.1
332

333
334
335
336             //csc_010404_1_start
337
//before we do anything else, see if we are dealing with a long running response
338
if (lrid!=null && !lrOverride) {
339                 //now since we have a lrid, there should be an object in the session...
340
ObjectRepository session = ObjectRepository.getSessionRepository();
341                 ObjectRepository softSession = ObjectRepository.getSoftSessionRepository();
342                 dresp = (DeferredResponseWrapper) session.getState(lrid);
343
344
345                 //...if there's not, just clear the lrid value and proceed.
346
if (dresp==null) {
347                     if (logger.isInfoEnabled()) logger.info("DeferredResponseWrapper missing from session - continuing as if $lrid=null (pass ??)");
348                     ((BarracudaServletRequestWrapper) req).removeParameter(LONG_RUNNING_ID);
349                     String JavaDoc lridstr = LONG_RUNNING_ID+"="+lrid;
350                     oqstr = StringUtil.replace(oqstr, lridstr, "");
351                     oqstr = StringUtil.replace(oqstr, "?"+lridstr, "");
352                     lrid = null;
353
354                     //now, check to see if there are any params for this url in the soft session; if so,
355
//we can assume they did a CTRL-R on the page (that's why we're in this particular block) -
356
//in this case, restore the params from the last POST request
357
BarracudaServletRequestWrapper breq = (BarracudaServletRequestWrapper) req;
358                     Map pmap = (Map) softSession.getState(ourl);
359                     if (pmap!=null) {
360                         if (logger.isInfoEnabled()) logger.info("Restoring params from previous POST");
361                         Iterator it = pmap.entrySet().iterator();
362                         while (it.hasNext()) {
363                             Map.Entry me = (Map.Entry) it.next();
364                             String JavaDoc key = (String JavaDoc) me.getKey();
365                             if (key.equals(LONG_RUNNING_ID)) continue;
366                             String JavaDoc[] vals = (String JavaDoc[]) me.getValue();
367                             for (int i=0; i<vals.length; i++) {
368                                 String JavaDoc val = vals[i];
369                                 String JavaDoc oval = breq.getParameter(key);
370                                 if (val==oval || (val!=null && val.equals(oval))) continue; //in certain situations, the url may actually have parameters embedded into it; those should not be reconstituted from the session since they are already there
371
breq.addParameter(key, val);
372                             }
373                         }
374                         breq.setMethod("POST");
375                     }
376
377                 //...if there is, but the response has already been generated, just show it
378
} else if (dresp.isCommitted()) {
379                     try {
380                         //first see if there is any error; if so - resend it
381
Integer JavaDoc error = (Integer JavaDoc) session.getState(lrid+"_error");
382                         if (error!=null) {
383                             resp.sendError(error.intValue());
384                             return;
385                         }
386
387                         //next check and see if we encountered an exception; if so, re-throw it
388
Exception JavaDoc dexcp = (Exception JavaDoc) session.getState(lrid+"_exception");
389                         if (dexcp!=null) {
390                             if (logger.isInfoEnabled()) logger.info("Throwing a deferred EventException (pass 3)");
391                             if (dexcp instanceof EventException) throw (EventException) dexcp;
392                             else if (dexcp instanceof ServletException) throw (ServletException) dexcp;
393                             else if (dexcp instanceof IOException) throw (IOException) dexcp;
394                             else if (dexcp instanceof RuntimeException JavaDoc) throw (RuntimeException JavaDoc) dexcp;
395                             else {
396                                 logger.warn("found unexpected exception in session:"+dexcp);
397                             }
398                         }
399
400                         //otherwise, render
401
if (logger.isInfoEnabled()) logger.info("Actually rendering completed response from DeferredResponseWrapper (pass 3)");
402                         dresp.actuallySendResponse(resp);
403                         return;
404                     } finally {
405                         session.removeState(lrid+"*");
406                         dresp = null;
407                     }
408
409                 //...otherwise, lets set everything up to execute the long running task
410
} else {
411                     if (logger.isInfoEnabled()) logger.info("Writing response to DeferredResponseWrapper in session (pass 2)");
412
413                     //save a reference to our orig response; we'll use the deferred response to actually save the results
414
oresp = resp;
415                     resp = dresp;
416                     dresp.setUnderlyingResponse(oresp);
417
418                     //we also want to reconstitute params from the session (this ensures that
419
//all the params from the orig request are available this second time around)
420
BarracudaServletRequestWrapper breq = (BarracudaServletRequestWrapper) req;
421                     Map pmap = (Map) session.getState(lrid+"_params");
422                     Iterator it = pmap.entrySet().iterator();
423                     while (it.hasNext()) {
424                         Map.Entry me = (Map.Entry) it.next();
425                         String JavaDoc key = (String JavaDoc) me.getKey();
426                         String JavaDoc[] vals = (String JavaDoc[]) me.getValue();
427                         for (int i=0; i<vals.length; i++) {
428                             String JavaDoc val = vals[i];
429                             String JavaDoc oval = breq.getParameter(key);
430                             if (val==oval || (val!=null && val.equals(oval))) continue; //in certain situations, the url may actually have parameters embedded into it; those should not be reconstituted from the session since they are already there
431
breq.addParameter(key, val);
432                         }
433                     }
434                     session.removeState(lrid+"_params");
435
436                     //now, if the original method was post, save the params in the soft session (so in case they hit CTRL-R
437
//later, we at least have a chance of resubmitting properly)
438
if ("POST".equalsIgnoreCase((String JavaDoc) session.getState(lrid+"_orig_method"))) {
439                         softSession.putState(ourl, req.getParameterMap());
440                     } else {
441                         softSession.removeState(ourl);
442                     }
443                 }
444             }
445             //csc_010404_1_end
446

447
448
449
450
451
452             //store the req/resp objects in the local repository
453
ObjectRepository lor = ObjectRepository.getLocalRepository(); //csc_010404_1
454
lor.putState(HTTP_SERVLET_REQUEST, req); //csc_010404_1
455
lor.putState(HTTP_SERVLET_RESPONSE, resp); //csc_010404_1
456

457             //figure out the name of the event handler being requested
458
target = req.getServletPath();
459             if (logger.isDebugEnabled()) {
460                 logger.debug("Incoming URI:"+req.getRequestURI());
461                 logger.debug("ServletPath:"+target);
462 // logger.debug("HTTP Headers..."); //csc_052803.1
463
ServletUtil.showHeader(req, logger); //csc_052803.1
464
}
465             if (logger.isInfoEnabled()) ServletUtil.showParams(req, logger); //csc_010404_1
466

467             // cater for Enhydra's different behaviour if in a PO
468
if (null==target || target.length()==0) {
469                 target = req.getRequestURI();
470                 if (logger.isDebugEnabled()) logger.debug("Setting target to request URI: " + target);
471             }
472
473             //..trim any path info (based on '/')
474
if (target!=null) {
475                 int spos = target.lastIndexOf("/");
476                 if (spos>-1) target = target.substring(spos+1);
477             }
478             //..trim any path info (based on '\')
479
if (target!=null) {
480                 int spos = target.lastIndexOf("\\");
481                 if (spos>-1) target = target.substring(spos+1);
482             }
483
484             //now get the actual name of the event
485
String JavaDoc ext = eventBroker.getEventExtension();
486             String JavaDoc eventName = target;
487             if (eventName.endsWith(ext)) {
488                 eventName = target.substring(0, target.length()-ext.length());
489                 if (logger.isDebugEnabled()) logger.debug("Target Event:"+eventName);
490             }
491
492             //now get the actual event name
493
if (allowEventAliasing) try {
494                 String JavaDoc fullEventName = eventBroker.matchEventClass(eventName);
495                 if (fullEventName!=null) {
496                     eventName = fullEventName;
497                     if (logger.isDebugEnabled()) logger.debug("Fully qualified Event:"+eventName);
498                 }
499             } catch (InvalidClassException e) {}
500
501             //now instantiate an Event (here's where it would make sense to
502
//use an Event pool)
503
if (logger.isDebugEnabled()) logger.debug("Creating Event");
504             try {
505                 //get the class name for the event
506
//csc_060903_3 Class cl = Thread.currentThread().getContextClassLoader().loadClass(eventName);
507
Class JavaDoc cl = Classes.getClass(eventName); //csc_060903_3
508

509                 //get it from the pool if appropriate
510
if (useEventPool) try {
511                     if (logger.isDebugEnabled()) logger.debug("Checking out event from event pool");
512                     event = eventPool.checkoutEvent(cl);
513                     eventCameFromPool = true;
514                 } catch (NoAvailableEventsException e) {
515                     if (logger.isDebugEnabled()) logger.debug("No available events in pool");
516                 }
517
518                 //if that didn't work (or we're not getting it from the
519
//pool in the first place) create it manually
520
if (event==null) {
521                     if (logger.isDebugEnabled()) logger.debug("Creating a new event from scratch");
522                     event = (BaseEvent) cl.newInstance(); //this requires that events being dispatched have a noargs constructor
523
}
524
525             } catch (Exception JavaDoc e) {
526                 //if we can't map the request to an event, we will just
527
//dispatch a generic HttpRequestEvent
528
//csc_100603_1_start
529
// logger.error("Class "+eventName+" not found...Creating a generic HttpRequestEvent");
530
// event = new HttpRequestEvent();
531
if (RESPOND_WITH_404) {
532
533 //csc_010404_1_start
534
// logger.warn("Class "+eventName+" not found...Responding with 404 error");
535
// resp.sendError(HttpServletResponse.SC_NOT_FOUND);
536
if (oresp!=null && dresp!=null) {
537                         ObjectRepository session = ObjectRepository.getSessionRepository();
538                         session.putState(lrid+"_error", new Integer JavaDoc(HttpServletResponse.SC_NOT_FOUND));
539                     } else {
540                         logger.warn("Class "+eventName+" not found...Responding with 404 error");
541                         resp.sendError(HttpServletResponse.SC_NOT_FOUND);
542                     }
543                     return;
544 //csc_010404_1_end
545
} else {
546                     logger.error("Class "+eventName+" not found...Creating a generic HttpRequestEvent");
547                     event = new HttpRequestEvent();
548                 }
549 //csc_100603_1_end
550
}
551
552             //make sure the incoming event implements HttpRequestEvent...if not,
553
//consider it invalid (This is VERY important: it prevents people
554
//from hacking the system by directly invoking events that were
555
//not intended to be invoked directly from teh outside world)
556
if (!(event instanceof HttpRequestEvent)) event = new HttpRequestEvent();
557
558
559
560
561
562
563
564 //csc_010404_1_start
565
//if we encounter a LongRunning event...
566
if (event instanceof LongRunning && !lrOverride) {
567
568                 //if we're dealing with a LongRunning event, make sure the response object implements
569
//BarracudaServletResponseWrapper (else there's no point continuing)
570
if (!(req instanceof BarracudaServletRequestWrapper)) throw new EventException("LongRunning support not enabled - you must use a req wrapper that implements BarracudaServletRequestWrapper");
571                 if (!(resp instanceof BarracudaServletResponseWrapper)) throw new EventException("LongRunning support not enabled - you must use a resp wrapper that implements BarracudaServletResponseWrapper");
572
573                 //if its NOT already running as a long running response (ie. the URL does not include the
574
//$lrid=xxxxx param yet), then we are on the first pass: redirect accordingly
575
if (lrid==null) {
576                     if (logger.isInfoEnabled()) logger.info("Redirecting for CheckLongRunningEvent (pass 1)");
577
578                     //create a new deferred response and place it in the session. We also want
579
//to save a copy of the params so we can reconstitute those on subsquent requests
580
ObjectRepository session = ObjectRepository.getSessionRepository();
581                     lrid = getUID();
582                     session.putState(lrid, new DeferredResponseWrapper());
583                     session.putState(lrid+"_params", new HashMap(req.getParameterMap()));
584                     session.putState(lrid+"_orig_url", ourl+(oqstr!=null ? "?"+oqstr : ""));
585                     session.putState(lrid+"_orig_method", req.getMethod());
586                     session.putState(lrid+"_event", event);
587
588                     //now build the check status url
589
ClientSideRedirectException rdException = new ClientSideRedirectException(new CheckLongRunningEvent());
590                     String JavaDoc rdURL = URLRewriter.encodeRedirectURL(req, resp, rdException.getRedirectURL()+"?"+LongRunningEventGateway.LRG_ID+"="+lrid);
591                     rdURL = ScriptDetector.prepareRedirectURL(rdURL, vc);
592                     if (logger.isInfoEnabled()) logger.info("rdURL: "+rdURL);
593
594                     //now build the long running url
595
String JavaDoc lrURL = ourl+(oqstr!=null ? "?"+oqstr : "")+(oqstr!=null ? "&" : "?")+LONG_RUNNING_ID+"="+lrid;
596                     if (logger.isInfoEnabled()) logger.info("lrURL: "+lrURL);
597
598                     //send the redirect request
599
resp.setContentType("text/html");
600                     StringBuffer JavaDoc sb = new StringBuffer JavaDoc(500);
601                     sb.append("<html>");
602                     sb.append(" <head>");
603                     sb.append(" <title>Redirecting...</title>");
604                     sb.append(" </head>");
605                     sb.append(" <script language=\"javascript\">");
606                     sb.append(" var pageFullyLoaded = false;");
607                     sb.append(" function handleComplete() {");
608                     sb.append(" if (!pageFullyLoaded) {");
609                     sb.append(" window.top.location.replace('CancelLongRunningEvent.event?"+LongRunningEventGateway.LRG_ID+"="+lrid+"');");
610                     sb.append(" alert('In the future, please press the Cancel button to properly stop a long running process');");
611                     sb.append(" }");
612                     sb.append(" }");
613                     sb.append(" </script>");
614                     if (LR_DEBUG==1) { //allow resize
615
sb.append(" <frameset rows=\"100%,200\">");
616                         sb.append(" <frame SRC=\""+rdURL+"\">");
617                         sb.append(" <frame SRC=\""+lrURL+"\">");
618                         sb.append(" </frameset>");
619                     } else if (LR_DEBUG==2) { //don't show the check frame
620
sb.append(" <frameset rows=\"100%,200\">");
621                         sb.append(" <frame SRC=\"foo.html\" >");
622                         sb.append(" <frame SRC=\""+lrURL+"\">");
623                         sb.append(" </frameset>");
624                     } else { //normal
625
sb.append(" <frameset rows=\"100%,1\" onload=\"handleComplete();\">");
626                         sb.append(" <frame SRC=\""+rdURL+"\" frameborder=\"0\" noresize>");
627                         sb.append(" <frame SRC=\""+lrURL+"\" frameborder=\"0\" noresize>");
628                         sb.append(" </frameset>");
629                     }
630                     sb.append(" </frameset>");
631                     sb.append("</html>");
632                     String JavaDoc content = sb.toString();
633                     Writer wr = resp.getWriter();
634                     wr.write(content);
635                     wr.close();
636                     resp.flushBuffer();
637
638                     //once we've done all this, simply return
639
return;
640
641                 //if we are actually running generating the long running response (pass 2),
642
//set the event in the resp object (it will be needed for progress updates)
643
} else {
644                     LongRunning lr = (LongRunning) event;
645                     lr.reset();
646                     dresp.setLongRunning(lr);
647                     dresp.setLongRunningThread(Thread.currentThread());
648                 }
649             }
650 //csc_010404_1_end
651

652
653
654
655
656
657
658             //now set any special paramters
659
event.setSource(this);
660             event.setHandled(false);
661
662             //now figure out if the event targets any specific listener IDs, and
663
//if so add these ids to the event. This info will be used by the
664
//dispatcher to send the event to the specified listeners, rather
665
//doing a general dispatch to all parties interested in this class of
666
//event.
667
String JavaDoc[] ids = req.getParameterValues(BaseEvent.EVENT_ID);
668             if (logger.isDebugEnabled()) logger.debug("Looking for event listener ids:"+ids);
669             if (ids!=null) {
670                 for (int i=0, max=ids.length; i<max; i++) {
671                     String JavaDoc id = ids[i];
672                     if (logger.isDebugEnabled()) logger.debug("Target EventID:"+id);
673                     if (allowEventAliasing) try {
674                         id = eventBroker.matchListenerID(ids[i]);
675                         if (logger.isDebugEnabled()) logger.debug("Fully qualified EventID:"+id);
676                     } catch (InvalidClassException e) {}
677                     event.addListenerID(id);
678                 }
679             }
680
681             //finally, dispatch it to the EventBroker
682
if (logger.isDebugEnabled()) logger.debug("Dispatching event:"+event+" to broker:"+eventBroker);
683             DispatchQueue eventQueue = getNewDispatchQueueInstance();
684             HttpResponseEvent defaultResponseEvent = new HttpResponseEvent();
685             defaultResponseEvent.setSource(event);
686             eventQueue.addEvent(event);
687             context = new DefaultEventContext(eventQueue, vc, this.getServletConfig(), req, resp, defaultResponseEvent);
688             context.putState(TARGET_EVENT_NAME, eventName);
689             if (null!=externalContextObj) {
690                 context.putState(EXTERNAL_CONTEXT_OBJ_NAME, externalContextObj);
691             }
692             if (logger.isInfoEnabled()) smillis = System.currentTimeMillis();
693             eventBroker.dispatchEvent(context);
694             if (logger.isInfoEnabled()) emillis = System.currentTimeMillis();
695             if (logger.isInfoEnabled()) logger.info("Dispatching complete! (handled in "+(emillis-smillis)+" of "+(emillis-bmillis)+" millis)");
696
697
698         } catch (ClientSideRedirectException re) {
699             //save current context to session
700
if (context!=null) {
701                 if (logger.isDebugEnabled()) logger.debug("Saving context");
702                 context.persistContext(re);
703             }
704
705             //if we get a redirect exception, request the browser to redirect accordingly
706
String JavaDoc url = URLRewriter.encodeRedirectURL(req, resp, re.getRedirectURL());
707             url = ScriptDetector.prepareRedirectURL(url, vc); //csc_102501.2
708
if (logger.isInfoEnabled()) logger.info("ClientSideRedirectException...redirecting to "+url);
709             resp.sendRedirect(url);
710
711         } catch (EventException e) {
712             //csc_010404_1_start
713
//if we are dealing with a deferred response, and its been interrupted, just return
714
if (logger.isInfoEnabled()) logger.debug("got EventException: "+e);
715             if (oresp!=null && dresp!=null) {
716                  if (dresp.isInterrupted()) return;
717                  ObjectRepository session = ObjectRepository.getSessionRepository();
718                  session.putState(lrid+"_exception"</