Save This Page
Home » apache-tomcat-6.0.26-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 ctxt.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 (FileNotFoundException fnfe) {
  343               // File has been removed. Let caller handle this.
  344               throw fnfe;
  345           } catch (IOException ex) {
  346               if (options.getDevelopment()) {
  347                   throw handleJspException(ex);
  348               } else {
  349                   throw ex;
  350               }
  351           } catch (IllegalStateException ex) {
  352               if (options.getDevelopment()) {
  353                   throw handleJspException(ex);
  354               } else {
  355                   throw ex;
  356               }
  357           } catch (Exception ex) {
  358               if (options.getDevelopment()) {
  359                   throw handleJspException(ex);
  360               } else {
  361                   throw new JasperException(ex);
  362               }
  363           }
  364   
  365           try {
  366               
  367               /*
  368                * (3) Service request
  369                */
  370               if (theServlet instanceof SingleThreadModel) {
  371                  // sync on the wrapper so that the freshness
  372                  // of the page is determined right before servicing
  373                  synchronized (this) {
  374                      theServlet.service(request, response);
  375                   }
  376               } else {
  377                   theServlet.service(request, response);
  378               }
  379   
  380           } catch (UnavailableException ex) {
  381               String includeRequestUri = (String)
  382                   request.getAttribute("javax.servlet.include.request_uri");
  383               if (includeRequestUri != null) {
  384                   // This file was included. Throw an exception as
  385                   // a response.sendError() will be ignored by the
  386                   // servlet engine.
  387                   throw ex;
  388               } else {
  389                   int unavailableSeconds = ex.getUnavailableSeconds();
  390                   if (unavailableSeconds <= 0) {
  391                       unavailableSeconds = 60;        // Arbitrary default
  392                   }
  393                   available = System.currentTimeMillis() +
  394                       (unavailableSeconds * 1000L);
  395                   response.sendError
  396                       (HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
  397                        ex.getMessage());
  398               }
  399           } catch (ServletException ex) {
  400               if(options.getDevelopment()) {
  401                   throw handleJspException(ex);
  402               } else {
  403                   throw ex;
  404               }
  405           } catch (IOException ex) {
  406               if(options.getDevelopment()) {
  407                   throw handleJspException(ex);
  408               } else {
  409                   throw ex;
  410               }
  411           } catch (IllegalStateException ex) {
  412               if(options.getDevelopment()) {
  413                   throw handleJspException(ex);
  414               } else {
  415                   throw ex;
  416               }
  417           } catch (Exception ex) {
  418               if(options.getDevelopment()) {
  419                   throw handleJspException(ex);
  420               } else {
  421                   throw new JasperException(ex);
  422               }
  423           }
  424       }
  425   
  426       public void destroy() {
  427           if (theServlet != null) {
  428               theServlet.destroy();
  429               AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
  430               if (annotationProcessor != null) {
  431                   try {
  432                       annotationProcessor.preDestroy(theServlet);
  433                   } catch (Exception e) {
  434                       // Log any exception, since it can't be passed along
  435                       log.error(Localizer.getMessage("jsp.error.file.not.found",
  436                              e.getMessage()), e);
  437                   }
  438               }
  439           }
  440       }
  441   
  442       /**
  443        * @return Returns the lastModificationTest.
  444        */
  445       public long getLastModificationTest() {
  446           return lastModificationTest;
  447       }
  448       /**
  449        * @param lastModificationTest The lastModificationTest to set.
  450        */
  451       public void setLastModificationTest(long lastModificationTest) {
  452           this.lastModificationTest = lastModificationTest;
  453       }
  454   
  455       /**
  456        * <p>Attempts to construct a JasperException that contains helpful information
  457        * about what went wrong. Uses the JSP compiler system to translate the line
  458        * number in the generated servlet that originated the exception to a line
  459        * number in the JSP.  Then constructs an exception containing that
  460        * information, and a snippet of the JSP to help debugging.
  461        * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and
  462        * http://www.tfenne.com/jasper/ for more details.
  463        *</p>
  464        *
  465        * @param ex the exception that was the cause of the problem.
  466        * @return a JasperException with more detailed information
  467        */
  468       protected JasperException handleJspException(Exception ex) {
  469           try {
  470               Throwable realException = ex;
  471               if (ex instanceof ServletException) {
  472                   realException = ((ServletException) ex).getRootCause();
  473               }
  474   
  475               // First identify the stack frame in the trace that represents the JSP
  476               StackTraceElement[] frames = realException.getStackTrace();
  477               StackTraceElement jspFrame = null;
  478   
  479               for (int i=0; i<frames.length; ++i) {
  480                   if ( frames[i].getClassName().equals(this.getServlet().getClass().getName()) ) {
  481                       jspFrame = frames[i];
  482                       break;
  483                   }
  484               }
  485   
  486               if (jspFrame == null ||
  487                       this.ctxt.getCompiler().getPageNodes() == null) {
  488                   // If we couldn't find a frame in the stack trace corresponding
  489                   // to the generated servlet class or we don't have a copy of the
  490                   // parsed JSP to hand, we can't really add anything
  491                   return new JasperException(ex);
  492               }
  493               else {
  494                   int javaLineNumber = jspFrame.getLineNumber();
  495                   JavacErrorDetail detail = ErrorDispatcher.createJavacError(
  496                           jspFrame.getMethodName(),
  497                           this.ctxt.getCompiler().getPageNodes(),
  498                           null,
  499                           javaLineNumber,
  500                           ctxt);
  501   
  502                   // If the line number is less than one we couldn't find out
  503                   // where in the JSP things went wrong
  504                   int jspLineNumber = detail.getJspBeginLineNumber();
  505                   if (jspLineNumber < 1) {
  506                       throw new JasperException(ex);
  507                   }
  508   
  509                   if (options.getDisplaySourceFragment()) {
  510                       return new JasperException(Localizer.getMessage
  511                               ("jsp.exception", detail.getJspFileName(),
  512                                       "" + jspLineNumber) +
  513                                       "\n\n" + detail.getJspExtract() +
  514                                       "\n\nStacktrace:", ex);
  515                       
  516                   } else {
  517                       return new JasperException(Localizer.getMessage
  518                               ("jsp.exception", detail.getJspFileName(),
  519                                       "" + jspLineNumber), ex);
  520                   }
  521               }
  522           } catch (Exception je) {
  523               // If anything goes wrong, just revert to the original behaviour
  524               if (ex instanceof JasperException) {
  525                   return (JasperException) ex;
  526               } else {
  527                   return new JasperException(ex);
  528               }
  529           }
  530       }
  531   
  532   }

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