KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > services > applications > JahiaApplicationsDispatchingServletService


1 /*
2  * ____.
3  * __/\ ______| |__/\. _______
4  * __ .____| | \ | +----+ \
5  * _______| /--| | | - \ _ | : - \_________
6  * \\______: :---| : : | : | \________>
7  * |__\---\_____________:______: :____|____:_____\
8  * /_____|
9  *
10  * . . . i n j a h i a w e t r u s t . . .
11  *
12  *
13  *
14  * ----- BEGIN LICENSE BLOCK -----
15  * Version: JCSL 1.0
16  *
17  * The contents of this file are subject to the Jahia Community Source License
18  * 1.0 or later (the "License"); you may not use this file except in
19  * compliance with the License. You may obtain a copy of the License at
20  * http://www.jahia.org/license
21  *
22  * Software distributed under the License is distributed on an "AS IS" basis,
23  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
24  * for the rights, obligations and limitations governing use of the contents
25  * of the file. The Original and Upgraded Code is the Jahia CMS and Portal
26  * Server. The developer of the Original and Upgraded Code is JAHIA Ltd. JAHIA
27  * Ltd. owns the copyrights in the portions it created. All Rights Reserved.
28  *
29  * The Shared Modifications are Jahia View Helper.
30  *
31  * The Developer of the Shared Modifications is Jahia Solution S�rl.
32  * Portions created by the Initial Developer are Copyright (C) 2002 by the
33  * Initial Developer. All Rights Reserved.
34  *
35  * Contributor(s):
36  * 20-AUG-2003, Jahia Solutions Sarl, Fulco Houkes
37  *
38  * ----- END LICENSE BLOCK -----
39  */

40
41 package org.jahia.services.applications;
42
43 import org.apache.log4j.Logger;
44 import org.jahia.data.applications.ApplicationBean;
45 import org.jahia.data.applications.ApplicationContext;
46 import org.jahia.data.applications.ServletBean;
47 import org.jahia.exceptions.JahiaException;
48 import org.jahia.exceptions.JahiaInitializationException;
49 import org.jahia.exceptions.JahiaSessionExpirationException;
50 import org.jahia.params.ParamBean;
51 import org.jahia.registries.ServicesRegistry;
52 import org.jahia.services.cache.Cache;
53 import org.jahia.services.cache.CacheFactory;
54 import org.jahia.settings.SettingsBean;
55
56 import javax.servlet.RequestDispatcher JavaDoc;
57 import javax.servlet.ServletContext JavaDoc;
58 import javax.servlet.ServletException JavaDoc;
59 import javax.servlet.http.HttpServletRequest JavaDoc;
60 import javax.servlet.http.HttpSession JavaDoc;
61 import java.io.IOException JavaDoc;
62 import java.util.ArrayList JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.Set JavaDoc;
65 import java.util.Iterator JavaDoc;
66 import java.util.HashSet JavaDoc;
67 import org.jahia.bin.JahiaErrorDisplay;
68
69 /**
70  * This service handles dispatching requests to sub-applications, that is to say servlets or JSP
71  * under the same context or another one. The context, destination application and arguments are
72  * retrieved from Jahia's application database.
73  * Note:
74  * One of the reasons that we are requesting the output of servlets and JSPs as String is to enable
75  * further output processing before sending out to the browser. There might be a more efficient way
76  * to do this by implemented variable PrintWriters, but this is simple enough and works well. If
77  * we hit performance walls on this we might want to look at this second approach. It is notably
78  * used by the Engine's to generate forms whose content in generated at a handling time and then
79  * re-forwarded for final output rendering. (see the Fetcher Service for an example of this use).
80  *
81  * @author Serge Huber.
82  * @todo : Currently dispatching to a JSP is no longer possible because on Tomcat's implementation
83  * there seems to be a problems using a getNamedDispatcher on a <jsp-file> declaration.
84  * Will have to double check this for the next version of Jahia.
85  * @todo : test session awareness caches
86  */

87 public class JahiaApplicationsDispatchingServletService extends
88         JahiaApplicationsDispatchingService {
89
90     private static Logger logger = Logger.getLogger (JahiaApplicationsDispatchingServletService.class);
91
92     /** the service unique instance */
93     private static JahiaApplicationsDispatchingServletService instance;
94     private static final String JavaDoc APP_ID_SEPARATOR = "_";
95     private static final String JavaDoc CACHE_ID_SEPARATOR = ":";
96
97     // the Portlet Output cache name.
98
public static final String JavaDoc PORTLET_OUTPUT_CACHE = "PortletsOutputCache";
99     // the Portlet Request cache name.
100
public static final String JavaDoc PORTLET_REQUEST_CACHE = "PortletsRequestCache";
101     /** the output cache */
102     private Cache outputCache = null;
103
104     /** the request cache */
105     private Cache requestCache = null;
106
107     private boolean cacheOutputBoolean;
108     private boolean inheritJahiaSessionAttributes = false;
109
110     /**
111      * The constructor is protected because of singleton pattern
112      */

113     protected JahiaApplicationsDispatchingServletService () {
114         logger.debug ("***** Starting Service *****");
115         cacheOutputBoolean = true;
116     }
117
118     /**
119      * @return Retrieves the instance of the servlet service singleton
120      */

121     public static synchronized JahiaApplicationsDispatchingServletService
122             getInstance () {
123
124         if (instance == null) {
125             instance = new JahiaApplicationsDispatchingServletService ();
126         }
127         return instance;
128     }
129
130     /**
131      * Initializes the servlet dispatching service with parameters loaded
132      * from the Jahia configuration file.
133      *
134      * @param jSettings private settings object that contains Jahia configuration
135      * parameters
136      *
137      * @throws JahiaInitializationException shouldn't be thrown, only to be
138      * compliant with the interface.
139      */

140     public void init (SettingsBean jSettings)
141             throws JahiaInitializationException {
142         inheritJahiaSessionAttributes = jSettings.
143                 isAppInheritingJahiaSessionAttributes ();
144
145         outputCache = CacheFactory.createCache (PORTLET_OUTPUT_CACHE);
146         requestCache = CacheFactory.createCache (PORTLET_REQUEST_CACHE);
147     }
148
149     /**
150      * Actually does the dispatching to the web application, along with all the
151      * request and response wrapping process.
152      *
153      * @param jParams Jahia's parameters object passed mostly because it contains
154      * the request and response objects
155      * @param appBean This object contains Jahia's persistant definition
156      * of the application and is used for emulation generation as well as request
157      * cache generation.
158      * @param appUniqueIDStr This string contains a concatenation of the appID
159      * that comes from the application definition in Jahia's persistant storage
160      * with the fieldID to make sure the resulting ID is unique for the page
161      * (to properly handle the case of having twice the same application on the
162      * same page). It is used mostly for the response.encodeURL behaviour to handle
163      * the routing of requests.
164      * @param appURL String containg the request URL to use for the emulation of
165      * the request object
166      * @param appMethod String containing the method type to emulate (POST, GET,
167      * PUT, ...)
168      * @param cacheOutput Specifies whether the application output cache table
169      * should be updated with the result of this dispatch.
170      *
171      * @return A string containing the output of the servlet that we are
172      * dispatching to.
173      */

174     protected String JavaDoc dispatchRequest (ParamBean jParams,
175                                       ApplicationBean appBean,
176                                       ServletBean servletBean,
177                                       String JavaDoc appUniqueIDStr,
178                                       String JavaDoc appURL,
179                                       String JavaDoc appMethod,
180                                       String JavaDoc contextID,
181                                       boolean cacheOutput,
182                                       boolean fullScreenActivated
183                                       )
184             throws JahiaException,
185             JahiaSessionExpirationException {
186         PersistantServletRequest appRequest;
187         ServletIncludeRequestWrapper requestWrapper = null;
188         ServletIncludeResponseWrapper responseWrapper = null;
189
190         boolean mustCache = cacheOutput;
191         long cacheExpirationDelay = -1; // by default we never expire
192

193         logger.debug ("Dispatching by using request : " +
194                 "appMethod=" + appMethod +
195                 ", appURL=" + appURL);
196
197         try {
198
199             // Setting attributes in request should the application want to access some of Jahia's data
200
jParams.getRequest ().setAttribute ("org.jahia.params", jParams);
201
202             // First let's get the context in which to dispatch our request
203
logger.debug ("Trying get dispatcher to context=[" +
204                     servletBean.getContext () + "] appName=[" +
205                     servletBean.getServletName () + "]");
206
207             ServletContext JavaDoc dispatchedContext = jParams.getContext ().getContext (
208                     servletBean.getContext ());
209
210             if (dispatchedContext == null) {
211                 logger.debug ("Error getting dispatch context [" +
212                         servletBean.getContext () + "]");
213                 logger.error ("Web application error",
214                         new JahiaException ("Can't access context " +
215                         servletBean.getContext (),
216                                 "Error getting request context " +
217                         servletBean.getContext () + " for app " +
218                         servletBean.getName (),
219                                 JahiaException.ERROR_SEVERITY,
220                                 JahiaException.APPLICATION_ERROR));
221                 return "Error accessing application " + appBean.getName () +
222                         " , dispatchedContext is null ";
223             }
224
225             // Now let's retrieve that context's dispatcher object.
226
RequestDispatcher JavaDoc requestDispatcher = null;
227             boolean dispatcherObtainedByGetNamedDispatcher = false;
228
229             logger.debug("WebApp. type is ["+servletBean.getWebAppType ()+"]");
230             if (servletBean.getWebAppType () == ServletBean.JSP_TYPE) {
231                 logger.debug("WebApp. type is ["+ServletBean.JSP+"]");
232                 // we are doing this because most serlvet containers do not support
233
// servlet names for JSP pages...
234
logger.debug("JSP path is ["+servletBean.getservletsrc()+"]");
235                 requestDispatcher = dispatchedContext.getRequestDispatcher (
236                         servletBean.getservletsrc ());
237             } else if (servletBean.getWebAppType () == ServletBean.SERVLET_TYPE) {
238                 logger.debug("WebApp. type is ["+ServletBean.SERVLET+"]");
239                 // Retrieving a named dispatcher is done to avoid generation of
240
// include attribute which confuse JSP inclusion later on...
241
logger.debug("WebApp name is ["+servletBean.getServletName()+"]");
242                 requestDispatcher = dispatchedContext.getNamedDispatcher (
243                         servletBean.getServletName ());
244                 logger.debug ("Retrieved NamedDispatcher for servlet name " +
245                         servletBean.getServletName ());
246                 dispatcherObtainedByGetNamedDispatcher = true;
247             }
248             RequestDispatcherWrapper sessionDispatcher = new
249                     RequestDispatcherWrapper (requestDispatcher, dispatcherObtainedByGetNamedDispatcher);
250
251             if (sessionDispatcher == null) {
252                 logger.debug (
253                         "Error getting request dispatcher because sessionDispatcher is null");
254                 logger.error ("Error in web application",
255                         new JahiaException ("Can't access application " +
256                         appBean.getName (),
257                                 "Error getting request dispatcher for app " +
258                         appBean.getName (),
259                                 JahiaException.ERROR_SEVERITY,
260                                 JahiaException.APPLICATION_ERROR));
261                 return "Error accessing application " + appBean.getName () +
262                         " , sessionDispatcher is null ";
263             }
264
265             jParams.getResponse ().setContentType ("text/html");
266
267             if (appBean == null) {
268                 logger.debug ("Application bean object is null !!");
269             }
270
271             appRequest = new PersistantServletRequest (appBean,
272                     servletBean,
273                     appUniqueIDStr,
274                     appURL,
275                     appMethod,
276                     contextID
277             );
278
279             logger.debug ("appRequest URL :" + appRequest.getURL ());
280             HttpServletRequest JavaDoc request = jParams.getRealRequest();
281             requestWrapper = new ServletIncludeRequestWrapper (request,
282                     appRequest.getURL (),
283                     appRequest.getContext (),
284                     appRequest.getMethod (),
285                     appRequest,
286                     contextID,
287                     fullScreenActivated,
288                     inheritJahiaSessionAttributes,
289                     jParams);
290
291             String JavaDoc forceEncoding = null;
292             if (jParams.settings ().isUtf8Encoding ()) {
293                 forceEncoding = "UTF-8";
294             }
295             responseWrapper = new ServletIncludeResponseWrapper (jParams.
296                     getResponse (),
297                     appRequest.getUniqueIDStr (),
298                     appRequest.getURL (),
299                     jParams, false, forceEncoding);
300
301             // requestWrapper.setContextPath(jParams.getRequest().getContextPath() + "/" + CONTEXT_PATH_HEADER + appIDStr + "/");
302
logger.debug ("INCLUDE BEGIN -----");
303             // Let's now call the servlet and retrieve the result of it's processing
304
if (servletBean.getWebAppType () == ServletBean.JSP_TYPE) {
305                 // for JSP's we do a forward to avoid generation of the extra
306
// include parameters to be set internally by the servlet
307
// container.
308
String JavaDoc name = requestWrapper.getRequest().getClass().getName();
309                 if(name.indexOf("weblogic")>-1) {
310                     sessionDispatcher.include(requestWrapper, responseWrapper);
311                 } else {
312                     sessionDispatcher.forward(requestWrapper, responseWrapper);
313                 }
314             } else if (servletBean.getWebAppType () == ServletBean.SERVLET_TYPE) {
315                 logger.debug ("servletBean is of SERVLET TYPE");
316                 sessionDispatcher.include (requestWrapper, responseWrapper);
317                 //sessionDispatcher.forward(requestWrapper, responseWrapper);
318
}
319             logger.debug ("INCLUDE END -----");
320             if (!requestWrapper.isApplicationCacheOn ()) {
321                 logger.debug ("The application deactivated caching itself");
322                 mustCache = false;
323             }
324             cacheExpirationDelay = requestWrapper.
325                     getApplicationCacheExpirationDelay ();
326
327             if (responseWrapper.getRedirectLocation() != null) {
328                 // FIXME NK : 03 FEBRUARY 2004
329
// As send redirect doesn't work well I comment this out and
330
// provide a javascript redirection
331
//realResp.sendRedirect(responseWrapper.getRedirectLocation());
332
String JavaDoc outPut = ("<html><body><script language=\"JavaScript\">window.location.href='"
333                     + responseWrapper.encodeUrl(responseWrapper.getRedirectLocation()) + "';</script></body></html>");
334                 /*
335                 String outPut = ("<html><body><form method='GET' name='redirectForm' action='"
336                     + responseWrapper.encodeUrl(responseWrapper.getRedirectLocation()) + "'></form><script language=\"JavaScript\">document.redirectForm.action='"+responseWrapper.encodeUrl(responseWrapper.getRedirectLocation())+"'; alert(document.redirectForm.action); document.redirectForm.submit();</script></body></html>");
337                 */

338                return outPut;
339             }
340
341         } catch (ServletException JavaDoc se) {
342             logger.error ("Error in web application, can't access application " +
343                           appBean.getName (), se);
344             Throwable JavaDoc t = se;
345             t = JahiaErrorDisplay.getNestedException(t);
346             logger.error("Nested exception ", t);
347             return "Error while retrieving application " + appBean.getName ();
348         } catch (IOException JavaDoc ioe) {
349             logger.error ("Error in web application " +
350                           appBean.getName (), ioe);
351             return "Error while retrieving application " + appBean.getName ();
352         } catch (Throwable JavaDoc t) {
353             logger.error ("Error in web application for app " +
354                           appBean.getName (), t);
355             Throwable JavaDoc th = t;
356             th = JahiaErrorDisplay.getNestedException(th);
357             logger.error("Nested exception ", th);
358             return "Error while retrieving application " + appBean.getName ();
359         }
360
361         //logger.debug("Response=[" + responseWrapper.getStringBuffer() + "]");
362

363         //String applicationOutput = "Error while retrieving application " + appBean.getName();
364
String JavaDoc applicationOutput = null;
365         try {
366             applicationOutput = responseWrapper.getStringBuffer (false);
367         } catch (IOException JavaDoc ioe) {
368             logger.debug ("Exception on calling response.getStringBuffer()", ioe);
369             applicationOutput = "IOException while retrieving application " +
370                     appBean.getName () + ": " + ioe.getMessage ();
371             return applicationOutput;
372         }
373
374         // Return the String containing the output of the application.
375
if (mustCache) {
376             if (cacheExpirationDelay != -1) {
377                 // for the moment as we don't have an expiration system for the
378
// application output caches, we simply never use it if a
379
// delay has been set. We do however use the expiration mechanism
380
// of the HTML page output cache.
381
flushOutputCacheByAppUniqueID (jParams.getSession (), appUniqueIDStr);
382
383                 // flush the was processed attribute too
384
jParams.getSession ().removeAttribute (
385                         "org.jahia.services.applications.wasProcessed."
386                         + appUniqueIDStr);
387
388                 jParams.setCacheExpirationDelay (cacheExpirationDelay);
389             } else {
390                 flushOutputCacheByAppUniqueID (jParams.getSession (), appUniqueIDStr);
391                 HttpSession JavaDoc curSession = jParams.getSession ();
392                 if (curSession != null && applicationOutput != null) {
393                     outputCache.put (buildCacheKey (curSession, appUniqueIDStr),
394                             applicationOutput);
395                 }
396                 if (applicationOutput == null) {
397                     // flush the was processed attribute too
398
jParams.getSession ().removeAttribute (
399                             "org.jahia.services.applications.wasProcessed."
400                             + appUniqueIDStr);
401                 }
402             }
403         } else {
404             // let's set the page's cache expiration date
405
jParams.setCacheExpirationDelay (0);
406             flushOutputCacheByAppUniqueID (jParams.getSession (),
407                     appUniqueIDStr);
408
409             // flush the was processed attribute too
410
jParams.getSession ().removeAttribute (
411                     "org.jahia.services.applications.wasProcessed."
412                     + appUniqueIDStr);
413
414         }
415
416         if (appRequest.getMethod ().equalsIgnoreCase ("GET") && mustCache) {
417             HttpSession JavaDoc curSession = jParams.getSession ();
418             if (curSession != null) {
419                 requestCache.put (buildCacheKey (curSession, appUniqueIDStr),
420                         appRequest);
421             }
422         } else {
423             logger.debug ("POST method, skipping request cache update...");
424         }
425
426
427         return applicationOutput;
428     }
429
430     /**
431      * This method retrieves the output of an application in the case where we
432      * have no action defined for it. In this case we either previously stored
433      * a request in the cache, or we have to generate a new request since this
434      * is the first time we are calling the request, or no request has been stored
435      * because this feature was deactivated.
436      *
437      * @param appID Web application database ID
438      * @param appUniqueIDStr Unique web application ID generated from fieldID and
439      * database ID
440      * @param jParams a Jahia ParamBean object containing the request and response
441      * objects
442      *
443      * @return A string containing the output of the web application
444      */

445     public String JavaDoc getAppOutputNoAction (int appID,
446                                         String JavaDoc appUniqueIDStr,
447                                         String JavaDoc contextID,
448                                         ParamBean jParams,
449                                         boolean cacheRead,
450                                         boolean fullScreenActivated)
451             throws JahiaException {
452
453         String JavaDoc outputResult = null;
454         // we are in the case were there is no application ID
455
// default behavior :
456
// 1. lookup in cache for output for the current app
457
// 2. if none, generate URL and do request
458
HttpSession JavaDoc curSession = jParams.getSession ();
459
460         if (cacheRead) {
461             outputResult = (String JavaDoc) outputCache.get (buildCacheKey (curSession,
462                     appUniqueIDStr));
463         }
464
465         if (outputResult == null) {
466             // we must now check the request table to know if we can use a
467
// previous request.
468

469             PersistantServletRequest storedRequest =
470                     (PersistantServletRequest) requestCache.get (buildCacheKey (
471                             curSession, appUniqueIDStr));
472             if (storedRequest != null) {
473                 // we have found a previous request, let's use it.
474
if (storedRequest.getVisibleStatus () != 0) {
475                     logger.debug ("Using request stored in cache");
476                     outputResult = dispatchRequest (jParams,
477                             storedRequest.getApplicationBean (),
478                             storedRequest,
479                             storedRequest.getUniqueIDStr (),
480                             storedRequest.getURL (),
481                             storedRequest.getMethod (),
482                             contextID,
483                             cacheOutputBoolean,
484                             fullScreenActivated);
485                 } else {
486                     logger.debug ("Application has been deactivated");
487                     logger.error ("Error in web application",
488                             new JahiaException ("JahiaApplicationsDispatchingServletService",
489                                     "Application " + appID + " has been deactivated",
490                                     JahiaException.APPLICATION_ERROR,
491                                     JahiaException.WARNING_SEVERITY));
492                     return "Application has been deactivated";
493                 }
494             } else {
495                 // let's generate an URL since we never had any. we use the application's default servlet
496

497                 logger.debug ("Generating new URL for request");
498                 ApplicationBean appBean = ServicesRegistry.getInstance ()
499                         .getJahiaApplicationsManagerService ()
500                         .getApplication (appID);
501
502                 if (appBean == null) {
503
504                     String JavaDoc errorMsg = "AppID : " + appID;
505                     logger.error ("Error in web application",
506                             new JahiaException ("Cannot retrieve application definition !",
507                                     errorMsg,
508                                     JahiaException.DATABASE_ERROR,
509                                     JahiaException.ERROR_SEVERITY));
510
511                     return "The requested application is not available";
512
513                 }
514
515                 // visibleStatusCache.put(new Integer(appID), new Integer(appBean.getVisibleStatus())); // let's update visible status cache
516
if (curSession != null) {
517                     curSession.setAttribute (Integer.toString (appID),
518                             new
519                                     Integer JavaDoc (appBean.getVisibleStatus ()));
520                 }
521
522                 if (appBean.getVisibleStatus () == 0) {
523                     logger.debug ("Application has been deactivated");
524                     logger.warn ("Error in web application",
525                             new JahiaException ("JahiaApplicationsDispatchingServletService",
526                                     "Application " + appID + " has been deactivated",
527                                     JahiaException.APPLICATION_ERROR,
528                                     JahiaException.WARNING_SEVERITY));
529                     return "Application has been deactivated";
530                 }
531
532                 ApplicationContext appContext = ServicesRegistry.getInstance ()
533                         .
534                         getJahiaApplicationContextService ()
535                         .getApplicationContext (appBean.
536                         getContext ());
537
538                 // get the default servlet if any
539
String JavaDoc servletName = appContext.findServletMapping ("/");
540                 ServletBean servletBean = null;
541                 if (servletName != null) {
542                     servletBean = appContext.getServlet (servletName);
543                     if (servletBean != null) {
544                         servletBean.setUrlMappingPattern ("/");
545                     }
546                 } else {
547                     // no default servlet defined, we look for available welcome files
548
// actually we get the first if any
549
if (appContext.getWelcomeFiles ().size () > 0) {
550                         String JavaDoc welcomefile = (String JavaDoc) appContext.
551                                 getWelcomeFiles ().get (0);
552                         String JavaDoc resourceFile = welcomefile;
553                         if (!resourceFile.startsWith ("/")) {
554                             resourceFile = "/" + resourceFile;
555                         }
556                         servletBean = new ServletBean (ServletBean.JSP_TYPE,
557                                 appBean.getName (),
558                                 welcomefile,
559                                 resourceFile,
560                                 appBean.getContext (),
561                                 "");
562                         servletBean.setIsWelcomeFile(true);
563                     }
564                 }
565
566                 // NK : I added this for application without any servlet mapping information
567
//
568
if (servletBean == null) {
569                     try {
570                         servletBean = (ServletBean) appContext.getServlets ().
571                                 values ().iterator ().next ();
572                     } catch (Throwable JavaDoc t) {
573                     }
574                 }
575
576                 if (servletBean == null) {
577                     logger.error ("Error in web application",
578                             new JahiaException (
579                                     "Neither default servlet or welcome files found !",
580                                     "Neither default servlet or welcome files found !",
581                                     JahiaException.APPLICATION_ERROR,
582                                     JahiaException.ERROR_SEVERITY));
583                     return "Neither default servlet or welcome files found !";
584                 }
585
586                 if ((appBean.getJahiaID () != jParams.getSiteID ()) &&
587                         !appBean.isShared () &&
588                         ServicesRegistry.getInstance ().getAppsShareService ().
589                         getShare (jParams.getSite (), appBean) == null) {
590                     logger.debug ("You cannot access the application");
591                     logger.warn ("Warning in web application",
592                             new
593                                     JahiaException (
594                                             "JahiaApplicationsDispatchingServletService",
595                                             "Site has not share access with the app " + appID,
596                                             JahiaException.APPLICATION_ERROR,
597                                             JahiaException.WARNING_SEVERITY));
598                     return "Application has been deactivated";
599                 }
600
601                 String JavaDoc context;
602                 if (appBean.getContext ().equals ("/")) {
603                     context = "";
604                 } else {
605                     context = appBean.getContext ();
606                 }
607
608                 String JavaDoc URLPath = context;
609
610                 // WELCOME_FILE_ISSUE
611
if ( servletBean.isWelcomeFile()
612                     && !"".equals(servletBean.getservletsrc()) ){
613                     // we can have a welcome file here, so we must recompute the whole
614
// app URL if needed
615
if ( !URLPath.endsWith(servletBean.getservletsrc()) ){
616                         String JavaDoc url = URLPath;
617                         if ( URLPath.endsWith("/") ){
618                             url = URLPath.substring(0,URLPath.length()-1);
619                         }
620                         String JavaDoc servletSrc = servletBean.getservletsrc();
621                         if ( servletSrc.startsWith("/") ){
622                             servletSrc = servletBean.getservletsrc().substring(1);
623                         }
624                         URLPath = url + "/" + servletSrc;
625                     }
626                 }
627
628
629                 logger.debug ("Using URLPath = " + URLPath);
630
631                 outputResult = dispatchRequest (jParams,
632                         appBean,
633                         servletBean,
634                         appUniqueIDStr,
635                         URLPath,
636                         "GET",
637                         contextID,
638                         cacheOutputBoolean,
639                         fullScreenActivated);
640             }
641
642         } else {
643             logger.debug ("Retrieving application output from cache.");
644             // Integer visibleStatus = (Integer) visibleStatusCache.get(new Integer(appID));
645
Integer JavaDoc visibleStatus = null;
646             if (curSession != null) {
647                 visibleStatus = (Integer JavaDoc) curSession.getAttribute (Integer.
648                         toString (appID));
649             }
650             if (visibleStatus != null) {
651                 if (visibleStatus.intValue () == 0) {
652                     logger.warn ("Warning",
653                             new JahiaException ("JahiaApplicationsDispatchingServletService",
654                                     "Application " + appID + " has been deactivated",
655                                     JahiaException.APPLICATION_ERROR,
656                                     JahiaException.WARNING_SEVERITY));
657                     return "Application has been deactivated";
658                 }
659             }
660         }
661
662         return outputResult;
663     }
664
665     /**
666      * Retrieves the output of a servlet in a String object
667      * In order to avoid namespaces conflict, applications should be in seperate contexts of a servlet container.
668      * This way session information and object will be automatically local to that context.
669      * FIXME : still to be done : request wrapper, context wrapper (in case we need to change session info),
670      * We still have to decide what can of request we send objects that aren't concerned by the current
671      * request. One way to do it would be to clone the initial request and store it in a hashtable, then
672      * update it when a real request come to the concerned app.
673      *
674      * @param fieldID used to generate the context id for the app and build the unique id string
675      * @param appIDStr String containing the application ID, to be used to look it up in the application definition database
676      * @param jParams Bean containg the request and response objects
677      *
678      * @return String containing the output generated by the application.
679      */

680     public String JavaDoc getAppOutput (int fieldID, String JavaDoc appIDStr, ParamBean jParams)
681             throws JahiaException {
682
683         String JavaDoc outputResult = "";
684         String JavaDoc fieldIDStr = Integer.toString (fieldID);
685         String JavaDoc appUniqueIDStr = fieldIDStr + APP_ID_SEPARATOR + appIDStr;
686         String JavaDoc contextID = fieldIDStr;
687         boolean cacheRead = true;
688
689         if ((ParamBean.CACHE_OFF.equals (jParams.getOriginalCacheStatus ())) ||
690                 (ParamBean.CACHE_OFFONCE.equals (jParams.getOriginalCacheStatus ())) ||
691                 (ParamBean.CACHE_ONLYUPDATE.equals (jParams.getOriginalCacheStatus ()))) {
692             logger.debug (
693                     "Application cache deactivated because of request page cache status : " +
694                     jParams.getOriginalCacheStatus ());
695             cacheRead = false;
696         }
697
698         boolean fullScreenActivated = false;
699
700         logger.debug ("Requested Application is [" +
701                 appUniqueIDStr + "]");
702
703         if (jParams == null) {
704             return null;
705         }
706
707         // we deactivate the HTML page cache to avoid storing the entry screen of
708
// the application (first call on a page since it was flushed) in the
709
// HTML cache. The side effect of this is that any page that contains
710
// a web application is *NEVER* cached.
711
jParams.setCacheExpirationDelay(0);
712
713         HttpSession JavaDoc session = jParams.getSession ();
714
715         Boolean JavaDoc wasProcessed = (Boolean JavaDoc) session.getAttribute (
716                 "org.jahia.services.applications.wasProcessed." + appUniqueIDStr);
717         if (wasProcessed != null) {
718             // this means the application has ALREADY been processed during this request, we should just return the output cache
719
// if we have one, otherwise this means we had an error previously.
720
if (wasProcessed.booleanValue ()) {
721                 logger.debug (
722                         "Application was already accessed during this request, will only output cache again or error if we cannot find it !");
723                 outputResult = (String JavaDoc) outputCache.get (buildCacheKey (session,
724                         appUniqueIDStr));
725                 if (outputResult != null) {
726                     return outputResult;
727                 } else {
728                     logger.warn("Warning : Application " + appUniqueIDStr +
729                                 " has been marked as already processed but has no output cache stored !");
730                     session.setAttribute (
731                             "org.jahia.services.applications.wasProcessed." +
732                             appUniqueIDStr, new Boolean JavaDoc (true));
733                 }
734             } else {
735                 logger.debug (
736                         "Invalid attribute in request : org.jahia.services.applications.wasProcessed." +
737                         appUniqueIDStr + " should NEVER become false !");
738             }
739         } else {
740             session.setAttribute (
741                     "org.jahia.services.applications.wasProcessed." +
742                     appUniqueIDStr, new Boolean JavaDoc (true));
743         }
744
745         int appID = 0;
746
747         try {
748             appID = Integer.parseInt (appIDStr);
749         } catch (NumberFormatException JavaDoc nfe) {
750             logger.debug (
751                     "Error while parsing application id to convert to integer",
752                     nfe);
753             return "";
754         }
755
756         String JavaDoc fullScreenStr = jParams.getRequest ().getParameter ("maximize");
757         if (fullScreenStr == null) {
758             fullScreenStr = jParams.getRequest ().getParameter ("fullscreen");
759         }
760
761         int fullScreenFieldID = -1;
762         if (fullScreenStr != null) {
763             try {
764                 int seperatorPos = fullScreenStr.indexOf ("_");
765                 String JavaDoc fullScreenFieldIDStr = fullScreenStr.substring (
766                         seperatorPos + 1, fullScreenStr.length ());
767                 fullScreenFieldID = Integer.parseInt (fullScreenFieldIDStr);
768             } catch (NumberFormatException JavaDoc nfe) {
769             }
770         } else {
771             Integer JavaDoc sessionFullScreenFieldID = (Integer JavaDoc) session.getAttribute (
772                     "org.jahia.fullscreen");
773             if (sessionFullScreenFieldID != null) {
774                 if (sessionFullScreenFieldID.intValue () == fieldID) {
775                     // we found a full screen mode for this field but we don't have it in the URL, let's deactivate full screen mode.
776
logger.debug ("Restoring size, not reading from cache");
777                     session.removeAttribute ("org.jahia.fullscreen");
778                     fullScreenActivated = false;
779                     cacheRead = false;
780                 }
781             }
782         }
783
784         if (fullScreenFieldID != -1) {
785             if (fullScreenFieldID == fieldID) {
786                 logger.debug (
787                         "Fullscreen mode detected for this field, not reading from cache...");
788                 session.setAttribute ("org.jahia.fullscreen",
789                         new Integer JavaDoc (fullScreenFieldID));
790                 cacheRead = false;
791                 fullScreenActivated = true;
792             }
793         }
794
795         // Now let's check the request URL to see if the target application is this one or not.
796

797         String JavaDoc queryStr = jParams.getRequest ().getParameter ("appid");
798         // logger.debug("queryStr=[" + queryStr + "]");
799

800         if (queryStr != null) {
801             if (queryStr.equals (appUniqueIDStr)) {
802                 String JavaDoc appURL = jParams.getRequest ().getParameter ("appparams");
803                 logger.debug ("Action detected : appParams=[" + appURL + "]");
804                 // This is indeed the targeted application
805

806                 ApplicationBean appBean = ServicesRegistry.getInstance ().
807                         getJahiaApplicationsManagerService ().
808                         getApplication (appID);
809
810                 if (appBean == null) {
811                     /*
812                                          String errorMsg = "AppID : " + appID;
813                          throw new JahiaException ( "Cannot retrieve application definition !",
814                                                errorMsg,
815                                                JahiaException.DATABASE_ERROR,
816                                                JahiaException.ERROR);
817                      */

818                     return "The referred application is not available";
819                 }
820
821                 if (appBean.getVisibleStatus () == 0) {
822                     logger.warn ("Application has been deactivated",
823                             new
824                                     JahiaException (
825                                             "JahiaApplicationsDispatchingServletService",
826                                             "Application " + appID +
827                             " has been deactivated",
828                                             JahiaException.APPLICATION_ERROR,
829                                             JahiaException.WARNING_SEVERITY));
830                     return "Application has been deactivated";
831                 }
832
833                 ServletBean servletBean = getServletBean (appBean, appURL);
834
835                 HttpSession JavaDoc curSession = jParams.getSession ();
836                 if (curSession != null) {
837                     curSession.setAttribute (Integer.toString (appID),
838                             new Integer JavaDoc (appBean.
839                             getVisibleStatus ()));
840                 }
841
842                 if (appBean == null || servletBean == null) {
843
844                     String JavaDoc errorMsg = "AppID : " + appID;
845                     throw new JahiaException (
846                             "Cannot retrieve application definition !",
847                             errorMsg,
848                             JahiaException.DATABASE_ERROR,
849                             JahiaException.ERROR_SEVERITY);
850                 }
851
852                 // WELCOME_FILE_ISSUE
853
if ( servletBean.isWelcomeFile() &&
854                      !"".equals(servletBean.getservletsrc())){
855                     // we can have a welcome file here, so we must recompute the whole
856
// app URL if needed
857
if ( !appURL.endsWith(servletBean.getservletsrc()) ){
858                         String JavaDoc url = appURL;
859                         if ( appURL.endsWith("/") ){
860                             url = appURL.substring(0,appURL.length()-1);
861                         }
862                         String JavaDoc servletSrc = servletBean.getservletsrc();
863                         if ( servletSrc.startsWith("/") ){
864                             servletSrc = servletBean.getservletsrc().substring(1);
865                         }
866                         appURL = url + "/" + servletSrc;
867                     }
868                 }
869
870                 outputResult = dispatchRequest (jParams,
871                         appBean,
872                         servletBean,
873                         appUniqueIDStr,
874                         appURL,
875                         jParams.getRequest().getMethod (),
876                         contextID,
877                         cacheOutputBoolean,
878                         fullScreenActivated);
879             } else {
880                 outputResult = getAppOutputNoAction (appID, appUniqueIDStr,
881                         contextID, jParams, cacheRead, fullScreenActivated);
882             }
883         } else {
884             outputResult = getAppOutputNoAction (appID, appUniqueIDStr,
885                     contextID, jParams, cacheRead,
886                     fullScreenActivated);
887         }
888
889         return outputResult;
890
891     }
892
893     // @author NK
894
/**
895      * Resolve servlet mapping, return a servlet bean for the given application
896      * request.
897      */

898     private ServletBean getServletBean (ApplicationBean appBean, String JavaDoc appURL)
899             throws JahiaException {
900
901         ServletBean servletBean = null;
902
903         String JavaDoc url = ServletIncludeRequestWrapper.URLDecode (appURL);
904
905         int pos = url.indexOf (appBean.getContext ());
906         if (pos == -1) {
907             String JavaDoc errMsg = "Cannot locate the application context path part [" +
908                     appBean.getContext () + "] in the appParams [" +
909                     appURL + "]";
910             throw new JahiaException (errMsg, errMsg,
911                     JahiaException.ERROR_SEVERITY,
912                     JahiaException.APPLICATION_ERROR);
913         }
914
915         String JavaDoc appRequestURI = url.substring (pos);
916         ApplicationContext appContext = ServicesRegistry.getInstance ()
917                 .getJahiaApplicationContextService ()
918                 .getApplicationContext (appBean.
919                 getContext ());
920         if (appContext == null) {
921             String JavaDoc errMsg = "ApplicationContext not found for app context [" +
922                     appBean.getContext () + "] in the appParams [" +
923                     appURL + "]";
924             throw new JahiaException (errMsg, errMsg,
925                     JahiaException.ERROR_SEVERITY,
926                     JahiaException.APPLICATION_ERROR);
927         }
928
929         String JavaDoc servletMappingPattern = appContext.
930                 findServletMappingFromRequestURI (
931                         appRequestURI);
932         if (servletMappingPattern != null) {
933             String JavaDoc servletName = appContext.findServletMapping (
934                     servletMappingPattern);
935             servletBean = appContext.getServlet (servletName);
936             // store the mapping pattern information
937
if (servletBean != null) {
938                 servletBean.setUrlMappingPattern (servletMappingPattern);
939             }
940         } else {
941             logger.debug ("None of the servlet mapping matched the app URL [" +
942                     appURL + "]");
943             // no servlet mapping can resolve requested servlet
944
// perhaps, the requested resource is a file instead of a servlet
945
pos = appRequestURI.indexOf ("?");
946             String JavaDoc subStr = appRequestURI;
947             if (pos != -1) {
948                 subStr = appRequestURI.substring (0, pos);
949             }
950             logger.debug (" appURL without queryString = [" + subStr + "]");
951
952             // boolean servletBeanIsCreatedForResource = (subStr.indexOf (".")!=-1) ;
953
String JavaDoc[] resourceSuffix = {"jsp","html","htm","jsf","inc"};
954             boolean servletBeanIsCreatedForResource = false;
955             for(int i=0; i<resourceSuffix.length; i++){
956                 if(subStr.endsWith("."+resourceSuffix[i])){
957                     servletBeanIsCreatedForResource = true;
958                     break;
959                 }
960             }
961             if (servletBeanIsCreatedForResource) {
962                 logger.debug (
963                         " Servlet Bean is created for a resource (jsp,html,...) request ");
964                 
965                 servletBean = new ServletBean (ServletBean.JSP_TYPE,
966                         appBean.getName (),
967                         appBean.getName (),
968                         subStr.substring (appBean.
969                         getContext ().length ()),
970                         appBean.getContext (),
971                         "");
972             } else if (appContext.getWelcomeFiles ().size () > 0) {
973                 logger.debug (
974                         " Servlet Bean is created with the first welcome files ");
975                 String JavaDoc welcomefile = (String JavaDoc) appContext.getWelcomeFiles ().get (
976                         0);
977                 String JavaDoc resourceFile = subStr.substring (appBean.getContext ().
978                         length ());
979                 if (!resourceFile.startsWith ("/")) {
980                     resourceFile = "/" + resourceFile;
981                 }
982                 if (!resourceFile.endsWith ("/") && welcomefile.startsWith ("/")) {
983                     resourceFile += "/";
984                 }
985                 resourceFile += welcomefile;
986
987                 servletBean = new ServletBean (ServletBean.JSP_TYPE,
988                         appBean.getName (),
989                         welcomefile,
990                         resourceFile,
991                         appBean.getContext (),
992                         "");
993                 servletBean.setIsWelcomeFile(true);
994             } else {
995                 // NK : I added this for application without any servlet mapping information and without any welcome file
996
try {
997                     servletBean = (ServletBean) appContext.getServlets ().values ().
998                             iterator ().next ();
999                 } catch (Throwable JavaDoc t) {
1000                }
1001            }
1002        }
1003        return servletBean;
1004    }
1005
1006    public void flushAllSessionsCaches (HttpSession JavaDoc session) {
1007        logger.debug ("Starting to flush all the session caches");
1008        flushSessionOutputCache (session);
1009        flushSessionRequestCache (session);
1010
1011        java.util.Enumeration JavaDoc enumeration = null;
1012        try {
1013            enumeration = session.getAttributeNames();
1014        } catch (IllegalStateException JavaDoc ise) {
1015            // this happens when we call the flush from the web app listener,
1016
// in which case the session has already been invalidated. Therefore
1017
// we can just stop here.
1018
return;
1019        }
1020        java.util.Vector JavaDoc toRemove = new java.util.Vector JavaDoc ();
1021        while (enumeration.hasMoreElements ()) {
1022            String JavaDoc name = (String JavaDoc) enumeration.nextElement ();
1023            if (name.startsWith ("org.jahia.services.applications.wasProcessed.")) {
1024                toRemove.add (name);
1025            }
1026        }
1027
1028        int size = toRemove.size ();
1029        for (int i = 0; i < size; i++) {
1030            session.removeAttribute ((String JavaDoc) toRemove.get (i));
1031        }
1032    }
1033
1034    final public void flushSessionOutputCache (HttpSession JavaDoc session) {
1035        flushCacheBySession (outputCache, session);
1036    }
1037
1038    final public void flushSessionRequestCache (HttpSession JavaDoc session) {
1039        flushCacheBySession (requestCache, session);
1040    }
1041
1042    private void flushCacheBySession(Cache cache, HttpSession JavaDoc session) {
1043        // null sessions are not allowed
1044
if (session == null) {
1045            logger.debug("null session! Stopping flushing process.");
1046            return;
1047        }
1048
1049        logger.debug("Flushing cache [" + cache.getName() + "] for session "
1050                + session.getId());
1051        if (CacheFactory.getInstance().isKeyHierarchyEnabled()) {
1052            cache.remove(session.getId());
1053        } else {
1054            Object JavaDoc[] cacheKeys = cache.keys();
1055            Set JavaDoc keysToRemove = new java.util.HashSet JavaDoc();
1056            for (int i = 0; i < cacheKeys.length; i++) {
1057                String JavaDoc curCacheKey = (String JavaDoc) cacheKeys[i];
1058                if (curCacheKey.startsWith(session.getId())) {
1059                    keysToRemove.add(curCacheKey);
1060                }
1061            }
1062            java.util.Iterator JavaDoc keysToRemoveIter = keysToRemove.iterator();
1063            while (keysToRemoveIter.hasNext()) {
1064                String JavaDoc curKeyToRemove = (String JavaDoc) keysToRemoveIter.next();
1065                cache.remove(curKeyToRemove);
1066            }
1067        }
1068    }
1069
1070    public void flushApplicationSessionRequestCache (HttpSession JavaDoc session,
1071                                                     String JavaDoc appUniqueIDStr) {
1072
1073        // null sessions are not allowed, neither null application IDs
1074
if (session == null) {
1075            logger.debug ("null session! Stopping flushing process.");
1076            return;
1077        }
1078
1079        if (appUniqueIDStr == null) {
1080            logger.debug ("null application ID! Stopping flushing process.");
1081            return;
1082        }
1083
1084        logger.debug ("Flushing request cache for session " + session.getId ()
1085                + " and AppId=" + appUniqueIDStr);
1086
1087        requestCache.remove (buildCacheKey (session, appUniqueIDStr));
1088    }
1089
1090    public void setApplicationSessionRequestCache (HttpSession JavaDoc session,
1091                                                   PersistantServletRequest request) {
1092        if (session != null && request != null) {
1093            requestCache.put (buildCacheKey (session, request.getUniqueIDStr ()),
1094                    request);
1095
1096        } else {
1097            logger.debug (
1098                    "null session or null request! Stopping caching process.");
1099        }
1100    }
1101
1102    private Object JavaDoc buildCacheKey(HttpSession JavaDoc session, String JavaDoc appUniqueIDStr) {
1103        Object JavaDoc key = null;
1104        if (CacheFactory.getInstance().isKeyHierarchyEnabled()) {
1105            List JavaDoc keyList = new ArrayList JavaDoc(2);
1106            keyList.add(session.getId());
1107            keyList.add(appUniqueIDStr);
1108            key = keyList;
1109        } else {
1110            key = session.getId() + CACHE_ID_SEPARATOR + appUniqueIDStr;
1111        }
1112        return key;
1113    }
1114
1115    /**
1116     * if session is null flush all output entries for the given appID
1117     *
1118     * @param session
1119     * @param appUniqueIDStr
1120     */

1121    public void flushOutputCacheByAppUniqueID(HttpSession JavaDoc session,
1122            String JavaDoc appUniqueIDStr) {
1123        // null application IDs are not allowed
1124
if (appUniqueIDStr == null) {
1125            logger.debug("null application ID! Stopping flushing process.");
1126            return;
1127        }
1128
1129        if (session != null) {
1130            outputCache.remove(this.buildCacheKey(session, appUniqueIDStr));
1131        } else {
1132            Set JavaDoc keysToFlush = new HashSet JavaDoc();
1133
1134            if (CacheFactory.getInstance().isKeyHierarchyEnabled()) {
1135                Object JavaDoc[] outputCacheKeys = outputCache.keys();
1136                for (int i = 0; i < outputCacheKeys.length; i++) {
1137                    List JavaDoc keyList = new ArrayList JavaDoc(2);
1138                    keyList.add(outputCacheKeys[i]);
1139                    keyList.add(appUniqueIDStr);
1140                    if (outputCache.containsKey(keyList)){
1141                        keysToFlush.add(keyList);
1142                    }
1143                }
1144            } else {
1145                Object JavaDoc[] outputCacheKeys = outputCache.keys();
1146                for (int i = 0; i < outputCacheKeys.length; i++) {
1147                    String JavaDoc curOutputCacheKey = (String JavaDoc) outputCacheKeys[i];
1148                    if (curOutputCacheKey
1149                            .indexOf(JahiaApplicationsDispatchingServletService.CACHE_ID_SEPARATOR
1150                                    + appUniqueIDStr) != -1) {
1151                        keysToFlush.add(curOutputCacheKey);
1152                    }
1153                }
1154            }
1155
1156            Iterator JavaDoc keyToFlushIter = keysToFlush.iterator();
1157            while (keyToFlushIter.hasNext()) {
1158                String JavaDoc curKeyToFlush = (String JavaDoc) keyToFlushIter.next();
1159                outputCache.remove(curKeyToFlush);
1160            }
1161        }
1162    }
1163
1164}
1165
Popular Tags