The JSP engine (a.k.a Jasper).
The servlet container is responsible for providing a
URLClassLoader for the web application context Jasper
is being used in. Jasper will try get the Tomcat
ServletContext attribute for its ServletContext class
loader, if that fails, it uses the parent class loader.
In either case, it must be a URLClassLoader.
| Constructor: |
public JspServletWrapper(ServletConfig config,
Options options,
String jspUri,
boolean isErrorPage,
JspRuntimeContext rctxt) throws JasperException {
this.isTagFile = false;
this.config = config;
this.options = options;
this.jspUri = jspUri;
ctxt = new JspCompilationContext(jspUri, isErrorPage, options,
config.getServletContext(),
this, rctxt);
}
|
public JspServletWrapper(ServletContext servletContext,
Options options,
String tagFilePath,
TagInfo tagInfo,
JspRuntimeContext rctxt,
URL tagFileJarUrl) throws JasperException {
this.isTagFile = true;
this.config = null; // not used
this.options = options;
this.jspUri = tagFilePath;
this.tripCount = 0;
ctxt = new JspCompilationContext(jspUri, tagInfo, options,
servletContext, this, rctxt,
tagFileJarUrl);
}
|
| Method from org.apache.jasper.servlet.JspServletWrapper Detail: |
public int decTripCount() {
return tripCount--;
}
|
public void destroy() {
if (theServlet != null) {
theServlet.destroy();
AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
if (annotationProcessor != null) {
try {
annotationProcessor.preDestroy(theServlet);
} catch (Exception e) {
// Log any exception, since it can't be passed along
log.error(Localizer.getMessage("jsp.error.file.not.found",
e.getMessage()), e);
}
}
}
}
|
public List getDependants() {
try {
Object target;
if (isTagFile) {
if (reload) {
tagHandlerClass = ctxt.load();
reload = false;
}
target = tagHandlerClass.newInstance();
} else {
target = getServlet();
}
if (target != null && target instanceof JspSourceDependent) {
return ((java.util.List) ((JspSourceDependent) target).getDependants());
}
} catch (Throwable ex) {
}
return null;
}
Get a list of files that the current page has source dependency on. |
public JspCompilationContext getJspEngineContext() {
return ctxt;
}
|
public long getLastModificationTest() {
return lastModificationTest;
}
|
public Servlet getServlet() throws ServletException, IOException, FileNotFoundException {
if (reload) {
synchronized (this) {
// Synchronizing on jsw enables simultaneous loading
// of different pages, but not the same page.
if (reload) {
// This is to maintain the original protocol.
destroy();
Servlet servlet = null;
try {
servletClass = ctxt.load();
servlet = (Servlet) servletClass.newInstance();
AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
if (annotationProcessor != null) {
annotationProcessor.processAnnotations(servlet);
annotationProcessor.postConstruct(servlet);
}
} catch (IllegalAccessException e) {
throw new JasperException(e);
} catch (InstantiationException e) {
throw new JasperException(e);
} catch (Exception e) {
throw new JasperException(e);
}
servlet.init(config);
if (!firstTime) {
ctxt.getRuntimeContext().incrementJspReloadCount();
}
theServlet = servlet;
reload = false;
}
}
}
return theServlet;
}
|
public ServletContext getServletContext() {
return ctxt.getServletContext();
}
|
protected JasperException handleJspException(Exception ex) {
try {
Throwable realException = ex;
if (ex instanceof ServletException) {
realException = ((ServletException) ex).getRootCause();
}
// First identify the stack frame in the trace that represents the JSP
StackTraceElement[] frames = realException.getStackTrace();
StackTraceElement jspFrame = null;
for (int i=0; i< frames.length; ++i) {
if ( frames[i].getClassName().equals(this.getServlet().getClass().getName()) ) {
jspFrame = frames[i];
break;
}
}
if (jspFrame == null ||
this.ctxt.getCompiler().getPageNodes() == null) {
// If we couldn't find a frame in the stack trace corresponding
// to the generated servlet class or we don't have a copy of the
// parsed JSP to hand, we can't really add anything
return new JasperException(ex);
}
else {
int javaLineNumber = jspFrame.getLineNumber();
JavacErrorDetail detail = ErrorDispatcher.createJavacError(
jspFrame.getMethodName(),
this.ctxt.getCompiler().getPageNodes(),
null,
javaLineNumber,
ctxt);
// If the line number is less than one we couldn't find out
// where in the JSP things went wrong
int jspLineNumber = detail.getJspBeginLineNumber();
if (jspLineNumber < 1) {
throw new JasperException(ex);
}
if (options.getDisplaySourceFragment()) {
return new JasperException(Localizer.getMessage
("jsp.exception", detail.getJspFileName(),
"" + jspLineNumber) +
"\n\n" + detail.getJspExtract() +
"\n\nStacktrace:", ex);
} else {
return new JasperException(Localizer.getMessage
("jsp.exception", detail.getJspFileName(),
"" + jspLineNumber), ex);
}
}
} catch (Exception je) {
// If anything goes wrong, just revert to the original behaviour
if (ex instanceof JasperException) {
return (JasperException) ex;
} else {
return new JasperException(ex);
}
}
}
Attempts to construct a JasperException that contains helpful information
about what went wrong. Uses the JSP compiler system to translate the line
number in the generated servlet that originated the exception to a line
number in the JSP. Then constructs an exception containing that
information, and a snippet of the JSP to help debugging.
Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and
http://www.tfenne.com/jasper/ for more details.
|
public int incTripCount() {
return tripCount++;
}
|
public boolean isTagFile() {
return this.isTagFile;
}
|
public Class loadTagFile() throws JasperException {
try {
if (ctxt.isRemoved()) {
throw new FileNotFoundException(jspUri);
}
if (options.getDevelopment() || firstTime ) {
synchronized (this) {
firstTime = false;
ctxt.compile();
}
} else {
if (compileException != null) {
throw compileException;
}
}
if (reload) {
tagHandlerClass = ctxt.load();
reload = false;
}
} catch (FileNotFoundException ex) {
throw new JasperException(ex);
}
return tagHandlerClass;
}
Compile (if needed) and load a tag file |
public Class loadTagFilePrototype() throws JasperException {
ctxt.setPrototypeMode(true);
try {
return loadTagFile();
} finally {
ctxt.setPrototypeMode(false);
}
}
Compile and load a prototype for the Tag file. This is needed
when compiling tag files with circular dependencies. A prototpe
(skeleton) with no dependencies on other other tag files is
generated and compiled. |
public void service(HttpServletRequest request,
HttpServletResponse response,
boolean precompile) throws ServletException, IOException, FileNotFoundException {
try {
if (ctxt.isRemoved()) {
throw new FileNotFoundException(jspUri);
}
if ((available > 0L) && (available < Long.MAX_VALUE)) {
if (available > System.currentTimeMillis()) {
response.setDateHeader("Retry-After", available);
response.sendError
(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
Localizer.getMessage("jsp.error.unavailable"));
return;
} else {
// Wait period has expired. Reset.
available = 0;
}
}
/*
* (1) Compile
*/
if (options.getDevelopment() || firstTime ) {
synchronized (this) {
firstTime = false;
// The following sets reload to true, if necessary
ctxt.compile();
}
} else {
if (compileException != null) {
// Throw cached compilation exception
throw compileException;
}
}
/*
* (2) (Re)load servlet class file
*/
getServlet();
// If a page is to be precompiled only, return.
if (precompile) {
return;
}
} catch (ServletException ex) {
if (options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw ex;
}
} catch (FileNotFoundException fnfe) {
// File has been removed. Let caller handle this.
throw fnfe;
} catch (IOException ex) {
if (options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw ex;
}
} catch (IllegalStateException ex) {
if (options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw ex;
}
} catch (Exception ex) {
if (options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw new JasperException(ex);
}
}
try {
/*
* (3) Service request
*/
if (theServlet instanceof SingleThreadModel) {
// sync on the wrapper so that the freshness
// of the page is determined right before servicing
synchronized (this) {
theServlet.service(request, response);
}
} else {
theServlet.service(request, response);
}
} catch (UnavailableException ex) {
String includeRequestUri = (String)
request.getAttribute("javax.servlet.include.request_uri");
if (includeRequestUri != null) {
// This file was included. Throw an exception as
// a response.sendError() will be ignored by the
// servlet engine.
throw ex;
} else {
int unavailableSeconds = ex.getUnavailableSeconds();
if (unavailableSeconds < = 0) {
unavailableSeconds = 60; // Arbitrary default
}
available = System.currentTimeMillis() +
(unavailableSeconds * 1000L);
response.sendError
(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
ex.getMessage());
}
} catch (ServletException ex) {
if(options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw ex;
}
} catch (IOException ex) {
if(options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw ex;
}
} catch (IllegalStateException ex) {
if(options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw ex;
}
} catch (Exception ex) {
if(options.getDevelopment()) {
throw handleJspException(ex);
} else {
throw new JasperException(ex);
}
}
}
|
public void setCompilationException(JasperException je) {
this.compileException = je;
}
Sets the compilation exception for this JspServletWrapper. |
public void setLastModificationTest(long lastModificationTest) {
this.lastModificationTest = lastModificationTest;
}
|
public void setReload(boolean reload) {
this.reload = reload;
}
|
public void setServletClassLastModifiedTime(long lastModified) {
if (this.servletClassLastModifiedTime < lastModified) {
synchronized (this) {
if (this.servletClassLastModifiedTime < lastModified) {
this.servletClassLastModifiedTime = lastModified;
reload = true;
}
}
}
}
Sets the last-modified time of the servlet class file associated with
this JspServletWrapper. |