KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jasper > servlet > JspServletWrapper


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.jasper.servlet;
19
20 import java.io.BufferedReader JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileNotFoundException JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.InputStreamReader JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.List JavaDoc;
29
30 import javax.servlet.Servlet JavaDoc;
31 import javax.servlet.ServletConfig JavaDoc;
32 import javax.servlet.ServletContext JavaDoc;
33 import javax.servlet.ServletException JavaDoc;
34 import javax.servlet.SingleThreadModel JavaDoc;
35 import javax.servlet.UnavailableException JavaDoc;
36 import javax.servlet.http.HttpServletRequest JavaDoc;
37 import javax.servlet.http.HttpServletResponse JavaDoc;
38 import javax.servlet.jsp.tagext.TagInfo JavaDoc;
39
40 import org.apache.AnnotationProcessor;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.apache.jasper.JasperException;
44 import org.apache.jasper.JspCompilationContext;
45 import org.apache.jasper.Options;
46 import org.apache.jasper.compiler.ErrorDispatcher;
47 import org.apache.jasper.compiler.JavacErrorDetail;
48 import org.apache.jasper.compiler.JspRuntimeContext;
49 import org.apache.jasper.compiler.Localizer;
50 import org.apache.jasper.runtime.JspSourceDependent;
51
52 /**
53  * The JSP engine (a.k.a Jasper).
54  *
55  * The servlet container is responsible for providing a
56  * URLClassLoader for the web application context Jasper
57  * is being used in. Jasper will try get the Tomcat
58  * ServletContext attribute for its ServletContext class
59  * loader, if that fails, it uses the parent class loader.
60  * In either case, it must be a URLClassLoader.
61  *
62  * @author Anil K. Vijendran
63  * @author Harish Prabandham
64  * @author Remy Maucherat
65  * @author Kin-man Chung
66  * @author Glenn Nielsen
67  * @author Tim Fennell
68  */

69
70 public class JspServletWrapper {
71
72     // Logger
73
private Log log = LogFactory.getLog(JspServletWrapper.class);
74
75     private Servlet JavaDoc theServlet;
76     private String JavaDoc jspUri;
77     private Class JavaDoc servletClass;
78     private Class JavaDoc tagHandlerClass;
79     private JspCompilationContext ctxt;
80     private long available = 0L;
81     private ServletConfig JavaDoc config;
82     private Options options;
83     private boolean firstTime = true;
84     private boolean reload = true;
85     private boolean isTagFile;
86     private int tripCount;
87     private JasperException compileException;
88     private long servletClassLastModifiedTime;
89     private long lastModificationTest = 0L;
90
91     /*
92      * JspServletWrapper for JSP pages.
93      */

94     public JspServletWrapper(ServletConfig JavaDoc config, Options options, String JavaDoc jspUri,
95                       boolean isErrorPage, JspRuntimeContext rctxt)
96             throws JasperException {
97
98     this.isTagFile = false;
99         this.config = config;
100         this.options = options;
101         this.jspUri = jspUri;
102         ctxt = new JspCompilationContext(jspUri, isErrorPage, options,
103                      config.getServletContext(),
104                      this, rctxt);
105     }
106
107     /*
108      * JspServletWrapper for tag files.
109      */

110     public JspServletWrapper(ServletContext JavaDoc servletContext,
111                  Options options,
112                  String JavaDoc tagFilePath,
113                  TagInfo JavaDoc tagInfo,
114                  JspRuntimeContext rctxt,
115                  URL JavaDoc tagFileJarUrl)
116         throws JasperException {
117
118     this.isTagFile = true;
119         this.config = null; // not used
120
this.options = options;
121     this.jspUri = tagFilePath;
122     this.tripCount = 0;
123         ctxt = new JspCompilationContext(jspUri, tagInfo, options,
124                      servletContext, this, rctxt,
125                      tagFileJarUrl);
126     }
127
128     public JspCompilationContext getJspEngineContext() {
129         return ctxt;
130     }
131
132     public void setReload(boolean reload) {
133         this.reload = reload;
134     }
135
136     public Servlet JavaDoc getServlet()
137         throws ServletException JavaDoc, IOException JavaDoc, FileNotFoundException JavaDoc
138     {
139         if (reload) {
140             synchronized (this) {
141                 // Synchronizing on jsw enables simultaneous loading
142
// of different pages, but not the same page.
143
if (reload) {
144                     // This is to maintain the original protocol.
145
destroy();
146                     
147                     try {
148                         servletClass = ctxt.load();
149                         theServlet = (Servlet JavaDoc) servletClass.newInstance();
150                         AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
151                         if (annotationProcessor != null) {
152                            annotationProcessor.processAnnotations(theServlet);
153                            annotationProcessor.postConstruct(theServlet);
154                         }
155                     } catch (IllegalAccessException JavaDoc e) {
156                         throw new JasperException(e);
157                     } catch (InstantiationException JavaDoc e) {
158                         throw new JasperException(e);
159                     } catch (Exception JavaDoc e) {
160                         throw new JasperException(e);
161                     }
162                     
163                     theServlet.init(config);
164
165                     if (!firstTime) {
166                         ctxt.getRuntimeContext().incrementJspReloadCount();
167                     }
168
169                     reload = false;
170                 }
171             }
172         }
173         return theServlet;
174     }
175
176     public ServletContext JavaDoc getServletContext() {
177         return config.getServletContext();
178     }
179
180     /**
181      * Sets the compilation exception for this JspServletWrapper.
182      *
183      * @param je The compilation exception
184      */

185     public void setCompilationException(JasperException je) {
186         this.compileException = je;
187     }
188
189     /**
190      * Sets the last-modified time of the servlet class file associated with
191      * this JspServletWrapper.
192      *
193      * @param lastModified Last-modified time of servlet class
194      */

195     public void setServletClassLastModifiedTime(long lastModified) {
196         if (this.servletClassLastModifiedTime < lastModified) {
197             synchronized (this) {
198                 if (this.servletClassLastModifiedTime < lastModified) {
199                     this.servletClassLastModifiedTime = lastModified;
200                     reload = true;
201                 }
202             }
203         }
204     }
205
206     /**
207      * Compile (if needed) and load a tag file
208      */

209     public Class JavaDoc loadTagFile() throws JasperException {
210
211         try {
212             if (ctxt.isRemoved()) {
213                 throw new FileNotFoundException JavaDoc(jspUri);
214             }
215             if (options.getDevelopment() || firstTime ) {
216                 synchronized (this) {
217                     firstTime = false;
218                     ctxt.compile();
219                 }
220             } else {
221                 if (compileException != null) {
222                     throw compileException;
223                 }
224             }
225
226             if (reload) {
227                 tagHandlerClass = ctxt.load();
228                 reload = false;
229             }
230         } catch (FileNotFoundException JavaDoc ex) {
231             throw new JasperException(ex);
232     }
233
234     return tagHandlerClass;
235     }
236
237     /**
238      * Compile and load a prototype for the Tag file. This is needed
239      * when compiling tag files with circular dependencies. A prototpe
240      * (skeleton) with no dependencies on other other tag files is
241      * generated and compiled.
242      */

243     public Class JavaDoc loadTagFilePrototype() throws JasperException {
244
245     ctxt.setPrototypeMode(true);
246     try {
247         return loadTagFile();
248     } finally {
249         ctxt.setPrototypeMode(false);
250     }
251     }
252
253     /**
254      * Get a list of files that the current page has source dependency on.
255      */

256     public java.util.List JavaDoc getDependants() {
257         try {
258             Object JavaDoc target;
259             if (isTagFile) {
260                 if (reload) {
261                     tagHandlerClass = ctxt.load();
262                     reload = false;
263                 }
264                 target = tagHandlerClass.newInstance();
265             } else {
266                 target = getServlet();
267             }
268             if (target != null && target instanceof JspSourceDependent) {
269                 return ((java.util.List JavaDoc) ((JspSourceDependent) target).getDependants());
270             }
271         } catch (Throwable JavaDoc ex) {
272         }
273         return null;
274     }
275
276     public boolean isTagFile() {
277     return this.isTagFile;
278     }
279
280     public int incTripCount() {
281     return tripCount++;
282     }
283
284     public int decTripCount() {
285     return tripCount--;
286     }
287
288     public void service(HttpServletRequest JavaDoc request,
289                         HttpServletResponse JavaDoc response,
290                         boolean precompile)
291         throws ServletException JavaDoc, IOException JavaDoc, FileNotFoundException JavaDoc {
292         
293         try {
294
295             if (ctxt.isRemoved()) {
296                 throw new FileNotFoundException JavaDoc(jspUri);
297             }
298
299             if ((available > 0L) && (available < Long.MAX_VALUE)) {
300                 response.setDateHeader("Retry-After", available);
301                 response.sendError
302                     (HttpServletResponse.SC_SERVICE_UNAVAILABLE,
303                      Localizer.getMessage("jsp.error.unavailable"));
304             }
305
306             /*
307              * (1) Compile
308              */

309             if (options.getDevelopment() || firstTime ) {
310                 synchronized (this) {
311                     firstTime = false;
312
313                     // The following sets reload to true, if necessary
314
ctxt.compile();
315                 }
316             } else {
317                 if (compileException != null) {
318                     // Throw cached compilation exception
319
throw compileException;
320                 }
321             }
322
323             /*
324              * (2) (Re)load servlet class file
325              */

326             getServlet();
327
328             // If a page is to be precompiled only, return.
329
if (precompile) {
330                 return;
331             }
332
333         } catch (FileNotFoundException JavaDoc ex) {
334             ctxt.incrementRemoved();
335             String JavaDoc includeRequestUri = (String JavaDoc)
336                 request.getAttribute("javax.servlet.include.request_uri");
337             if (includeRequestUri != null) {
338                 // This file was included. Throw an exception as
339
// a response.sendError() will be ignored by the
340
// servlet engine.
341
throw new ServletException JavaDoc(ex);
342             } else {
343                 try {
344                     response.sendError(HttpServletResponse.SC_NOT_FOUND,
345                                       ex.getMessage());
346                 } catch (IllegalStateException JavaDoc ise) {
347                     log.error(Localizer.getMessage("jsp.error.file.not.found",
348                            ex.getMessage()),
349                   ex);
350                 }
351             }
352         } catch (ServletException JavaDoc ex) {
353             if (options.getDevelopment()) {
354                 throw handleJspException(ex);
355             } else {
356                 throw ex;
357             }
358         } catch (IOException JavaDoc ex) {
359             if (options.getDevelopment()) {
360                 throw handleJspException(ex);
361             } else {
362                 throw ex;
363             }
364         } catch (IllegalStateException JavaDoc ex) {
365             if (options.getDevelopment()) {
366                 throw handleJspException(ex);
367             } else {
368                 throw ex;
369             }
370         } catch (Exception JavaDoc ex) {
371             if (options.getDevelopment()) {
372                 throw handleJspException(ex);
373             } else {
374                 throw new JasperException(ex);
375             }
376         }
377
378         try {
379             
380             /*
381              * (3) Service request
382              */

383             if (theServlet instanceof SingleThreadModel JavaDoc) {
384                // sync on the wrapper so that the freshness
385
// of the page is determined right before servicing
386
synchronized (this) {
387                    theServlet.service(request, response);
388                 }
389             } else {
390                 theServlet.service(request, response);
391             }
392
393         } catch (UnavailableException JavaDoc ex) {
394             String JavaDoc includeRequestUri = (String JavaDoc)
395                 request.getAttribute("javax.servlet.include.request_uri");
396             if (includeRequestUri != null) {
397                 // This file was included. Throw an exception as
398
// a response.sendError() will be ignored by the
399
// servlet engine.
400
throw ex;
401             } else {
402                 int unavailableSeconds = ex.getUnavailableSeconds();
403                 if (unavailableSeconds <= 0) {
404                     unavailableSeconds = 60; // Arbitrary default
405
}
406                 available = System.currentTimeMillis() +
407                     (unavailableSeconds * 1000L);
408                 response.sendError
409                     (HttpServletResponse.SC_SERVICE_UNAVAILABLE,
410                      ex.getMessage());
411             }
412         } catch (ServletException JavaDoc ex) {
413             if(options.getDevelopment()) {
414                 throw handleJspException(ex);
415             } else {
416                 throw ex;
417             }
418         } catch (IOException JavaDoc ex) {
419             if(options.getDevelopment()) {
420                 throw handleJspException(ex);
421             } else {
422                 throw ex;
423             }
424         } catch (IllegalStateException JavaDoc ex) {
425             if(options.getDevelopment()) {
426                 throw handleJspException(ex);
427             } else {
428                 throw ex;
429             }
430         } catch (Exception JavaDoc ex) {
431             if(options.getDevelopment()) {
432                 throw handleJspException(ex);
433             } else {
434                 throw new JasperException(ex);
435             }
436         }
437     }
438
439     public void destroy() {
440         if (theServlet != null) {
441             theServlet.destroy();
442             AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
443             if (annotationProcessor != null) {
444                 try {
445                     annotationProcessor.preDestroy(theServlet);
446                 } catch (Exception JavaDoc e) {
447                     // Log any exception, since it can't be passed along
448
log.error(Localizer.getMessage("jsp.error.file.not.found",
449                            e.getMessage()), e);
450                 }
451             }
452         }
453     }
454
455     /**
456      * @return Returns the lastModificationTest.
457      */

458     public long getLastModificationTest() {
459         return lastModificationTest;
460     }
461     /**
462      * @param lastModificationTest The lastModificationTest to set.
463      */

464     public void setLastModificationTest(long lastModificationTest) {
465         this.lastModificationTest = lastModificationTest;
466     }
467
468     /**
469      * <p>Attempts to construct a JasperException that contains helpful information
470      * about what went wrong. Uses the JSP compiler system to translate the line
471      * number in the generated servlet that originated the exception to a line
472      * number in the JSP. Then constructs an exception containing that
473      * information, and a snippet of the JSP to help debugging.
474      * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and
475      * http://www.tfenne.com/jasper/ for more details.
476      *</p>
477      *
478      * @param ex the exception that was the cause of the problem.
479      * @return a JasperException with more detailed information
480      */

481     protected JasperException handleJspException(Exception JavaDoc ex) {
482         try {
483             Throwable JavaDoc realException = ex;
484             if (ex instanceof ServletException JavaDoc) {
485                 realException = ((ServletException JavaDoc) ex).getRootCause();
486             }
487
488             // First identify the stack frame in the trace that represents the JSP
489
StackTraceElement JavaDoc[] frames = realException.getStackTrace();
490             StackTraceElement JavaDoc jspFrame = null;
491
492             for (int i=0; i<frames.length; ++i) {
493                 if ( frames[i].getClassName().equals(this.getServlet().getClass().getName()) ) {
494                     jspFrame = frames[i];
495                     break;
496                 }
497             }
498
499             if (jspFrame == null) {
500                 // If we couldn't find a frame in the stack trace corresponding
501
// to the generated servlet class, we can't really add anything
502
return new JasperException(ex);
503             }
504             else {
505                 int javaLineNumber = jspFrame.getLineNumber();
506                 JavacErrorDetail detail = ErrorDispatcher.createJavacError(
507                                                                            jspFrame.getMethodName(),
508                                                                            this.ctxt.getCompiler().getPageNodes(),
509                                                                            null,
510                                                                            javaLineNumber);
511
512                 // If the line number is less than one we couldn't find out
513
// where in the JSP things went wrong
514
int jspLineNumber = detail.getJspBeginLineNumber();
515                 if (jspLineNumber < 1) {
516                     throw new JasperException(ex);
517                 }
518
519                 if (options.getDisplaySourceFragment()) {
520
521                     // Read both files in, so we can inspect them
522
String JavaDoc[] jspLines = readFile
523                     (this.ctxt.getResourceAsStream(this.ctxt.getJspFile()));
524
525                     String JavaDoc[] javaLines = readFile
526                     (new FileInputStream JavaDoc(this.ctxt.getServletJavaFileName()));
527
528                     // If the line contains the opening of a multi-line scriptlet
529
// block, then the JSP line number we got back is probably
530
// faulty. Scan forward to match the java line...
531
if (jspLines[jspLineNumber-1].lastIndexOf("<%") >
532                     jspLines[jspLineNumber-1].lastIndexOf("%>")) {
533                         String JavaDoc javaLine = javaLines[javaLineNumber-1].trim();
534
535                         for (int i=jspLineNumber-1; i<jspLines.length; i++) {
536                             if (jspLines[i].indexOf(javaLine) != -1) {
537                                 jspLineNumber = i+1;
538                                 break;
539                             }
540                         }
541                     }
542
543                     // copy out a fragment of JSP to display to the user
544
StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(1024);
545                     int startIndex = Math.max(0, jspLineNumber-1-3);
546                     int endIndex = Math.min(jspLines.length-1, jspLineNumber-1+3);
547
548                     for (int i=startIndex;i<=endIndex; ++i) {
549                         buffer.append(i+1);
550                         buffer.append(": ");
551                         buffer.append(jspLines[i]);
552                         buffer.append("\n");
553                     }
554
555                     return new JasperException(Localizer.getMessage
556                             ("jsp.exception", detail.getJspFileName(), "" + jspLineNumber) + "\n" + buffer, ex);
557                     
558                 } else {
559                     return new JasperException(Localizer.getMessage
560                             ("jsp.exception", detail.getJspFileName(), "" + jspLineNumber), ex);
561                 }
562             }
563         } catch (Exception JavaDoc je) {
564             // If anything goes wrong, just revert to the original behaviour
565
return new JasperException(ex);
566         }
567     }
568
569     /**
570      * Reads a text file from an input stream into a String[]. Used to read in
571      * the JSP and generated Java file when generating error messages.
572      */

573     private String JavaDoc[] readFile(InputStream JavaDoc s) throws IOException JavaDoc {
574         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(s));
575         List JavaDoc lines = new ArrayList JavaDoc();
576         String JavaDoc line;
577
578         while ( (line = reader.readLine()) != null ) {
579             lines.add(line);
580         }
581
582         return (String JavaDoc[]) lines.toArray( new String JavaDoc[lines.size()] );
583     }
584
585 }
586
Popular Tags