KickJava   Java API By Example, From Geeks To Geeks.

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


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 package org.jahia.services.applications;
14
15 import org.apache.log4j.Logger;
16 import org.apache.regexp.RE;
17 import org.jahia.bin.Jahia;
18 import org.jahia.data.applications.ApplicationBean;
19 import org.jahia.engines.applications.FullScreenDispatcherEngine;
20 import org.jahia.exceptions.JahiaException;
21 import org.jahia.params.ParamBean;
22 import org.jahia.registries.ServicesRegistry;
23
24 import javax.servlet.ServletContext JavaDoc;
25 import javax.servlet.ServletOutputStream JavaDoc;
26 import javax.servlet.http.Cookie JavaDoc;
27 import javax.servlet.http.HttpServletRequest JavaDoc;
28 import javax.servlet.http.HttpServletResponse JavaDoc;
29 import javax.servlet.http.HttpServletResponseWrapper JavaDoc;
30 import java.util.Properties JavaDoc;
31 import java.io.PrintWriter JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.UnsupportedEncodingException JavaDoc;
34 import java.io.File JavaDoc;
35 import java.io.OutputStreamWriter JavaDoc;
36 import java.net.MalformedURLException JavaDoc;
37 import java.net.URL JavaDoc;
38 import java.net.URLEncoder JavaDoc;
39
40
41 /**
42  * This response wrapper allows the use of a StringPrinterWriter instead of the
43  * regular output stream-based ones. This allows Jahia to get a copy of the output
44  * to enable further processing before sending it back to the browser.
45  * Another important feature of this wrapper is to modify the behaviour of the
46  * encodeURL function call to enable the routing of action URLs to the correct
47  * application.
48  * Note : the implementation of the getWriter and getOutputStream could be
49  * re-written by using a combination like this one PrintWriter(StringWriter(StringBuffer))
50  * but this would probably involve a small performance hit (to be tested !). It
51  * would have the advantage of probably removing some code that is a little
52  * unnecessary. (for implementation see org.jahia.bin.JahiaErrorDisplay where
53  * this has been used but performance is not an issue there).
54  *
55  * @author Serge Huber
56  * @todo We should really split this class into two classes : one with
57  * emulation, one without. It would make a lot of the code much simpler to
58  * maintain.
59  */

60 public class ServletIncludeResponseWrapper extends HttpServletResponseWrapper JavaDoc {
61
62     private static Logger logger = Logger.getLogger (ServletIncludeResponseWrapper.class);
63
64     // private StringPrintWriter strPrintWriter;
65
private PrintWriter JavaDoc strPrintWriter = null;
66     private StringServletOutputStream strOutputStream = null;
67     private String JavaDoc appUniqueIDStr; // application ID in String format
68
private ParamBean jahiaParams;
69     private String JavaDoc emulatedURL;
70     private String JavaDoc contentType;
71     private boolean outputStreamCalled = false;
72     private String JavaDoc redirectLocation = null;
73     private boolean isPassThrough = false;
74     private String JavaDoc encoding = "ISO-8859-1";
75     private String JavaDoc forceEncoding = null;
76     private static final String JavaDoc APP_ID_SEPARATOR = "_";
77     private String JavaDoc pageUrlKey;
78     
79     /** Pattern used to extract the second id part */
80     private static String JavaDoc mFieldIDPart = "(^\\d+)_\\d+";
81
82
83     /** The RExp used to extract the role name part in the Application role group name pattern */
84     private static org.apache.regexp.RE mRExpFieldID = null;
85
86
87     static {
88
89         try {
90             mRExpFieldID = new RE (mFieldIDPart);
91         } catch (Throwable JavaDoc t) {
92             logger.debug ("Error while creating regular expression ", t);
93         }
94
95     }
96
97     /**
98      * Simple constructor without support for URL redirecting.
99      */

100     public ServletIncludeResponseWrapper (HttpServletResponse JavaDoc httpServletResponse,
101                                           boolean passThrough, String JavaDoc forcedEncoding) {
102         super (httpServletResponse);
103         logger.debug ("Initializing using normal mode");
104         appUniqueIDStr = null;
105         this.isPassThrough = passThrough;
106         this.forceEncoding = forcedEncoding;
107         if (forceEncoding != null) {
108             encoding = forcedEncoding;
109             this.contentType = "text/html; charset=" + forceEncoding;
110         }
111     }
112
113     /**
114      * @param appID a String containg the application ID
115      * @param jahiaArgs Jahia's current HTTP request paramater to be concatenated with the URLs generated by the application
116      */

117     public ServletIncludeResponseWrapper (HttpServletResponse JavaDoc httpServletResponse,
118                                           String JavaDoc appUniqueID,
119                                           String JavaDoc emulURL,
120                                           ParamBean jParams,
121                                           boolean passThrough,
122                                           String JavaDoc forcedEncoding) {
123         super (httpServletResponse);
124         logger.debug ("Initializing using emulation mode. appID = [" + appUniqueID + "]");
125         appUniqueIDStr = appUniqueID;
126         jahiaParams = jParams;
127         emulatedURL = emulURL;
128         this.isPassThrough = passThrough;
129         this.forceEncoding = forcedEncoding;
130         if (forceEncoding != null) {
131             encoding = forcedEncoding;
132             this.contentType = "text/html; charset=" + forceEncoding;
133         }
134     }
135
136     public ServletIncludeResponseWrapper(
137             HttpServletResponse JavaDoc httpServletResponse, String JavaDoc aPageUrlKey,
138             String JavaDoc appUniqueID, String JavaDoc emulURL, ParamBean jParams,
139             boolean passThrough, String JavaDoc forcedEncoding) {
140         super(httpServletResponse);
141         logger.debug("Initializing using emulation mode. appID = ["
142                 + appUniqueID + "]");
143         appUniqueIDStr = appUniqueID;
144         jahiaParams = jParams;
145         emulatedURL = emulURL;
146         this.pageUrlKey = aPageUrlKey;
147         this.isPassThrough = passThrough;
148         this.forceEncoding = forcedEncoding;
149         if (forceEncoding != null) {
150             encoding = forcedEncoding;
151             this.contentType = "text/html; charset=" + forceEncoding;
152         }
153     }
154     
155     public PrintWriter JavaDoc getWriter () {
156         logger.debug ("Using a print writer for output");
157         checkStreams ();
158         if (outputStreamCalled) {
159             logger.debug (
160                     "Servlet compliance warning, OutputStream has already been called, the response output will be reset !");
161         }
162         return strPrintWriter;
163     }
164
165     public ServletOutputStream JavaDoc getOutputStream () throws IOException JavaDoc {
166         logger.debug ("Using an output stream for output");
167         checkStreams ();
168         this.outputStreamCalled = true;
169         return strOutputStream;
170     }
171
172     public String JavaDoc getStringBuffer () throws IOException JavaDoc {
173         return getStringBuffer (true);
174     }
175
176     public String JavaDoc getStringBuffer (boolean checkWriterError) throws IOException JavaDoc {
177         try {
178             if (outputStreamCalled) {
179                 // logger.debug("buffer=[" + strOutputStream.getBuffer(encoding) + "]");
180
return strOutputStream.getBuffer ();
181             } else {
182                 // logger.debug("buffer=[" + strOutputStream.getBuffer(encoding) + "]");
183
if (strOutputStream == null) {
184                     return null;
185                 } else {
186                     if (strPrintWriter.checkError () && checkWriterError) {
187                         throw new IOException JavaDoc ("An error has occured while writing to output");
188                     }
189                     return strOutputStream.getBuffer ();
190                 }
191             }
192         } catch (UnsupportedEncodingException JavaDoc uee) {
193             logger.debug ("Error in encoding [" + encoding + " ], returning empty buffer", uee);
194             return "";
195         }
196     }
197
198     public String JavaDoc getRedirectLocation () {
199         return redirectLocation;
200     }
201
202     public String JavaDoc getCharacterEncoding () {
203         return encoding;
204     }
205
206     public void flushBuffer () {
207         /*
208         if (strPrintWriter != null) {
209             strPrintWriter.flush();
210         }
211         if (strOutputStream != null) {
212             try {
213                 strOutputStream.flush();
214             } catch (IOException ioe) {
215                 logger.error("Error while flushing output stream", ioe);
216             }
217         }
218         */

219         logger.debug ("flushBuffer()");
220     }
221
222     public void resetBuffer () {
223         logger.debug ("resetBuffer()");
224     }
225
226     public void finishResponse () {
227         logger.debug ("finishResponse()");
228     }
229
230     public boolean isCommitted () {
231         logger.debug ("isCommitted()");
232         return false;
233     }
234
235     private static String JavaDoc[][] STATIC_EXTS = { null, // 0
236
null, // 1
237
{ "js" }, // 2
238
{ "css", "gif", "ico", "jpg", "jpe", "htm", "png", "xml" }, // 3
239
{ "jpeg", "html" } // 4
240
};
241
242     private String JavaDoc internalEncodeURL(String JavaDoc url) {
243         if (url != null && url.length() != 0) {
244             if (url.indexOf("/webdav/") == -1 || url.indexOf('?') == -1) {
245                 int point = url.lastIndexOf('.'); // in case URL is absolute
246
int extLen = url.length() - point - 1;
247                 if (extLen > 0 && extLen < STATIC_EXTS.length) {
248                     String JavaDoc ext = url.substring(point + 1);
249                     String JavaDoc[] exts = STATIC_EXTS[extLen];
250                     if (exts != null) {
251                         for (int j = 0; j < exts.length; j++)
252                             if (ext.equalsIgnoreCase(exts[j]))
253                                 return url; // skip encoding
254
}
255                 }
256             }
257             return super.encodeURL(url);
258         } else
259             return url;
260     }
261         
262     /**
263      * The purpose of this function is to transform relative URL for a Jahia aggregation.
264      * The issue here is that Jahia uses it's own parameters, and aggregates applications that
265      * also use their own parameters. Therefore Jahia must encode the URL of the application so
266      * that it is able to dispatch the call to the correct app and not misinterpret it for one
267      * of it's own parameters.
268      * <pre>
269      * Example:
270      * Let's say the application generates a URL like the following one :
271      * /servlet/Test?arg1=2&arg3=4
272      * Jahia must encode it into something like this :
273      * ?context=appid&appargs=%2Fservlet%2FTest%3Farg1%3D2%26arg3%3D
274      * </pre>
275      */

276     public String JavaDoc encodeURL (String JavaDoc url) {
277
278         if (url == null) {
279             return null;
280         }
281
282         String JavaDoc servletIncludeURL;
283
284         if (jahiaParams != null && appUniqueIDStr != null) {
285             if (url.toLowerCase ().indexOf (".jsp") == -1) {
286                 try {
287                     // Check if we should add Jahia extra URL encoding or not.
288
// We don't if the resource is not a servlet ( or jsp )
289
ApplicationBean appBean = ServicesRegistry.getInstance().getJahiaApplicationsManagerService()
290                             .getApplication(
291                                     Integer.parseInt(appUniqueIDStr
292                                             .substring(appUniqueIDStr.indexOf(APP_ID_SEPARATOR) + 1)));
293
294                     if (appBean == null) {
295                         logger.debug (
296                                 "The requested application [" + appUniqueIDStr + "] is not available");
297                     }
298
299                     ServletContext JavaDoc dispatchedContext = Jahia.getThreadParamBean ()
300                             .getContext ().getContext (appBean.getContext ());
301                     if (dispatchedContext == null) {
302                         logger.debug ("Error getting dispatch context [" +
303                                 appBean.getContext () + "]");
304                         return super.encodeURL (url);
305                     }
306                     try {
307                         String JavaDoc path = url;
308                         if (url.startsWith (appBean.getContext ())) {
309                             // remove the context
310
path = url.substring (url.indexOf (appBean.getContext ()))
311                                     .substring (appBean.getContext ().length ());
312                         }
313                         path = dispatchedContext.getRealPath (path);
314                         File JavaDoc f = new File JavaDoc (path);
315                         if (f.isFile ()) {
316                             return super.encodeURL (url);
317                         }
318                     } catch (Throwable JavaDoc t) {
319                     }
320                 } catch (Throwable JavaDoc t) {
321                     logger.debug (
322                             "Exception retrieving Applicatiton Context appid[" + appUniqueIDStr + "]\n",
323                             t);
324                     return super.encodeURL (url);
325                 }
326             }
327
328             boolean fullScreenEngineOn = false;
329             if (jahiaParams.getEngine ().equals (FullScreenDispatcherEngine.ENGINE_NAME)) {
330                 fullScreenEngineOn = true;
331             }
332
333             String JavaDoc realURL = new String JavaDoc (url);
334             // first let's check if there are special codes that are
335
// actually Jahia mode settings.
336
if (realURL != null) {
337                 if (realURL.startsWith ("###JAHIA###")) {
338                     // we have detected a special URL...
339

340                     realURL = realURL.substring (11); // remove the ###JAHIA###
341
while (realURL.indexOf ("###") >= 0) {
342                         int seperatorPos = realURL.indexOf ("###");
343                         String JavaDoc jahiaModifier = realURL.substring (0, seperatorPos);
344                         if (jahiaModifier != null) {
345                             if ("fullscreen".equals (jahiaModifier.toLowerCase ())) {
346                                 fullScreenEngineOn = true;
347                             }
348                             if ("restore".equals (jahiaModifier.toLowerCase ())) {
349                                 fullScreenEngineOn = false;
350                             }
351                         }
352                         realURL = realURL.substring (seperatorPos + 3);
353                     }
354                 }
355             }
356
357             HttpServletRequest JavaDoc request = jahiaParams.getRequest();
358             String JavaDoc urlPort;
359             URL JavaDoc resolvedURL;
360
361             int serverPort = request.getServerPort();
362             if (serverPort == 80) {
363                 urlPort = "";
364             } else {
365                 urlPort = ":" + serverPort;
366             }
367
368             try {
369                 URL JavaDoc contextURL = null;
370                 if (url.startsWith ("/")) { // if it starts with a "/" it is relative to the
371
// the context URL
372
contextURL = new URL JavaDoc (request.getScheme () + "://" +
373                             request.getServerName () + urlPort + "/");
374                 } else {
375                     // no starting "/", relative URL...
376
URL JavaDoc emulURL = new URL JavaDoc (emulatedURL);
377                     if (emulURL.getPort () != 80 && emulURL.getPort () != -1) {
378                         contextURL = new URL JavaDoc (emulURL.getProtocol () + "://" +
379                                 emulURL.getHost () + ":" +
380                                 emulURL.getPort () +
381                                 emulURL.getPath ());
382                     } else {
383                         contextURL = new URL JavaDoc (emulURL.getProtocol () + "://" +
384                                 emulURL.getHost () +
385                                 emulURL.getPath ());
386                     }
387                 }
388
389                 logger.debug ("encodeURL.contextURL=[" + contextURL.toString () + "]");
390
391                 resolvedURL = new URL JavaDoc (contextURL, realURL);
392             } catch (MalformedURLException JavaDoc mue) {
393                 return null;
394             }
395
396             //logger.debug( "encodeURL.resolvedURL=[" +
397
// resolvedURL.toString() + "]");
398

399             servletIncludeURL = super.encodeURL(resolvedURL.toString()); // let's
400
// logger.debug( "encodeURL.ServletIncludeURL=[" +
401
// ServletIncludeURL + "]");
402
try {
403                 servletIncludeURL = URLEncoder.encode(servletIncludeURL,
404                     encoding);
405             } catch (UnsupportedEncodingException JavaDoc ex) {
406                 logger.error(ex.getMessage(), ex);
407             }
408
409             try {
410                 // Hollis : append app anchor
411
String JavaDoc anchorID = ServletIncludeResponseWrapper.getFieldIDPart (appUniqueIDStr);
412                 if (anchorID != null) {
413                     jahiaParams.setAnchor ("field_" + anchorID);
414                     // logger.debug( "set anchor to " + jahiaParams.getAnchor() );
415
}
416                 // let's deactivate the cache in these requests since we must
417
// never cache application requests.
418
String JavaDoc savedCacheStatus = jahiaParams.getCacheStatus ();
419                 jahiaParams.setCacheStatus (ParamBean.CACHE_BYPASS);
420                 String JavaDoc fullScreenStr = "";
421                 String JavaDoc fullScreenIDStr = request.getParameter ("fullscreen");
422                 if (fullScreenIDStr == null) {
423                     fullScreenIDStr = request.getParameter ("maximize");
424                 }
425                 if (fullScreenIDStr != null) {
426                     fullScreenStr = "&fullscreen=" + fullScreenIDStr;
427                 }
428
429                 if (fullScreenEngineOn) {
430
431                     // we are using the full screen engine instead of the
432
// regular core engine.
433
Properties JavaDoc extraParams = new Properties JavaDoc ();
434                     extraParams.setProperty (ParamBean.PAGE_ID_PARAMETER,
435                             Integer.toString (jahiaParams.getPageID ()));
436                     servletIncludeURL = jahiaParams.composeEngineUrl(
437                             FullScreenDispatcherEngine.ENGINE_NAME, extraParams,
438                             "?appid=" + appUniqueIDStr + "&appparams="
439                                     + servletIncludeURL + "&resetAppSession=true");
440                 } else {
441                     if (pageUrlKey == null)
442                         servletIncludeURL = jahiaParams.composeUrl("?appid="
443                                 + appUniqueIDStr + fullScreenStr
444                                 + "&appparams=" + servletIncludeURL
445                                 + "&resetAppSession=true");
446                     else
447                         servletIncludeURL = jahiaParams.composeUrl(pageUrlKey,
448                             "?appid=" + appUniqueIDStr + fullScreenStr
449                                     + "&appparams=" + servletIncludeURL
450                                     + "&resetAppSession=true");
451                 }
452                 jahiaParams.setCacheStatus (savedCacheStatus);
453             } catch (JahiaException je) {
454                 servletIncludeURL = null;
455             }
456
457         } else {
458             if (url.indexOf (";jsessionid=") != -1) {
459                 logger.debug (
460                         "jsessionid already in URL, ignoring call and returning unmodified URL... ");
461                 servletIncludeURL = url;
462             } else {
463                 servletIncludeURL = internalEncodeURL(url); // let's add Java
464
}
465         }
466
467         return servletIncludeURL;
468     }
469
470     public String JavaDoc encodeUrl (String JavaDoc URL) {
471         return encodeURL (URL);
472     }
473
474     public void sendRedirect (String JavaDoc location) throws IOException JavaDoc {
475         logger.debug ("location=" + location + "");
476         if (redirectLocation != null) {
477             logger.debug ("Multiple calls to sendRedirect, keeping only the first one.");
478         } else {
479             if (location.endsWith ("/")) {
480                 redirectLocation = location.substring (0, location.length () - 1);
481             } else {
482                 redirectLocation = location;
483             }
484         }
485         if (isPassThrough) {
486             logger.debug (
487                     "Pass-through active, sending redirect to wrapped response directly...");
488             super.sendRedirect (location);
489         } else {
490             logger.debug ("redirectLocation=" + redirectLocation + "");
491         }
492     }
493
494
495     public void setContentType (java.lang.String JavaDoc type) {
496         logger.debug ("Content-type set to [" + type + "]");
497         if (contentType != null) {
498             if (!this.contentType.equals (type)) {
499                 logger.debug ("Warning, content type has already been set to [" +
500                         contentType + "]. Trying to set now to [" + type +
501                         "]");
502             }
503         }
504         if (forceEncoding != null) {
505             logger.debug ("Enforcing charset=[" + forceEncoding + "]");
506             int separatorPos = type.indexOf (";");
507             if (separatorPos > 0) {
508                 type = type.substring (0, separatorPos);
509             }
510             type += ";charset=" + forceEncoding;
511         }
512         this.contentType = type;
513         int charsetPos = type.toLowerCase ().indexOf ("charset=");
514         if (charsetPos > 0) {
515             encoding = type.toUpperCase ().substring (charsetPos + "charset=".length ()).trim ();
516         }
517         if (isPassThrough) {
518             super.setContentType (this.contentType);
519             try {
520                 ServletOutputStream JavaDoc outputStream = super.getResponse ().
521                         getOutputStream ();
522                 if (outputStream.getClass ().getName ().equals (
523                         "weblogic.servlet.internal.ServletOutputStreamImpl")) {
524                     Object JavaDoc o = outputStream.getClass ().getMethod ("getOutput",
525                             new Class JavaDoc[]{}).invoke (outputStream, new Object JavaDoc[]{});
526                     o.getClass ().getMethod ("changeToCharset",
527                             new Class JavaDoc[]{String JavaDoc.class,
528                                         Class.
529                             forName ("weblogic.servlet.internal.CharsetMap")}).
530                             invoke (o, new Object JavaDoc[]{null, null});
531                 }
532             } catch (Exception JavaDoc e) {
533             }
534         } else {
535             logger.debug (
536                     "Not setting parent response object because this wrapper is not in pass-through mode");
537         }
538     }
539
540     /**
541      * Returns the stored content type.
542      *
543      * @return a string containing the set contained type, or null if none
544      * was ever set.
545      */

546     public String JavaDoc getContentType () {
547         return this.contentType;
548     }
549
550     //--------------------------------------------------------------------------
551
/**
552      * Return the second id Part ( = the field id ) in the Application ID Str
553      *
554      * @param String Application ID Str
555      *
556      * @return String The Second ID part or null if not matching
557      *
558      * @author NK
559      */

560     public static String JavaDoc getFieldIDPart (String JavaDoc appUniqueIDStr) {
561
562         if (appUniqueIDStr == null) {
563             return null;
564         }
565
566         mRExpFieldID.match (appUniqueIDStr);
567         return mRExpFieldID.getParen (1);
568     }
569
570     public void addCookie (Cookie JavaDoc cookie) {
571         logger.debug ("Adding cookie name=" + cookie.getName ());
572         super.addCookie (cookie);
573     }
574
575     private void checkStreams () {
576         if ((strOutputStream == null) && (strPrintWriter == null)) {
577             try {
578                 // strPrintWriter = new StringPrintWriter(new StringWriter(), outputStringBuffer);
579
if (isPassThrough) {
580                     logger.debug (
581                             "Creating output streams for response wrapper using pass-through servlet output stream...");
582                     strOutputStream =
583                             new StringServletOutputStream (
584                                     super.getResponse ().getOutputStream (), encoding);
585                 } else {
586                     logger.debug (
587                             "Creating output streams for response wrapper using only stringbuffers and no pass-through...");
588                     strOutputStream = new StringServletOutputStream (encoding);
589                 }
590                 OutputStreamWriter JavaDoc streamWriter;
591                 if (encoding != null) {
592                     logger.debug ("Using PrintWriter with encoding : " + encoding);
593                     streamWriter = new OutputStreamWriter JavaDoc (strOutputStream, encoding);
594                 } else {
595                     streamWriter = new OutputStreamWriter JavaDoc (strOutputStream);
596                 }
597                 strPrintWriter = new PrintWriter JavaDoc (streamWriter, true);
598             } catch (Exception JavaDoc e) {
599                 logger.debug ("Error creating StringPrintWriter object !", e);
600             }
601         }
602     }
603
604
605 }
606
Popular Tags