Comment lines: Scott Johnson: JavaServer Pages for beginners

JavaServer Pages™ technology has been around for years, but it still is not very well understood. Although intended for beginners, all levels of expertise will benefit from this primer on exactly how JSP containers work.

Share:

Scott Johnson (scottjoh@us.ibm.com), Software Engineer, EMC

Author photoScott Johnson has been a software developer for 24 years. He joined IBM at the Research Triangle Park Lab in 2000, and was the Team Lead and Architect for the WebSphere Application Server JSP processor for six years. Scott is IBM's representative on the Expert Group for JSR 245, JavaServer Pages 2.1.


developerWorks Contributing author
        level

28 February 2007

Also available in Chinese

From the IBM WebSphere Developer Technical Journal.

Let's review

JavaServer Pages technology has been around since the last century, but I believe it is still not well understood. As the lead for WebSphere® Application Server’s JSP container, I was curious to see if there was information readily available, written for the beginner, about how JSP containers worked. I couldn’t find anything that was detailed enough to be interesting -- at the same time, I don’t expect everyone to know JSP technology inside and out. This article is my attempt to fill this middle gap of information: a primer on the practical details of the two major JSP processing phases, the translation and request phases. I hope you find this information helpful, and I expect you will find it sometimes surprising. It might even improve the quality of your JSPs!

Sample code

At the end of this article is a sample JSP file, codegen.jsp, that I will refer to throughout this article. The JSP shows two very different ways of setting a property called name in a class called Nameclass. The JSP incorporates various JSP syntax elements to make the discussion interesting. I have highlighted lines (in bold text) that I discuss in the article. If you want to run it yourself, invoke codegen.jsp in your browser with a URL like this (the request parameters nameParam and tableColor are optional):

http://localhost:9080/yourapp/codegen.jsp?nameParam=Your Name&tableColor=red

If codegen.jsp were invoked with this URL, the browser would display this:

Figure 1. Invoking codegen.jsp
Figure 1. Invoking codegen.jsp

The translation phase

So, what is a JSP page?

JSP technology was never intended to support binary data, either in a JSP page itself or in the response generated by a page.

In the translation phase, a JSP page is processed by the JSP container. A JSP page is a text document. It can consist entirely of a single text file. It can also consist of a primary text file -- the "top-level" JSP file -- and other text files that are statically included in it via the JSP include directive. The JSP include directive is a JSP syntax element that looks like this:

<%@ include file="relativeURL" %>

An example, <%@ include file="nameclass.jspf" %> , is shown in the codegen.jsp code sample at the end of this article. To "statically include" a file means that the actual contents of an included file ("relativeURL", in the JSP include directive) are placed in the JSP page exactly where the include directive was found, and the include directive itself is discarded. In a sense, a JSP page is an in-memory construct because you never really see the entire contents of a JSP page when it contains statically included files, unless you're using special JSP-aware development tools that show you the inclusions in-place.

A JSP file doesn't need to have any JSP syntax in it at all. It doesn't have to contain anything special to be a JSP file. A valid JSP file could simply contain "Hi there!" What makes it a JSP file is that it is delivered to a JSP container for processing. In an application server, a request for any file with the extensions jsp or jspx will be sent to the JSP container for processing, regardless of what is in it. What's in the file is important, though! Not all files with JSP extensions are valid JSP files.

What happens in the translation phase?

During the translation phase, the JSP page (also called the translation unit) has to be converted from text to an executable form so that it can run inside the application server. The executable form of a JSP page is a Java class that implements the javax.servlet.Servlet interface. This means that a JSP page is turned into a plain old servlet (specifically, an HttpServlet) which runs inside a Web application inside the application server. In JSP-speak, this servlet is called the JSP page implementation class. WebSphere Application Server's JSP container performs the conversion process in three steps:

  1. Validation
  2. Java source code generation
  3. Java source code compilation

The JavaServer Pages specification calls this the translation phase of JSP processing.

1. Validation

The JSP container ensures that the syntax of the JSP page is correct, and generates informative error messages when it encounters errors. To validate that a JSP page's syntax is correct, the JSP container reads the page character by character, parsing the page's contents. The JSP container looks for character sequences that it recognizes; sequences that indicate there's some syntax that it needs to process.

a. The include directive

For example, the JSP include directive I showed earlier starts with <%@. Those three characters form the opening sequence of JSP directive syntax. (JSP defines six directives altogether, if you count three directives that are valid only for JSP tag files.)

Consider the include directive from codegen.jsp as an example:

<%@ include file="nameclass.jspf"%>

The JSP container will see <%@ and will then look for a valid JSP directive name, such as "include" or "page." In our example "include" is found, and the JSP container knows that the next character sequence must be "file=" since that is the only valid attribute for the include directive. If the directive concludes properly with %> and if the value of the "file=" attribute is a filename that the JSP container can locate and read (in our example, nameclass.jspf), then the contents of that file are included in place in the JSP page, in the manner I described earlier. The included text is also validated. It must be validated, because it is now part of the JSP translation unit and must meet JSP syntax rules.

If a statically included file also statically includes a file via the include directive, then it too is included in place. There's no practical limit to the number of nested includes (although it can get pretty confusing and hard to follow if file nesting is very deep). The only restriction is that circular includes are not allowed; where JSP file A statically includes JSP file B and then B statically includes A. The JSP container recognizes this situation and halts validation with an error message.

In WebSphere Application Server, all those static includes are actually performed before validation really begins -- so that we have a complete JSP page/translation unit in memory and can validate it knowing that every file the author intended to be part of the final JSP page is now in place.

b. Custom tag validation, with an expression language expression in an attribute

JSP custom tags can be written by anyone and then supplied for use by JSP authors, in the form of tag libraries. A tag library is a collection of custom tag implementations. A custom tag like the JavaServer Pages Standard Tag Library (JSTL) out tag will have some attributes that are required, and others that are optional. Here's a sample usage of the JSTL out tag from codegen.jsp:

<c:out value='Just set the name from request!
[${nameBean.name}]' default="null"/>

The JSTL out tag has just one required attribute, the value attribute. If the value attribute and its value aren't present then the JSP container generates an error. In this example, the value attribute is a combination of some text:

Just set the name from request! []

and an expression language (EL) expression that is embedded in the text:

${nameBean.name}

With JSP 2.1 and JavaServer Faces 1.2, the Unified Expression Language defines an expression type with the syntax #{expr}.

EL expressions begin with "${" and end with "}". In our example, the JSP container must validate the syntax of the expression ${nameBean.name}. In this case, the expression syntax is valid. Note, however, that the expression may not execute successfully if the author made a mistake and, for example, there is no property called name on the nameBean. All we've done so far is validate the syntax, not the logic, of the expression.

The other attribute we encounter, default, is recognized as a valid but optional attribute, whose value can be a string constant, as it is in our example. So the example usage of this custom tag passes validation. We will see later what the Java code generated in the implementation servlet looks like.

c. A snippet from a tag library descriptor

How does the JSP container know which attributes of a custom tag are required and which are not? It finds what it needs to know about a custom tag by reading metadata about the tag. That metadata is found in a tag library descriptor file (TLD) which must be supplied by the author of the custom tag implementation. (The sample above is the usage of the out tag within a JSP page, and there's also an implementation of the out tag that actually makes the usage work.)

Here's what the JSP container reads and analyzes to know what attributes are valid in the out tag. I've left out a few things in consideration of space, and have highlighted relevant parts in bold type.

Listing 1
<tag>
  <description>
     Like <%= ... >, but for expressions.
  </description>
  <name>out</name><tag-class>
      org.apache.taglibs.standard.tag.rt.core.OutTag
  </tag-class>This is the implementation class for the out tag.
  <body-content>JSP</body-content>
  <attribute>
     <description>
        Expression to be evaluated.
     </description>
     <name>value</name>The value attribute is required...<required>true</required>
     <rtexprvalue>true</rtexprvalue>
		...and it is allowed to contain a 'runtimeexpression value', like our EL expression.
  </attribute>
  <attribute>
     <description>
        Default value if the resulting value is null.
     </description>
     <name>default</name>The default attribute is not required.<required>false</required>
     <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
     <name>escapeXml</name>
		The escapeXml attribute is not required.
     <required>false</required>
     <rtexprvalue>true</rtexprvalue>
  </attribute>
</tag>

d. jsp:useBean validation

Another example is the validation of the powerful jsp:useBean standard action. When validating a jsp:useBean tag, such as:

<jsp:useBean id="nameBean" 
class="codegen.Nameclass" scope="request" />

JSP standard actions are very similar to custom tags, but they are built right into JSP technology. There are nearly 20 standard actions, including <jsp:setProperty>, <jsp:include>, <jsp:forward> and <jsp:param>

.

the JSP container must validate many things. Each attribute has its own validation rules, and there are also rules about how combinations of attributes are handled. Unlike a custom tag, a JSP standard action like jsp:useBean doesn't have a metadata file like a TLD. Instead, the rules about which attributes are required (which can be run time expressions, and so on) are written into a JSP container's validation code by the container's author (who, of course, has read and thoroughly understands the JSP specification's six pages of detail about the rules regarding the jsp:useBean action).

In this simple example, the JSP container validates that the required ID attribute's value, "nameBean," is unique within the translation unit. For example, if another jsp:useBean tag in this JSP page also used "nameBean" as an ID, then the JSP container would generate an error. The jsp:useBean action requires that either the class or type attribute be present; in this case class is given. And, finally, the container validates that the value for the optional scope attribute is one of the four allowed: "page", "request", "session" or "application". This useBean tag passes validation; we will see the generated code later.

e. Template text

During validation of the JSP page, if the JSP container does not recognize text sequences, then it doesn't try to process them, and simply puts them into the JSP page implementation class exactly as they appear in the JSP page.

For example, the simple JSP file that contains only "Hi there!" doesn't have any text sequences that a JSP container needs to process. Sequences like this are called template text or template data. The JSP specification puts it this way:

A JSP page has elements and template data. An element is an instance of an element type known to the JSP container. Template data is everything else; that is, anything that the JSP translator does not know about.

HTML is template text; JSP technology doesn't know anything about parsing or validating HTML tags (like <html><head><title> in codegen.jsp). This means you can embed HTML in a JSP page and it will be sent straight through to the browser when the page executes. (In fact, this was one of the first objectives for JSP technology when it was created in the late 1990s.) Also, you can combine HTML with expressions to make your HTML dynamic. Take for example this example from codegen.jsp:

<table bgcolor=${tableColorVar} border="0" width="25%">

As the JSP container parses this text, it sends the HTML text <table bgcolor= straight through to the implementation servlet without any validation. But it recognizes ${tableColorVar} as an EL expression, and validates that its syntax is correct (it is). And, as we'll see in the Java source code generation topic, the container generates special Java code for the EL expression. The rest of this line, border="0" width="25%"> is not validated and is put in the implementation servlet as-is.

f. Scripting elements

Scripting elements in JSPs are declarations, scriptlets, and expressions. (JSP scripting elements are very different from JSP EL expressions.) What you put inside scripting elements is Java code. Declaration syntax is <%! ... %>, scriptlet syntax is <% ... %>, and expression syntax is <%= ... %>.

A JSP container doesn't validate what is inside these three elements. A JSP container does not know how to parse Java code. Whatever is inside a declaration, scriptlet, or expression must be valid Java, or else the Java code in the implementation class won't compile successfully. In this sense, scripting elements are pretty much like template text because the JSP container doesn't validate what's inside them; it just passes the contents right on into the JSP page implementation class. I describe this in the Code generation for scripting elements topic.

g. An experiment with binary data

Earlier I said that JSP pages are human-readable text documents. If you look at a binary file in a text file editor you'll see characters like PýÝ ýÔ üüý÷÷ùýÌ. This data might make sense in a Graphics Interchange Format (GIF) file but not in a JSP file. However, as an experiment, try renaming a GIF file so that it has a .jsp extension, request that file in WebSphere Application Server, and see what happens. It is very possible that the GIF image will display just fine in your browser even though a GIF is a binary file type. The reason this might work is that if the JSP container doesn't see any character sequences that it recognizes during the translation phase, then it will simply include all the data as-is in the JSP servlet it is creating. The servlet will execute and will output the data, which will be the original contents of the GIF file. The browser will take that response data and recognize it as a GIF and display it! However, if the file just happens to contain a sequence of characters that the JSP container recognizes during translation (like <%@), it will try to process the ensuing characters, and most likely these ensuing characters won't be valid JSP syntax. The JSP container will raise a translation exception and won't even go on to create the page implementation servlet.

h. When validation is complete

When the JSP container has determined that the JSP page's syntax is valid, it enters the next phase of processing: code generation. The container actually collected a lot of information about the page during the validation phase, and this information is now used to properly generate Java code.

2. Java source code generation

If the JSP page is valid, the JSP container converts the text in the JSP page into Java source code for what will become the JSP page implementation class. At the end of this article is a very stripped-down version of the actual .java code, _codegen.java, that was generated by WebSphere Application Server for the codegen.jsp example. In this code, you'll see many instances of out.write() and out.print(). These Java methods are what send response data back to the browser for display.

a. Code generation for an EL expression in a custom tag attribute

Using the example below, we earlier looked at how custom tag validation worked. Now we'll see the Java code generated by the JSP container.

<c:out value='Just set the name from request!
[${nameBean.name}]' default="null"/>

Earlier, I said that this example illustrates a usage of the JSTL out tag and that there's an implementation of that tag that actually does the work. The Java code generated by the JSP container must be able to invoke that implementation class at run time. The JSP container needs to discover the name of the class that implements the out tag. It finds this information in the tag library descriptor. The name of the out tag's implementation class is found here:

<tag-class>
   org.apache.taglibs.standard.tag.rt.core.OutTag
</tag-class>
this is the implementation class for the out tag

With this information, the container generates the following Java code, which is found in the method called _jspx_meth_c_out_1() in _codegen.java.

Listing 2
Line 1	private boolean _jspx_meth_c_out_1(JspTag _jspx_th_c_when_0, 
	PageContext pageContext) throws Throwable {
Line 2	org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_out_1 = new OutTag();
Line 3	_jspx_th_c_out_1.setValue((Object) PageContextImpl.proprietaryEvaluate("Just 
	set the name from request![${nameBean.name}]"));
Line 4	_jspx_th_c_out_1.setDefault("null");
Table for Listing 2
LineDescription
2Creates an instance of the c:out tag's implementation class and puts it in the variable _jspx_th_c_out_1.
3Calls the setValue() method on that instance variable to set the value that we want the out tag's implementation to return in the response to the browser. But this value contains an EL expression, ${nameBean.name}. EL expressions require special handling because they represent values that are dynamically discovered at run time, unlike static text which never changes. The machinery that WebSphere Application Server uses to enable the run time discovery of the value for nameBean.name is the invocation of the method called proprietaryEvaluate(). When the OutTag class executes at run time, it will use proprietaryEvaluate() to find the current value for nameBean.name, and will replace the expression ${nameBean.name} with the current value and return the text string to the browser.
4Calls setDefault() to set the value given for the default attribute.

b. Another custom tag code generation example

The following section from the codegen.jsp file checks for the existence of a request parameter called tableColor. If the parameter exists, it sets a variable called tableColorVar to the value of the request parameter. (You'll see how tableColorVar is used below.)

Listing 3
<c:if test='${not empty param.tableColor}'>
   <c:set var="tableColorVar" value="${param.tableColor}"/>
</c:if>

These actions are invoked via a single method call in _codegen.java's _jspService() method:

if (_jspx_meth_c_if_0(pageContext)) return;

The method _jspx_meth_c_if_0() contains the invocation of the implementation of the JSTL c:if tag. Here's a description of the most significant parts of that method:

Listing 4
Line 1	private boolean _jspx_meth_c_if_0(PageContext pageContext) throws Throwable {
Line 2		org.apache.taglibs.standard.tag.rt.core.IfTag _jspx_th_c_if_0 = new IfTag();
Line 3		_jspx_th_c_if_0.setPageContext(pageContext);
Line 4		_jspx_th_c_if_0.setParent(null);
Line 5		_jspx_th_c_if_0.setTest(((Boolean) PageContextImpl.proprietaryEvaluate("${not 
			empty param.tableColor}")).booleanValue());
Line 6		int _jspx_eval_c_if_0 = _jspx_th_c_if_0.doStartTag();
Line 7		if (_jspx_eval_c_if_0 != Tag.SKIP_BODY) {
Line 8			do {
Line 9				if (_jspx_meth_c_set_1(_jspx_th_c_if_0, pageContext)) return true;
Table for Listing 4
LineDescription
2Creates an instance of the c:if tag's implementation class and puts it in the variable _jspx_th_c_if_0.
5Calls the setValue() method on that instance variable to set the test condition that we want evaluated at run time when the method is executed. As with the c:out example above, the EL expression, ${not empty param.tableColor}, will be evaluated by the proprietaryEvaluate() method.
6The c:if tag implementation class is executed via the doStartTag() method. doStartTag()will return a value in _jspx_eval_c_if_0.
7If _jspx_eval_c_if_0 is not equal to the constant value Tag.SKIP_BODY then it means the EL expression evaluated to true: the request parameter called tableColor does exist!
9Another method is executed: _jspx_meth_c_set_1(). You can see this method in the _codegen.java snippet. This method retrieves the value of the request parameter tableColor (which we now know exists) and puts that value in our variable called tableColorVar, which is used later.

c. Code generation for jsp:useBean actions

We used this template text example earlier, while discussing validation of template text:

<jsp:useBean id="nameBean"
class="codegen.Nameclass" scope="request" />

The JSP Specification says this about the jsp:useBean action:

The jsp:useBean action is quite flexible; its exact semantics depends on the attributes given. The basic semantic tries to find an existing object using id and scope. If the object is not found it will attempt to create the object using the other attributes.

Our usage of jsp:useBean fits the "basic semantic" described above. WebSphere Application Server generates the following code:

Listing 5
Line 1	codegen.Nameclass nameBean = null;  
Line 2	synchronized (pageContext) {	
Line 3		nameBean = (codegen.Nameclass) pageContext.getAttribute("nameBean", 
			PageContext.REQUEST_SCOPE);
Line 4		if (nameBean == null) {
Line 5			nameBean =  new codegen.Nameclass();
Line 6			pageContext.setAttribute("nameBean", nameBean, PageContext.REQUEST_SCOPE);
Line 7		}
Line 8	}
Table for Listing 5
Line #Description
1Defines the variable nameBean of the type given in class="codegen.Nameclass"
2Synchronizes access to the pageContext, since another thread may be executing concurrently.
3Tries to obtain an object called "nameBean" at 'request' scope.
4-6If nameBean was not found, creates it and stores it with 'request' scope.

This generated code simply follows the rules described by the JSP specification for this simple usage of jsp:useBean.

d. Code generation for template text containing an embedded EL expression

We used this template text example earlier, while discussing validation of template text:

<table bgcolor=${tableColorVar} border="0" width="25%">

WebSphere Application Server generates the following code from this example:

Listing 6
Line 1	out.write("\r\n<table bgcolor=");
Line 2	out.write((java.lang.String) 
	PageContextImpl.proprietaryEvaluate("${tableColorVar}"));
Line 3	out.write(" border=\"0\" width=\"25%\">);
Table for Listing 6
LineDescription
1The JSP container doesn't see any syntax it needs to process, until it encounters${tableColorVar}. So this first part is output into _codegen.java as-is (including carriage return and newline).
2But ${tableColorVar} is an EL expression, and simply putting out.write("${tableColorVar}"); in _codegen.java would not accomplish what was intended by the JSP page's author. The author intends for ${tableColorVar} to be a dynamic runtime value. Similar to the c:out tag generation described above, the JSP container generates a call to proprietaryEvaluate(), which will discover the runtime value for tableColorVar.
3The last part of the template text is output into _codegen.java as-is -- with backslashes added by the JSP container so that the quotation marks are output as text.

The result of the code generation for this example of template text is three lines of Java code in the implementation class. The HTML that ends up in the browser would look like this:

<table bgcolor=blue border="0"
width="25%">

The HTML table would be displayed in the browser with a blue background.

The above example assumes that ${tableColorVar} resolved to the value "blue" at run time, as a result of a request URL like:

http://localhost:9080/yourapp/codegen.jsp?nameParam=Your Name&tableColor=blue

e. Code generation for scripting elements

A JSP container handles scriptlets, expressions, and declarations each in a different way.

An expression, such as <%=nameClass.getName()%> in codegen.jsp is converted to Java code in _codegen.java that looks like:

out.print(nameClass.getName());

An expression like <%=nameParam%> is converted to Java code that looks like:

out.print(nameParam);

In both of these examples, whatever is found within the expression is made the argument to an out.print() statement (or sometimes out.write()) inside the page implementation class's service method.

A valid declaration, such as the declaration of the class called Nameclass in nameclass.jsp, is put into _codegen.java, unmodified, in the page implementation class at the class level, not inside the service method. This is the part of _codegen.java that starts with:

public class Nameclass {
private String name="";

Recall that nameclass.jsp was statically included in our JSP page exactly where the JSP include directive was located. During Java code generation, the JSP container takes this block of code and moves it to a totally different place (at the class level) as per the JSP rules for declarations.

A valid scriptlet, such as <% if (nameParam != null){nameClass.setName(nameParam);%> is emitted directly into the implementation class's service method:

if (nameParam != null){nameClass.setName(nameParam);

Remember that the JSP container is parsing the page character by character. Once it has identified the start of one of these three scripting elements, it also has to determine where it ends. So, for example, if you happen to misunderstand how a scriptlet works, and you attempt to use an expression within a scriptlet to dynamically initialize a Java variable, it will fail. The example below illustrates this error:

Listing 7
<% if (nameParam != null){nameClass.setName(nameParam);
   String theName=new String("<%=nameParam%>");
//   trying to instantiate a Java variable called theName
   out.print(theName);
//   using a JSP expression inside a scriptlet.
%>

The novice might write code that doesn't work not realizing that scripting isn't designed for any of these three elements to be combined. In this case, the JSP container recognizes the start of the scriptlet (<% if (nameParam != null){...), but then sees %> (the closing of the expression <%=nameParam%>) and thinks it is the closing of the scriptlet. That causes the generated Java code to be invalid.

Several years ago, the JSP 2.0 Specification recommended that scripting elements be avoided. Why am I (and many others) opposed to using Java code inside JSPs?

  1. It is dangerous. I recently spent many hours debugging a customer's failing application. The developers were at a loss. We looked at their JSPs together. Finally, it dawned on me that they had declared many variables with global scope (class instance variables) via declaration elements. When the JSP was executing in a multi-user environment, one particularly important variable was having its value changed by one user's request thread while another user's request thread was processing. The result was seriously flawed response output. The developers were embarrassed, but I told them it was an easy mistake to make, especially if you're unaware that a single servlet handles all requests! It's easy to make mistakes if you choose to employ scripting elements, so they're best avoided all together.

  2. It makes JSPs difficult to read and debug. Often, you'll see syntax like that in codegen.jsp, after <!-- ***** but scripting is used here ***** -->. Looking at the scripting code in this tiny JSP is not very easy. The dangling braces -- for example, <%}%> -- are confusing, but they're needed in order to make the Java code valid and complete when you embed Java in JSPs. When a JSP contains hundreds, or thousands, of lines of mixed HTML, JSP syntax, and Java scripting, it can easily become a maintenance and debugging nightmare.

f. jspInit() and jspDestroy()

If a JSP page author wants the JSP page to have init and destroy methods, scripting must be used. Specifically, a JSP declaration that declares these methods must be part of the JSP page. Such a JSP page might look like this:

Listing 8
<%!
public void jspInit()
{
  // do some initialization work
}
public void jspDestroy()
{
  // do some finalization work
}
%>
<HTML>
  <BODY>
      Your JSP stuff here!
  </BODY>
</HTML>

g. A little humor

I include here, in spite of its awkward rhyme and stumbling meter, a little-known but apt limerick on the topic of JSP scripting elements.

There once was a coder from France
Who wrote by the seat of his pants
When his JSPs broke
He collapsed, and then spoke:
"I used scriptlets in my ignorance!"

h. When code generation is complete

When the JSP container has finished generating the .java file, it enters the next phase of processing: Java code compilation.

3. Java source code compilation

* The implementation class does not have to reside on disk. The JSP container in a future version of WebSphere Application Server will support optional in-memory translation and compilation of JSPs. In this mode of operation, JSP implementation classes (both the generated .java and .class files) are never persisted to disk, saving both disk I/O cycles and disk resources.

The JSP container compiles the .java file it has generated. Java compilation creates a binary class -- the JSP page implementation class -- which resides on disk as a .class file.* If there are Java compilation errors, then error messages are generated that identify the error, the JSP line number, and the equivalent .java source file line number where the error took place.

WebSphere Application Server, like most JSP containers, supports the Eclipse Java Development Tools (JDT) compiler, as well as the JDK's javac. WebSphere Application Server started supporting the JDT compiler with Version 6.1. The JDT compiler is the default Java compiler for the JSP container because it operates very efficiently in an Open Services Gateway Initiative (OSGi) environment.


The request phase

When a JSP is requested in a running application server, its page implementation servlet class is invoked. On each request, the servlet's service method executes on a thread of its own; the thread on which the request is executing. This way, a single JSP servlet can handle multiple concurrent requests.

The WebSphere JSP container is involved in the request phase in two ways:

  1. Runtime support: Provides classes and methods used by the servlet. This is called runtime support. For example, the method called proprietaryEvaluate(), which we saw earlier, is a run time support method.
  2. Reloading: Checks to see if the JSP source file, from which the servlet was created, has been modified and needs to be re-translated. See the JSP reloading below.

A detailed discussion of the WebSphere JSP container's role in the request phase is found here.

A JSP servlet's performance handicap

Even though a JSP servlet is just an ordinary servlet, it will never perform as well as an equivalent servlet that was written manually without JSP technology. This is because the JSP servlet generated by a JSP container must meet many requirements that make JSP technology powerful and simple to use.

For example, the generated JSP servlet must provide a Java object called the pageContext (described below) and every invocation of the _jspService() method must obtain that object and initialize some other variables:

Listing 9
pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 
	8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();

This description of the pageContext object is from the JSP specification:

The PageContext provides a number of facilities to the page/component author and page implementor, including:

  • a single API to manage the various scoped namespaces
  • a number of convenience API's to access various public objects
  • a mechanism to obtain the JspWriter for output
  • a mechanism to manage session usage by the page
  • a mechanism to expose page directive attributes to the scripting environment
  • mechanisms to forward or include the current request to other active components in the application
  • a mechanism to handle errorpage exception processing.

If one were to write the _codegen.java servlet without using JSP technology, it would be more difficult than writing codegen.jsp and having the JSP container generate the servlet. But if the handwritten servlet didn't need the facilities described above, then it would not have to provide them, and would be lighter-weight and faster-performing than the generated servlet.

JSP reloading

When a JSP source file is modified and subsequently requested, it can be reloaded. Reloading involves performing the entire translation phase on the requested JSP so that a new JSP implementation class is generated. That new class, which reflects the modifications made to the JSP source, is then reloaded and invoked.

The JSP specification doesn't mandate that a JSP container retranslate and reload a JSP when it is modified in a running Web application. However, all JSP containers provide this functionality. Runtime JSP reloading is a convenient feature for environments in which JSP source changes frequently.

WebSphere Application Server provides several ways to configure JSP reloading.

Static vs. dynamic includes

JSP technology provides two kinds of includes, static and dynamic. These two include types are often confused with each other.

We've already seen the following example of a static include:

<%@ include file="nameclass.jspf" %>

A static include is handled by the JSP container during the translation phase, while the JSP container is constructing the JSP page in memory.

A dynamic include -- known as the jsp:include standard action -- is performed during the request phase.

The syntax for a dynamic include is:

<jsp:include page="urlSpec"
flush="true|false"/>

If a JSP contained the following include action:

<jsp:include page="myInclude.jsp" flush="true "/>

then the following Java code would be generated by the JSP container:

JspRuntimeLibrary.include(request, response, "myInclude.jsp", out, true);

When that line of code is executed in the request phase, myInclude.jsp is invoked and its output is included in the current JSP's output. The JSP specification describes include actions this way:

An include action regards a resource such as a JSP page as a dynamic object; i.e. the request is sent to that object and the result of processing it is included.


Conclusion

I hope this helps you understand how a JSP container validates a JSP page, generates the Java code for the page's implementation servlet, and participates in request processing. Examine the sample code and generated source below for actual illustrations of this discussion.


Sample A

Listing 10. codegen.jsp (the top-level JSP file)

Click to see code listing

Listing 10. codegen.jsp (the top-level JSP file)

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html><head><title>Code Validation and Generation Sample</title></head>
<body>

<!-- ***** no scripting is used here ***** -->
<jsp:useBean id="nameBean" class="codegen.Nameclass" scope="request" />
<table>
<tr><td><c:out value='Checking to see if name is given in the request...'/></td></tr>
<c:choose>
    <c:when test='${not empty param.nameParam}'>
        <jsp:setProperty name="nameBean" property="name" value='${param.nameParam}'/>
        <tr><td><c:out value='Just set the name from request! [${nameBean.name}]'default="null"/></td></tr>
    </c:when>
    <c:otherwise>
        <tr><td><c:out value='Name not supplied on request...'/></td></tr>
        <jsp:setProperty name="nameBean" property="name" value="J. Doe"/>
        <tr><td><c:out value='... so we set it to [${nameBean.name}]'/></td></tr>
    </c:otherwise>
</c:choose>
</table>
</br>

<!-- ***** but scripting is used here ***** -->
<%@ include file="nameclass.jspf" %>
<%Nameclass nameClass = null;String nameParam=(String)request.getParameter("nameParam");%>
<%nameClass=new Nameclass();%>
<table>
<tr><td>Checking to see if name is given in the request...</td></tr>
<% if (nameParam != null){nameClass.setName(nameParam);%>
   <tr><td>Just set the name from request! [<%=nameParam%>]</td></tr>
<%}else{ %>
   <tr><td>Name not supplied on request...</td></tr>
   <% nameClass.setName("J. Doe");%>
   <tr><td>...so we set it to [<%=nameClass.getName()%>]</td></tr>
<%}%>
</table>
</br>

<!-- ***** results table ***** -->
<c:set var="tableColorVar" value="blue" scope="request" />   
	<!-- ***** blue is the default table color ***** -->
<c:if test='${not empty param.tableColor}'><c:set var="tableColorVar" value="${param.tableColor}"/></c:if><table bgcolor=${tableColorVar} border="0" width="25%">
<tr><td bgcolor="lightgray">Name from EL expression <b>(\${nameBean.name})</b></td>
<td><font color="white">${nameBean.name}</font></td></tr>
<tr><td bgcolor="lightgray">Name from JSP expression <b>(<\%=nameClass.getName()%>)
	</b></td>
<td><font color="white"><%=nameClass.getName()%></font></td></tr>
</table>
</body></html>

------------------- nameclass.jspf  (statically included in codegen.jsp and used in 
	the scriptlet <%nameClass=new Nameclass();%>) -------------------
<%!
// This class will be statically included in codegen.jsp,
//    and will be placed in the class section of the generated code, _codegen.java, 
//    because it is enclosed in a JSP declaration.
public class Nameclass {
    private String name="";
    public Nameclass() {
    }
    public Nameclass(String name) {
        this.name=name;
    }
    public void setName(String name) {
        this.name=name;
    }
    public String getName() {
        return this.name;
    }
}
%>
------------------- Nameclass.java  (must be compiled into a .class file;  Nameclass is 
	used by the <jsp:useBean> element in codegen.jsp) -------------------
package codegen;
public class Nameclass {
    private String name="";
    public Nameclass() {
    }
    public Nameclass(String name) {
        this.name=name;
    }
    public void setName(String name) {
        this.name=name;
    }
    public String getName() {
        return this.name;
    }
}

Sample B

(The stripped-down code in this snippet is for demonstration purposes only; it will not compile.)

Listing 11. Sample generated code
------------------- _codegen.java -------------------
public final class _codegen extends com.ibm.ws.jsp.runtime.HttpJspBase {
  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();

  // This declaration of the class called Nameclass was statically included from 
  // nameclass.jspf where it is defined as a JSP declaration  (<%! ... %>).  Because 
  // it was defined as a JSP declaration, it is placed in _codegen.java at the class 
  // level (as opposed to inside the _jspService() method).
  public class Nameclass {
        private String name="";
        public Nameclass() {
        }
        public Nameclass(String name) {
              this.name=name;
        }
        public void setName(String name) {
              this.name=name;
        }
        public String getName() {
              return this.name;
        }
  }

  // this _jspService() method is invoked when a request for codegen.jsp is received by 
  // the application server
  public void _jspService(HttpServletRequest request, HttpServletResponse  response)
      throws java.io.IOException, ServletException {

    PageContext pageContext = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;

    try {
      pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 
	8192, true);

      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      out = pageContext.getOut();

      out.write("\r\n<html><head><title>Code Validation and Generation Sample</title>
	</head>\r\n<body>\r\n\r\n");

      out.write("<!-- ***** no scripting is used here ***** -->");

      // This is code generated from the jsp:useBean statement in codegen.jsp
      codegen.Nameclass nameBean = null;
      synchronized (pageContext) {
        nameBean = (codegen.Nameclass) pageContext.getAttribute("nameBean", 
		PageContext.REQUEST_SCOPE);
        if (nameBean == null) {
          nameBean =  new codegen.Nameclass();
          pageContext.setAttribute("nameBean", nameBean, PageContext.REQUEST_SCOPE);
        }
      }
      out.write("\r\n<table>\r\n<tr><td>");

      // This is code generated from the <c:choose> custom tag in codegen.jsp
      if (_jspx_meth_c_choose_0(pageContext)) return;
      out.write("\r\n</table>\r\n</br>\r\n\r\n");

      out.write("<!-- ***** but scripting is used here ***** -->");

      Nameclass nameClass = null;String nameParam=(String)request.getParameter
	("nameParam");

      nameClass=new Nameclass();
      out.write("\r\n<table>\r\n<tr><td>Checking to see if name is given in the 
	request...</td></tr>\r\n");
       if (nameParam != null){nameClass.setName(nameParam);
        out.write("\r\n   <tr><td>Just set the name from request! [");
        out.print(nameParam);
        out.write("]</td></tr>\r\n");
      }else{
        out.write("\r\n   <tr><td>Name not supplied on 
		request...</td></tr>\r\n   ");
        nameClass.setName("J. Doe");
        out.write("\r\n   <tr><td>...so we set it to [");
        out.print(nameClass.getName());
        out.write("]</td></tr>\r\n");
      }
      out.write("\r\n</table>\r\n</br>\r\n\r\n");
      out.write("<!-- ***** results table ***** -->");

      // This is code generated from the first <c:set> custom tag in codegen.jsp
      if (_jspx_meth_c_set_0(pageContext)) return;

      // This is code generated from the <c:if> custom tag in codegen.jsp
      if (_jspx_meth_c_if_0(pageContext)) return;
      out.write("\r\n<table bgcolor=");
      out.write((String) PageContextImpl.proprietaryEvaluate("${tableColorVar}"));
      out.write(" border=\"0\" width=\"25%\">\r\n<tr><td bgcolor=\"lightgray\">Name from 
	EL expression
                  <b>(${nameBean.name})</b></td>\r\n<td><font color=\"white\">");
      out.write((String) PageContextImpl.proprietaryEvaluate("${nameBean.name}"));
      out.write("</font></td></tr>\r\n<tr><td bgcolor=\"lightgray\">Name from JSP 
	expression 
                  <b>(<%=nameClass.getName()%>)</b></td>\r\n<td><font color=\"white\">");
      out.print(nameClass.getName());
      out.write("</font></td></tr>\r\n</table>\r\n</body></html>\r\n\r\n");

    } finally {
      _jspxFactory.releasePageContext(pageContext);
    }
  }

  private boolean _jspx_meth_c_out_1(JspTag _jspx_th_c_when_0, PageContext pageContext) 
	throws Throwable {
    org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_out_1 = new OutTag();
    _jspx_th_c_out_1.setValue((Object) PageContextImpl.proprietaryEvaluate("Just set the 
	name from request! [${nameBean.name}]"));
    _jspx_th_c_out_1.setDefault("null");
    int _jspx_eval_c_out_1 = _jspx_th_c_out_1.doStartTag();
    if (_jspx_th_c_out_1.doEndTag() == Tag.SKIP_PAGE) {
      return true;
    }
    return false;
  }

  private boolean _jspx_meth_c_set_1(JspTag _jspx_th_c_if_0, PageContext pageContext) 
	throws Throwable {
    org.apache.taglibs.standard.tag.rt.core.SetTag _jspx_th_c_set_1 = new SetTag();
    _jspx_th_c_set_1.setPageContext(pageContext);
    _jspx_th_c_set_1.setParent((Tag) _jspx_th_c_if_0);
    _jspx_th_c_set_1.setVar("tableColorVar");
    _jspx_th_c_set_1.setValue(new JspValueExpression("/codegen.jsp(42,4)
                 '${param.tableColor}'",_el_expressionfactory.createValueExpression(new
                  ELContextWrapper(pageContext.getELContext(),_jspx_fnmap),
		 "${param.tableColor}",Object.class))
                  .getValue(pageContext.getELContext()));
    int _jspx_eval_c_set_1 = _jspx_th_c_set_1.doStartTag();
    if (_jspx_th_c_set_1.doEndTag() == Tag.SKIP_PAGE) {
      return true;
    }
    return false;
  }

  private boolean _jspx_meth_c_if_0(PageContext pageContext) throws Throwable {
    org.apache.taglibs.standard.tag.rt.core.IfTag _jspx_th_c_if_0 = new IfTag();
    _jspx_th_c_if_0.setPageContext(pageContext);
    _jspx_th_c_if_0.setParent(null);
    _jspx_th_c_if_0.setTest(((Boolean) PageContextImpl.proprietaryEvaluate("${not 
	empty param.tableColor}")).booleanValue());
    int _jspx_eval_c_if_0 = _jspx_th_c_if_0.doStartTag();
    if (_jspx_eval_c_if_0 != Tag.SKIP_BODY) {
      do {
        if (_jspx_meth_c_set_1(_jspx_th_c_if_0, pageContext)) return true;
        int evalDoAfterBody = _jspx_th_c_if_0.doAfterBody();
        if (evalDoAfterBody != BodyTag.EVAL_BODY_AGAIN) break;
      } while (true);
    }
    if (_jspx_th_c_if_0.doEndTag() == Tag.SKIP_PAGE) {
      return true;
    }
    return false;
  }
}

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=198157
ArticleTitle=Comment lines: Scott Johnson: JavaServer Pages for beginners
publish-date=02282007