Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » servlet » [javadoc | source]
    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.FileNotFoundException;
   21   import java.io.IOException;
   22   import java.net.URL;
   23   
   24   import javax.servlet.Servlet;
   25   import javax.servlet.ServletConfig;
   26   import javax.servlet.ServletContext;
   27   import javax.servlet.ServletException;
   28   import javax.servlet.SingleThreadModel;
   29   import javax.servlet.UnavailableException;
   30   import javax.servlet.http.HttpServletRequest;
   31   import javax.servlet.http.HttpServletResponse;
   32   import javax.servlet.jsp.tagext.TagInfo;
   33   
   34   import org.apache.AnnotationProcessor;
   35   import org.apache.jasper.JasperException;
   36   import org.apache.jasper.JspCompilationContext;
   37   import org.apache.jasper.Options;
   38   import org.apache.jasper.compiler.ErrorDispatcher;
   39   import org.apache.jasper.compiler.JavacErrorDetail;
   40   import org.apache.jasper.compiler.JspRuntimeContext;
   41   import org.apache.jasper.compiler.Localizer;
   42   import org.apache.jasper.runtime.JspSourceDependent;
   43   import org.apache.juli.logging.Log;
   44   import org.apache.juli.logging.LogFactory;
   45   
   46   /**
   47    * The JSP engine (a.k.a Jasper).
   48    *
   49    * The servlet container is responsible for providing a
   50    * URLClassLoader for the web application context Jasper
   51    * is being used in. Jasper will try get the Tomcat
   52    * ServletContext attribute for its ServletContext class
   53    * loader, if that fails, it uses the parent class loader.
   54    * In either case, it must be a URLClassLoader.
   55    *
   56    * @author Anil K. Vijendran
   57    * @author Harish Prabandham
   58    * @author Remy Maucherat
   59    * @author Kin-man Chung
   60    * @author Glenn Nielsen
   61    * @author Tim Fennell
   62    */
   63   
   64   public class JspServletWrapper {
   65   
   66       // Logger
   67       private Log log = LogFactory.getLog(JspServletWrapper.class);
   68   
   69       private Servlet theServlet;
   70       private String jspUri;
   71       private Class servletClass;
   72       private Class tagHandlerClass;
   73       private JspCompilationContext ctxt;
   74       private long available = 0L;
   75       private ServletConfig config;
   76       private Options options;
   77       private boolean firstTime = true;
   78       private boolean reload = true;
   79       private boolean isTagFile;
   80       private int tripCount;
   81       private JasperException compileException;
   82       private long servletClassLastModifiedTime;
   83       private long lastModificationTest = 0L;
   84   
   85       /*
   86        * JspServletWrapper for JSP pages.
   87        */
   88       public JspServletWrapper(ServletConfig config, Options options, String jspUri,
   89                         boolean isErrorPage, JspRuntimeContext rctxt)
   90               throws JasperException {
   91   
   92   	this.isTagFile = false;
   93           this.config = config;
   94           this.options = options;
   95           this.jspUri = jspUri;
   96           ctxt = new JspCompilationContext(jspUri, isErrorPage, options,
   97   					 config.getServletContext(),
   98   					 this, rctxt);
   99       }
  100   
  101       /*
  102        * JspServletWrapper for tag files.
  103        */
  104       public JspServletWrapper(ServletContext servletContext,
  105   			     Options options,
  106   			     String tagFilePath,
  107   			     TagInfo tagInfo,
  108   			     JspRuntimeContext rctxt,
  109   			     URL tagFileJarUrl)
  110   	    throws JasperException {
  111   
  112   	this.isTagFile = true;
  113           this.config = null;	// not used
  114           this.options = options;
  115   	this.jspUri = tagFilePath;
  116   	this.tripCount = 0;
  117           ctxt = new JspCompilationContext(jspUri, tagInfo, options,
  118   					 servletContext, this, rctxt,
  119   					 tagFileJarUrl);
  120       }
  121   
  122       public JspCompilationContext getJspEngineContext() {
  123           return ctxt;
  124       }
  125   
  126       public void setReload(boolean reload) {
  127           this.reload = reload;
  128       }
  129   
  130       public Servlet getServlet()
  131           throws ServletException, IOException, FileNotFoundException
  132       {
  133           if (reload) {
  134               synchronized (this) {
  135                   // Synchronizing on jsw enables simultaneous loading
  136                   // of different pages, but not the same page.
  137                   if (reload) {
  138                       // This is to maintain the original protocol.
  139                       destroy();
  140                       
  141                       Servlet servlet = null;
  142                       
  143                       try {
  144                           servletClass = ctxt.load();
  145                           servlet = (Servlet) servletClass.newInstance();
  146                           AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
  147                           if (annotationProcessor != null) {
  148                              annotationProcessor.processAnnotations(servlet);
  149                              annotationProcessor.postConstruct(servlet);
  150                           }
  151                       } catch (IllegalAccessException e) {
  152                           throw new JasperException(e);
  153                       } catch (InstantiationException e) {
  154                           throw new JasperException(e);
  155                       } catch (Exception e) {
  156                           throw new JasperException(e);
  157                       }
  158                       
  159                       servlet.init(config);
  160   
  161                       if (!firstTime) {
  162                           ctxt.getRuntimeContext().incrementJspReloadCount();
  163                       }
  164   
  165                       theServlet = servlet;
  166                       reload = false;
  167                   }
  168               }    
  169           }
  170           return theServlet;
  171       }
  172   
  173       public ServletContext getServletContext() {
  174           return config.getServletContext();
  175       }
  176   
  177       /**
  178        * Sets the compilation exception for this JspServletWrapper.
  179        *
  180        * @param je The compilation exception
  181        */
  182       public void setCompilationException(JasperException je) {
  183           this.compileException = je;
  184       }
  185   
  186       /**
  187        * Sets the last-modified time of the servlet class file associated with
  188        * this JspServletWrapper.
  189        *
  190        * @param lastModified Last-modified time of servlet class
  191        */
  192       public void setServletClassLastModifiedTime(long lastModified) {
  193           if (this.servletClassLastModifiedTime < lastModified) {
  194               synchronized (this) {
  195                   if (this.servletClassLastModifiedTime < lastModified) {
  196                       this.servletClassLastModifiedTime = lastModified;
  197                       reload = true;
  198                   }
  199               }
  200           }
  201       }
  202   
  203       /**
  204        * Compile (if needed) and load a tag file
  205        */
  206       public Class loadTagFile() throws JasperException {
  207   
  208           try {
  209               if (ctxt.isRemoved()) {
  210                   throw new FileNotFoundException(jspUri);
  211               }
  212               if (options.getDevelopment() || firstTime ) {
  213                   synchronized (this) {
  214                       firstTime = false;
  215                       ctxt.compile();
  216                   }
  217               } else {
  218                   if (compileException != null) {
  219                       throw compileException;
  220                   }
  221               }
  222   
  223               if (reload) {
  224                   tagHandlerClass = ctxt.load();
  225                   reload = false;
  226               }
  227           } catch (FileNotFoundException ex) {
  228               throw new JasperException(ex);
  229   	}
  230   
  231   	return tagHandlerClass;
  232       }
  233   
  234       /**
  235        * Compile and load a prototype for the Tag file.  This is needed
  236        * when compiling tag files with circular dependencies.  A prototpe
  237        * (skeleton) with no dependencies on other other tag files is
  238        * generated and compiled.
  239        */
  240       public Class loadTagFilePrototype() throws JasperException {
  241   
  242   	ctxt.setPrototypeMode(true);
  243   	try {
  244   	    return loadTagFile();
  245   	} finally {
  246   	    ctxt.setPrototypeMode(false);
  247   	}
  248       }
  249   
  250       /**
  251        * Get a list of files that the current page has source dependency on.
  252        */
  253       public java.util.List getDependants() {
  254           try {
  255               Object target;
  256               if (isTagFile) {
  257                   if (reload) {
  258                       tagHandlerClass = ctxt.load();
  259                       reload = false;
  260                   }
  261                   target = tagHandlerClass.newInstance();
  262               } else {
  263                   target = getServlet();
  264               }
  265               if (target != null && target instanceof JspSourceDependent) {
  266                   return ((java.util.List) ((JspSourceDependent) target).getDependants());
  267               }
  268           } catch (Throwable ex) {
  269           }
  270           return null;
  271       }
  272   
  273       public boolean isTagFile() {
  274   	return this.isTagFile;
  275       }
  276   
  277       public int incTripCount() {
  278   	return tripCount++;
  279       }
  280   
  281       public int decTripCount() {
  282   	return tripCount--;
  283       }
  284   
  285       public void service(HttpServletRequest request, 
  286                           HttpServletResponse response,
  287                           boolean precompile)
  288   	    throws ServletException, IOException, FileNotFoundException {
  289           
  290           try {
  291   
  292               if (ctxt.isRemoved()) {
  293                   throw new FileNotFoundException(jspUri);
  294               }
  295   
  296               if ((available > 0L) && (available < Long.MAX_VALUE)) {
  297                   if (available > System.currentTimeMillis()) {
  298                       response.setDateHeader("Retry-After", available);
  299                       response.sendError
  300                           (HttpServletResponse.SC_SERVICE_UNAVAILABLE,
  301                            Localizer.getMessage("jsp.error.unavailable"));
  302                       return;
  303                   } else {
  304                       // Wait period has expired. Reset.
  305                       available = 0;
  306                   }
  307               }
  308   
  309               /*
  310                * (1) Compile
  311                */
  312               if (options.getDevelopment() || firstTime ) {
  313                   synchronized (this) {
  314                       firstTime = false;
  315   
  316                       // The following sets reload to true, if necessary
  317                       ctxt.compile();
  318                   }
  319               } else {
  320                   if (compileException != null) {
  321                       // Throw cached compilation exception
  322                       throw compileException;
  323                   }
  324               }
  325   
  326               /*
  327                * (2) (Re)load servlet class file
  328                */
  329               getServlet();
  330   
  331               // If a page is to be precompiled only, return.
  332               if (precompile) {
  333                   return;
  334               }
  335   
  336           } catch (ServletException ex) {
  337               if (options.getDevelopment()) {
  338                   throw handleJspException(ex);
  339               } else {
  340                   throw ex;
  341               }
  342           } catch (IOException ex) {
  343               if (options.getDevelopment()) {
  344                   throw handleJspException(ex);
  345               } else {
  346                   throw ex;
  347               }
  348           } catch (IllegalStateException ex) {
  349               if (options.getDevelopment()) {
  350                   throw handleJspException(ex);
  351               } else {
  352                   throw ex;
  353               }
  354           } catch (Exception ex) {
  355               if (options.getDevelopment()) {
  356                   throw handleJspException(ex);
  357               } else {
  358                   throw new JasperException(ex);
  359               }
  360           }
  361   
  362           try {
  363               
  364               /*
  365                * (3) Service request
  366                */
  367               if (theServlet instanceof SingleThreadModel) {
  368                  // sync on the wrapper so that the freshness
  369                  // of the page is determined right before servicing
  370                  synchronized (this) {
  371                      theServlet.service(request, response);
  372                   }
  373               } else {
  374                   theServlet.service(request, response);
  375               }
  376   
  377           } catch (UnavailableException ex) {
  378               String includeRequestUri = (String)
  379                   request.getAttribute("javax.servlet.include.request_uri");
  380               if (includeRequestUri != null) {
  381                   // This file was included. Throw an exception as
  382                   // a response.sendError() will be ignored by the
  383                   // servlet engine.
  384                   throw ex;
  385               } else {
  386                   int unavailableSeconds = ex.getUnavailableSeconds();
  387                   if (unavailableSeconds <= 0) {
  388                       unavailableSeconds = 60;        // Arbitrary default
  389                   }
  390                   available = System.currentTimeMillis() +
  391                       (unavailableSeconds * 1000L);
  392                   response.sendError
  393                       (HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
  394                        ex.getMessage());
  395               }
  396           } catch (ServletException ex) {
  397               if(options.getDevelopment()) {
  398                   throw handleJspException(ex);
  399               } else {
  400                   throw ex;
  401               }
  402           } catch (IOException ex) {
  403               if(options.getDevelopment()) {
  404                   throw handleJspException(ex);
  405               } else {
  406                   throw ex;
  407               }
  408           } catch (IllegalStateException ex) {
  409               if(options.getDevelopment()) {
  410                   throw handleJspException(ex);
  411               } else {
  412                   throw ex;
  413               }
  414           } catch (Exception ex) {
  415               if(options.getDevelopment()) {
  416                   throw handleJspException(ex);
  417               } else {
  418                   throw new JasperException(ex);
  419               }
  420           }
  421       }
  422   
  423       public void destroy() {
  424           if (theServlet != null) {
  425               theServlet.destroy();
  426               AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
  427               if (annotationProcessor != null) {
  428                   try {
  429                       annotationProcessor.preDestroy(theServlet);
  430                   } catch (Exception e) {
  431                       // Log any exception, since it can't be passed along
  432                       log.error(Localizer.getMessage("jsp.error.file.not.found",
  433                              e.getMessage()), e);
  434                   }
  435               }
  436           }
  437       }
  438   
  439       /**
  440        * @return Returns the lastModificationTest.
  441        */
  442       public long getLastModificationTest() {
  443           return lastModificationTest;
  444       }
  445       /**
  446        * @param lastModificationTest The lastModificationTest to set.
  447        */
  448       public void setLastModificationTest(long lastModificationTest) {
  449           this.lastModificationTest = lastModificationTest;
  450       }
  451   
  452       /**
  453        * <p>Attempts to construct a JasperException that contains helpful information
  454        * about what went wrong. Uses the JSP compiler system to translate the line
  455        * number in the generated servlet that originated the exception to a line
  456        * number in the JSP.  Then constructs an exception containing that
  457        * information, and a snippet of the JSP to help debugging.
  458        * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and
  459        * http://www.tfenne.com/jasper/ for more details.
  460        *</p>
  461        *
  462        * @param ex the exception that was the cause of the problem.
  463        * @return a JasperException with more detailed information
  464        */
  465       protected JasperException handleJspException(Exception ex) {
  466           try {
  467               Throwable realException = ex;
  468               if (ex instanceof ServletException) {
  469                   realException = ((ServletException) ex).getRootCause();
  470               }
  471   
  472               // First identify the stack frame in the trace that represents the JSP
  473               StackTraceElement[] frames = realException.getStackTrace();
  474               StackTraceElement jspFrame = null;
  475   
  476               for (int i=0; i<frames.length; ++i) {
  477                   if ( frames[i].getClassName().equals(this.getServlet().getClass().getName()) ) {
  478                       jspFrame = frames[i];
  479                       break;
  480                   }
  481               }
  482   
  483               if (jspFrame == null) {
  484                   // If we couldn't find a frame in the stack trace corresponding
  485                   // to the generated servlet class, we can't really add anything
  486                   return new JasperException(ex);
  487               }
  488               else {
  489                   int javaLineNumber = jspFrame.getLineNumber();
  490                   JavacErrorDetail detail = ErrorDispatcher.createJavacError(
  491                           jspFrame.getMethodName(),
  492                           this.ctxt.getCompiler().getPageNodes(),
  493                           null,
  494                           javaLineNumber,
  495                           ctxt);
  496   
  497                   // If the line number is less than one we couldn't find out
  498                   // where in the JSP things went wrong
  499                   int jspLineNumber = detail.getJspBeginLineNumber();
  500                   if (jspLineNumber < 1) {
  501                       throw new JasperException(ex);
  502                   }
  503   
  504                   if (options.getDisplaySourceFragment()) {
  505                       return new JasperException(Localizer.getMessage
  506                               ("jsp.exception", detail.getJspFileName(),
  507                                       "" + jspLineNumber) +
  508                                       "\n\n" + detail.getJspExtract() +
  509                                       "\n\nStacktrace:", ex);
  510                       
  511                   } else {
  512                       return new JasperException(Localizer.getMessage
  513                               ("jsp.exception", detail.getJspFileName(),
  514                                       "" + jspLineNumber), ex);
  515                   }
  516               }
  517           } catch (Exception je) {
  518               // If anything goes wrong, just revert to the original behaviour
  519               if (ex instanceof JasperException) {
  520                   return (JasperException) ex;
  521               } else {
  522                   return new JasperException(ex);
  523               }
  524           }
  525       }
  526   
  527   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » servlet » [javadoc | source]