KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > bridge > jsp > taglib > pageflow > IncludeTag


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.bridge.jsp.taglib.pageflow;
11
12 import org.mmbase.bridge.jsp.taglib.util.Attribute;
13 import org.mmbase.bridge.jsp.taglib.util.Referids;
14 import org.mmbase.bridge.jsp.taglib.util.Notfound;
15 import org.mmbase.bridge.jsp.taglib.TaglibException;
16 import org.mmbase.bridge.jsp.taglib.ContextTag;
17 import org.mmbase.bridge.NotFoundException;
18 import java.net.*;
19 //import javax.net.ssl.*;
20
import java.io.*;
21 import javax.servlet.jsp.JspTagException JavaDoc;
22 import javax.servlet.jsp.tagext.BodyContent JavaDoc;
23 import javax.servlet.http.*;
24 import javax.servlet.*;
25
26 import java.util.*;
27
28 import org.mmbase.util.*;
29 import org.mmbase.util.logging.Logger;
30 import org.mmbase.util.logging.Logging;
31
32 /**
33  * Like UrlTag, but does not spit out an URL, but the page itself.
34  *
35  * @author Michiel Meeuwissen
36  * @author Johannes Verelst
37  * @version $Id: IncludeTag.java,v 1.66.2.1 2006/11/15 19:49:59 michiel Exp $
38  */

39
40 public class IncludeTag extends UrlTag {
41
42     private static final Logger log = Logging.getLoggerInstance(IncludeTag.class);
43     private static final Logger pageLog = Logging.getLoggerInstance(Logging.PAGE_CATEGORY);
44
45     private static final int DEBUG_NONE = 0;
46     private static final int DEBUG_HTML = 1;
47     private static final int DEBUG_CSS = 2;
48     private static final int DEBUG_XML = 3;
49
50     public static final String JavaDoc INCLUDE_PATH_KEY = "javax.servlet.include.servlet_path";
51     public static final String JavaDoc INCLUDE_LEVEL_KEY = "org.mmbase.taglib.includeLevel";
52
53
54     protected Attribute debugType = Attribute.NULL;
55
56     private Attribute cite = Attribute.NULL;
57
58     private Attribute encodingAttribute = Attribute.NULL;
59
60     private Attribute attributes = Attribute.NULL;
61
62     protected Attribute notFound = Attribute.NULL;
63
64     protected Attribute resource = Attribute.NULL;
65
66
67     /**
68      * Test whether or not the 'cite' parameter is set
69      */

70     public void setCite(String JavaDoc c) throws JspTagException JavaDoc {
71         cite = getAttribute(c);
72     }
73
74     public void setEncoding(String JavaDoc e) throws JspTagException JavaDoc {
75         encodingAttribute = getAttribute(e);
76     }
77
78     public void setNotfound(String JavaDoc n) throws JspTagException JavaDoc {
79         notFound = getAttribute(n);
80     }
81
82     protected boolean getCite() throws JspTagException JavaDoc {
83         return resource != Attribute.NULL || cite.getBoolean(this, false);
84     }
85
86     public void setAttributes(String JavaDoc a) throws JspTagException JavaDoc {
87         attributes = getAttribute(a);
88     }
89
90     public void setResource(String JavaDoc r) throws JspTagException JavaDoc {
91         resource = getAttribute(r);
92     }
93
94     protected String JavaDoc getPage() throws JspTagException JavaDoc {
95         if (resource != Attribute.NULL) return resource.getString(this);
96         return super.getPage();
97     }
98
99     public int doStartTag() throws JspTagException JavaDoc {
100         if (page == Attribute.NULL && resource == Attribute.NULL) { // for include tags, page attribute is obligatory.
101
throw new JspTagException JavaDoc("No attribute 'page' or 'resource' was specified");
102         }
103         return super.doStartTag();
104     }
105
106     protected void doAfterBodySetValue() throws JspTagException JavaDoc {
107         includePage();
108     }
109     /**
110      * Opens an Http Connection, retrieves the page, and returns the result.
111      **/

112     private void external(BodyContent JavaDoc bodyContent, String JavaDoc absoluteUrl, HttpServletRequest request, HttpServletResponse response) throws JspTagException JavaDoc {
113         if (log.isDebugEnabled()) {
114             log.debug("External: found url: >" + absoluteUrl + "<");
115         }
116         try {
117             URL includeURL = new URL(absoluteUrl);
118
119             HttpURLConnection connection = (HttpURLConnection) includeURL.openConnection();
120
121             if (request != null) {
122                 // Also propagate the cookies (like the jsession...)
123
// Then these, and the session, also can be used in the include-d page
124
Cookie[] cookies = request.getCookies();
125                 if (cookies != null) {
126                     StringBuffer JavaDoc koekjes = new StringBuffer JavaDoc();
127                     for (int i=0; i < cookies.length; i++) {
128                         if (log.isDebugEnabled()) {
129                             log.debug("setting cookie " + i + ":" + cookies[i].getName() + "=" + cookies[i].getValue());
130                         }
131                         koekjes.append((i > 0 ? ";" : "")).append(cookies[i].getName()).append("=").append(cookies[i].getValue());
132                     }
133                     connection.setRequestProperty("Cookie", koekjes.toString());
134                 }
135             }
136
137             String JavaDoc result;
138             int responseCode;
139             try {
140                 responseCode = connection.getResponseCode();
141                 // how about responsecodes < 200?
142
if (responseCode < 300) {
143
144                     String JavaDoc encoding = encodingAttribute.getString(this);
145                     if (encoding.equals("")) {
146                         encoding = connection.getContentEncoding();
147                     }
148                     log.debug("Found content encoding " + encoding);
149                     ByteArrayOutputStream bytes = new ByteArrayOutputStream();
150                     InputStream inputStream = connection.getInputStream();
151                     int c = inputStream.read();
152                     while (c != -1) {
153                         bytes.write(c);
154                         c = inputStream.read();
155                     }
156                     byte[] allBytes = bytes.toByteArray();
157                     if (encoding == null || encoding.equals("")) {
158                         String JavaDoc contentType = connection.getContentType();
159                         if (contentType != null) {
160                             // according to http://www.w3.org/TR/2002/NOTE-xhtml-media-types-20020801/, 'higher level' charset indication should prevail
161
encoding = GenericResponseWrapper.getEncoding(contentType);
162                         }
163
164                         if (encoding == null && contentType != null) { // take a default based on the content type
165
encoding = GenericResponseWrapper.getDefaultEncoding(contentType);
166                         }
167                         if (encoding.equals(GenericResponseWrapper.TEXT_XML_DEFAULT_CHARSET)) { // if content-type is text/xml the body should be US-ASCII, which we will ignore and evalute the body. See comments in GenericResponseWrapper#getDefaultEncoding.
168
encoding = GenericResponseWrapper.getXMLEncoding(allBytes); // Will detect if body is XML, and set encoding to something if it is, otherwise, remains null.
169
}
170
171                     }
172                     log.debug("Using " + encoding);
173                     result = new String JavaDoc(allBytes, encoding) + debugEnd(absoluteUrl);
174
175                 } else {
176                     if (responseCode >= 500) {
177                         result = "Server error " + responseCode + " during mm:include of " + includeURL + " " + connection.getResponseMessage();
178                     } else if (responseCode >= 400) {
179                         result = "Client error " + responseCode + " during mm:include of " + includeURL + " " + connection.getResponseMessage();
180                     } else { // >= 300 < 400
181
result = "Redirect " + responseCode + " during mm:include of " + includeURL + " " + connection.getResponseMessage() + " " + connection.getInstanceFollowRedirects();
182                     }
183                 }
184             } catch (java.net.ConnectException JavaDoc ce) {
185                 result = "For " + includeURL + ": " + ce.getMessage();
186                 responseCode = -1;
187             }
188
189             handleResponse(responseCode, result, absoluteUrl);
190
191             if (log.isDebugEnabled()) {
192                 log.debug("found string: " + helper.getValue());
193             }
194
195         } catch (IOException e) {
196             throw new TaglibException (e.getMessage(), e);
197         }
198     }
199
200     /**
201      * Include a local file by doing a new HTTP request
202      * Do not use this method, but use the 'internal()' method instead
203      */

204     private void externalRelative(BodyContent JavaDoc bodyContent, String JavaDoc relativeUrl, HttpServletRequest request, HttpServletResponse response) throws JspTagException JavaDoc {
205         external(bodyContent,
206                  request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + relativeUrl,
207                  request, response);
208     }
209
210
211     protected boolean addContext() {
212         return false;
213     }
214
215     /**
216      * @since MMBase-1.8
217      */

218     protected void handleResponse(int code, String JavaDoc result, String JavaDoc url) throws JspTagException JavaDoc {
219
220         String JavaDoc page;
221         switch(code) {
222         case 200:
223             page = result;
224             break;
225         default:
226         case 404:
227             switch(Notfound.get(notFound, this)) {
228             case Notfound.SKIP:
229             case Notfound.PROVIDENULL:
230                 page = "";
231                 break;
232             case Notfound.THROW:
233                 if ("".equals(result)) result = "The requested resource '" + url + "' is not available";
234                 throw new JspTagException JavaDoc(result);
235             default:
236             case Notfound.DEFAULT:
237             case Notfound.MESSAGE:
238                 if ("".equals(result)) result = "The requested resource '" + url + "' is not available";
239                 page = result;
240             }
241             break;
242         }
243         helper.setValue(debugStart(url) + page + debugEnd(url));
244     }
245     /**
246      * Use the RequestDispatcher to include a page without doing a request.
247      * Encoding apparently work, but why they do isn't very clear.
248      */

249     private void internal(BodyContent JavaDoc bodyContent, String JavaDoc relativeUrl, HttpServletRequest req, HttpServletResponse resp) throws JspTagException JavaDoc {
250         if (log.isDebugEnabled()) {
251             log.debug("Internal: found url: >" + relativeUrl + "<");
252             String JavaDoc targetEncoding = resp.getCharacterEncoding();
253             log.debug("encoding: " + targetEncoding);
254             log.debug("req Parameters");
255             Map params = req.getParameterMap();
256             Iterator i = params.entrySet().iterator();
257             Object JavaDoc o;
258             while (i.hasNext()) {
259                 Map.Entry e = (Map.Entry) i.next();
260                 o = e.getValue();
261                 if (o instanceof String JavaDoc[]) {
262                     log.debug("key '" + e.getKey() + "' value '" + Arrays.asList((String JavaDoc[]) o) + "'");
263                 } else {
264                     log.debug("key '" + e.getKey() + "' value '" + o.toString() + "'");
265                 }
266             }
267         }
268
269         req.removeAttribute(ContextTag.CONTEXTTAG_KEY);
270
271         if (attributes != Attribute.NULL) {
272             Iterator i = Referids.getReferids(attributes, this).entrySet().iterator();
273             while (i.hasNext()) {
274                 Map.Entry entry = (Map.Entry) i.next();
275                 req.setAttribute((String JavaDoc) entry.getKey(), entry.getValue());
276             }
277
278         }
279         // Orion bug fix.
280
req.getParameterMap();
281
282         HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(req);
283
284         try {
285             ServletContext sc = pageContext.getServletContext();
286             if (sc == null) log.error("Cannot retrieve ServletContext from PageContext");
287             RequestDispatcher requestDispatcher = sc.getRequestDispatcher(relativeUrl);
288             if (requestDispatcher == null) {
289                 throw new NotFoundException("Page \"" + relativeUrl + "\" does not exist (No request-dispatcher could be created)");
290             }
291
292             IncludeWrapper responseWrapper;
293             String JavaDoc encoding = encodingAttribute.getString(this);
294             if (encoding.equals("")) {
295                 responseWrapper = new IncludeWrapper(resp);
296             } else {
297                 responseWrapper = new IncludeWrapper(resp, encoding);
298             }
299             requestDispatcher.include(requestWrapper, responseWrapper);
300
301             handleResponse(responseWrapper.getStatus(), responseWrapper.toString(), relativeUrl);
302
303
304         } catch (Throwable JavaDoc e) {
305             log.error(relativeUrl + " " + Logging.stackTrace(e));
306             throw new TaglibException(relativeUrl + " " + e.getMessage(), e);
307         }
308
309         if (log.isDebugEnabled()) {
310             log.debug("req Parameters");
311             Map params = req.getParameterMap();
312             Iterator i = params.entrySet().iterator();
313             while (i.hasNext()) {
314                 Map.Entry e = (Map.Entry) i.next();
315                 log.debug("key '" + e.getKey() + "' value '" + e.getValue() + "'");
316             }
317         }
318     }
319
320
321
322     /**
323      * When staying in the same web-application, then the file also can be found on the file system,
324      * and the possibility arises simply citing it (passing the web-server). It is in no way
325      * interpreted then. This can be useful when creating example pages.
326      * @param bodyContent unused
327      * @param relativeUrl URL to cite relative to root of web-app.
328      * @param request unused
329      */

330     private void cite(BodyContent JavaDoc bodyContent, String JavaDoc relativeUrl, HttpServletRequest request) throws JspTagException JavaDoc {
331         try {
332             if (log.isDebugEnabled()) log.trace("Citing " + relativeUrl);
333             if (resource == Attribute.NULL) {
334                 if (relativeUrl.indexOf("..") > -1 || relativeUrl.toUpperCase().indexOf("WEB-INF") > -1) { // toUpperCase: just for windows, of course
335
throw new JspTagException JavaDoc("Not allowed to cite " + relativeUrl);
336                 }
337             }
338
339             // take of the sessionid if it is present
340
//HttpSession session = request.getSession(false);
341
//if (session != null && session.isNew())
342
{ // means there is a ;jsession argument
343
int j = relativeUrl.lastIndexOf(';');
344                 if (j != -1) {
345                     relativeUrl = relativeUrl.substring(0, j);
346                 }
347
348             }
349
350
351             String JavaDoc resource = relativeUrl;
352             if (log.isDebugEnabled()) log.debug("Citing " + resource);
353
354
355             Reader reader = ResourceLoader.getWebRoot().getReader(resource);
356             if (reader == null) {
357                 handleResponse(404, "No such resource " + resource, resource);
358             } else {
359                 StringWriter writer = new StringWriter();
360                 while (true) {
361                     int c = reader.read();
362                     if (c == -1) break;
363                     writer.write(c);
364                 }
365                 handleResponse(200, writer.toString(), resource);
366             }
367
368         } catch (IOException e) {
369             throw new TaglibException (e);
370         }
371     }
372
373     /**
374      * Includes another page in the current page.
375      */

376     protected void includePage() throws JspTagException JavaDoc {
377         String JavaDoc gotUrl = null;
378         try {
379             gotUrl = getUrl(false, false); // false, false: don't write &amp; tags but real & and don't urlEncode
380

381             if (gotUrl == null || "".equals(gotUrl)) {
382                 return; //if there is no url, we cannot include
383
}
384
385             if (pageLog.isServiceEnabled()) {
386                 pageLog.service("Parsing mm:include JSP page: " + gotUrl);
387             }
388
389             // Do some things to make the URL absolute.
390
String JavaDoc nudeUrl; // url withouth the params
391
String JavaDoc params; // only the params.
392
int paramsIndex = gotUrl.indexOf('?');
393             if (paramsIndex != -1) {
394                 nudeUrl = gotUrl.substring(0, paramsIndex);
395                 params = gotUrl.substring(paramsIndex);
396             } else {
397                 nudeUrl = gotUrl;
398                 params = "";
399             }
400             if (log.isDebugEnabled()) {
401                 log.debug("Found nude url " + nudeUrl);
402             }
403             HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
404             HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
405
406
407             if (nudeUrl.indexOf(':') == -1) { // relative
408
// Fetch include level from Attributes, mainly for debugging
409
Integer JavaDoc level = (Integer JavaDoc) request.getAttribute(INCLUDE_LEVEL_KEY);
410                 int includeLevel;
411                 if (level == null) {
412                     includeLevel = 0;
413                 } else {
414                     includeLevel = level.intValue();
415                 }
416
417                 // Fetch the current servlet from request attribute.
418
// This is needed when we are resolving relatively.
419
String JavaDoc includingServlet = (String JavaDoc) request.getAttribute(INCLUDE_PATH_KEY);
420                 if (includingServlet == null) {
421                     includingServlet = request.getServletPath();
422                 }
423                 if (log.isDebugEnabled()) {
424                     log.debug("Including from : Level=" + includeLevel + " URI=" + includingServlet);
425                 }
426
427                 String JavaDoc includedServlet;
428                 if (nudeUrl.startsWith("/")) {
429                     log.debug("URL was absolute on servletcontext");
430                     includedServlet = gotUrl;
431                 } else {
432                     log.debug("URL was relative");
433                     // Using url-objects only because they know how to resolve relativity
434
URL u = new URL("http", "localhost", includingServlet);
435                     URL dir = new URL(u, "."); // directory
436

437                     File currentDir = new File(includingServlet + "includetagpostfix"); // to make sure that it is not a directory (tomcat 5 does not redirect then)
438
nudeUrl = new URL(dir, nudeUrl).getFile();
439                     includedServlet = nudeUrl + params;
440                 }
441
442                 // Increase level and put it together with the new URI in the Attributes of the request
443
includeLevel++;
444                 request.setAttribute(INCLUDE_LEVEL_KEY, new Integer JavaDoc(includeLevel));
445
446                 if (log.isDebugEnabled()) {
447                     log.debug("Next Include: Level=" + includeLevel + " URI=" + includedServlet);
448                 }
449
450                 if (getCite()) {
451                     cite(bodyContent, includedServlet, request);
452                 } else {
453                     internal(bodyContent, includedServlet, request, response);
454                 }
455                 // Reset include level and URI to previous state
456
includeLevel--;
457                 if (includeLevel == 0) {
458                     request.removeAttribute(INCLUDE_LEVEL_KEY);
459                 } else {
460                     request.setAttribute(INCLUDE_LEVEL_KEY, new Integer JavaDoc(includeLevel));
461                 }
462
463             } else { // really absolute
464
if (getCite()) {
465                     cite(bodyContent, gotUrl, request);
466                 } else {
467                     external(bodyContent, gotUrl, null, response); // null: no need to give cookies to external url
468
// also no need to encode the URL.
469
}
470             }
471
472         } catch (IOException e) {
473             throw new TaglibException (e);
474         }
475         if (pageLog.isDebugEnabled()) {
476             pageLog.debug("END Parsing mm:include JSP page " + gotUrl);
477         }
478     }
479
480     /**
481      * With debug attribute you can write the urls in comments to the page, just before and after
482      * the included page.
483      */

484     public void setDebug(String JavaDoc p) throws JspTagException JavaDoc {
485         debugType = getAttribute(p);
486     }
487
488     protected int getDebug() throws JspTagException JavaDoc {
489
490         if (debugType == Attribute.NULL) return DEBUG_NONE;
491
492         String JavaDoc dtype = debugType.getString(this).toLowerCase();
493         if (dtype.equals("none")) {
494             return DEBUG_NONE; // also implement the default, then people can use a variable
495
// to select this property in their jsp pages.
496
} else if (dtype.equals("html")) {
497             return DEBUG_HTML;
498         } else if (dtype.equals("xml")) {
499             return DEBUG_XML;
500         } else if (dtype.equals("css")) {
501             return DEBUG_CSS;
502         } else {
503             throw new JspTagException JavaDoc("Unknow value for debug attribute " + dtype);
504         }
505     }
506
507     /**
508      * Returns a name for this tag, that must appear in the debug message (in the comments)
509      */

510     protected String JavaDoc getThisName() {
511         String JavaDoc clazz = this.getClass().getName();
512         return clazz.substring(clazz.lastIndexOf(".") + 1);
513     }
514
515     /**
516      * Write the comment that is just above the include page.
517      */

518     private String JavaDoc debugStart(String JavaDoc url) throws JspTagException JavaDoc {
519         switch(getDebug()) {
520         case DEBUG_NONE: return "";
521         case DEBUG_HTML:
522             return "\n<!-- " + getThisName() + " page = '" + url + "' -->\n";
523         case DEBUG_XML:
524             return "<!-- " + getThisName() + " page = '" + url + "' -->";
525         case DEBUG_CSS: return "\n/* " + getThisName() + " page = '" + url + "' */\n";
526         default: return "";
527         }
528     }
529
530     /**
531      * Write the comment that is just below the include page.
532      */

533     private String JavaDoc debugEnd(String JavaDoc url) throws JspTagException JavaDoc {
534         switch(getDebug()) {
535         case DEBUG_NONE: return "";
536         case DEBUG_HTML:
537             return "\n<!-- END " + getThisName() + " page = '" + url + "' -->\n";
538         case DEBUG_XML:
539             return "<!-- END " + getThisName() + " page = '" + url + "' -->";
540         case DEBUG_CSS: return "\n/* END " + getThisName() + " page = '" + url + "' */\n";
541         default: return "";
542         }
543     }
544     private static class IncludeWrapper extends GenericResponseWrapper {
545         int includeStatus = 200;
546         public IncludeWrapper(HttpServletResponse resp) {
547             super(resp);
548         }
549         public IncludeWrapper(HttpServletResponse resp, String JavaDoc encoding) {
550             super(resp, encoding);
551         }
552
553         // don't wrap status to including request.
554
public void setStatus(int status) {
555             includeStatus = status;
556         }
557         public void sendError(int sc, String JavaDoc mes) {
558             includeStatus = sc;
559         }
560         public void sendError(int sc) {
561             includeStatus = sc;
562         }
563         public int getStatus() {
564             return includeStatus;
565         }
566
567     }
568 }
569
Popular Tags