The Web scripting capability of Java Specification Request (JSR) 223, Scripting for the Java Platform, specifies what a script engine must implement so that code written in the script language can run in a servlet container. In this article, we will equip BoolScript, a simple Boolean language I introduced in my previous JavaWorld article, "Build Your Own Scripting Language for Java," with Web scripting. If we draw an analogy between BoolScript and JavaServer Pages (JSP) in regards to Web scripting, we can see that essentially what we will be doing in this article is turning our BoolScript engine into something like a JSP engine. A JSP engine allows JSP code to run in a servlet container. Similarly, a BoolScript engine allows BoolScript code to run in a servlet container.
Before we begin, a word of caution is in order: JSR 223 implementation is still a work in progress. The implementation of Web scripting is not yet included in Java Platform, Standard Edition 6 beta build 80 (Java SE is Sun's new name for J2SE), the latest build as of this writing. Besides the Java SE beta, another source we can turn to for a JSR 223 implementation is the reference implementation. However, this reference implementation is dated to the extent that it is broken if you use it with build 80. In the article's example code, I spent minimum effort fixing those issues since they are temporarily due to the beta quality of the Java SE build. Although I can't speak for the Java SE development community, I believe the implementation and specification will undergo some changes, but the concepts and overall structure will remain. And in the production release of Java SE 6, the temporary issues will all be fixed. For now, think of my temporary fixes as an opportunity to see how things work behind the scenes.
This article doesn't require much knowledge of Java servlets. If you know the use of a servlet context in a servlet and the basics of deploying a servlet in a servlet container, you know enough to proceed.
To set up the environment for this article's example code, you need three things:
The article's code example, which can be downloaded from Resources, comes in two files:
After you download all the required software, you must perform the following steps to set up and run the example code.
<Server>
...
<Service>
...
<Engine>
...
<Host>
...
<Context path="/BoolScript" docBase="BoolScript"
debug="0" reloadable="true" />
...
</Host>
</Engine>
</Service>
</Server>
Now you are ready to test the example. Ensure the Tomcat server is up and running. Open a Web browser and type in this URL: http://localhost:8080/BoolScript/logic.bool. If everything is set up correctly, the result you will see should look like this: [true, false, true].
The figure below and subsequent list describe the sequence of events that occur when you run the above test. The rest of the article explains the various parts of this figure in detail.
Overview of example. Click on thumbnail to view full-sized image.
getScriptSource() method on the HTTP script context to get the script source file logic.bool
From the figure and the list above, you can see that the script servlet and the HTTP script context are the key components that carry out script evaluation in a servlet container. Let's first look at the script servlet in detail. Then I'll explain the HTTP script context and its functionalities. After those discussions, we will look at the configurations that glue together all the parties depicted in the figure above.
JSR 223's Web scripting framework consists of mainly three items: script servlet, HTTP script context, and configurations.
(Note: Though these are not standard terms, they prove helpful for our discussion.) Let's discuss them one-by-one, starting
with the script servlet. A script servlet is really just a servlet (i.e., an instance of GenericServlet). A servlet performs its tasks in its service() method and so does a script servlet. Like a typical servlet, a script servlet performs in its service() method tasks such as processing an HTTP request and stuffing Web contents in an HTTP response. Unlike a typical servlet,
a script servlet, while performing its tasks, runs script code in one or more script engines.
Now that I've explained a script servlet at a conceptual level, let's talk about the code. A servlet must directly or indirectly
derive from javax.servlet.GenericServlet. In this article's example code, we implement a script servlet class called BoolScriptServlet. It inherits GenericHttpScriptServlet, which in turn inherits GenericServlet. From this, we confirm that our script servlet is a bona fide servlet as I claimed it must be.
If you look at the JSR 223 reference implementation, you'll notice that it provides a subtype of GenericServlet called HttpScriptServlet in the javax.script.http package. HttpScriptServlet is a convenience class on which script engine providers can base their script servlet classes. Unfortunately, it is dated
and cannot work with Java SE beta 6 build 80. Otherwise I would have derived BoolScriptServlet from HttpScriptServlet instead of GenericHttpScriptServlet. I implemented GenericHttpScriptServlet as a quick fix of the issues I found in HttpScriptServlet.
While I was at it, I also improved the implementation a bit by declaring an abstract method called runScript() in GenericHttpScriptServlet. This is helpful because the bulk of GenericHttpScriptServlet's service() method is boilerplate code necessary to make a script servlet class conform to JSR 223's Web scripting framework. If a script
servlet class derives from GenericHttpScriptServlet, the only part it will most likely want to change in the inherited service() method is how it will invoke a script engine to execute script code. By deriving from GenericHttpScriptServlet, a script servlet class gets to keep the boilerplate code in the service() method and, at the same time, has the flexibility of customizing how it will invoke a script engine in the runScript() method.
Another important method is the getContext() method in BoolScriptServlet.java:
public HttpScriptContext getContext(HttpServletRequest request, HttpServletResponse response) throws ServletException {
if (ctx == null)
ctx = new SimpleHttpScriptContext();
ctx.initialize(this, request, response);
return ctx;
}
The getContext() method returns an HTTP script context (i.e., an instance of some class that implements the interface javax.script.http.HttpScriptContext), the topic of the next section. For now, the important thing to know is that a script servlet should initialize the HTTP
script context for every HTTP request the servlet receives. And the place where a script servlet does that initialization
is in its getContext() method. The line of code in bold above shows that the getContext() method calls the initialize() method on the HTTP script context to initialize it before returning it back to the caller. We will see in the next section
what the initialization does and why a script servlet should initialize the HTTP script context for every HTTP request.
A servlet runs in a servlet context. Since a script servlet is a servlet, it also runs in a servlet context. But in addition
to a servlet context, a script servlet has another context that a typical servlet doesn't have called an HTTP script context
(i.e., an instance of some class that implements interface javax.script.http.HttpScriptContext). The purpose of a servlet context is to provide a servlet with a view of the Web application the servlet runs in. The purpose
of an HTTP script context is to provide a script (i.e., code written in a script language) with a view of the script engine
the script runs in.
An HTTP script context is a script context, which I discussed in my previous article. So whatever I said about script context there still holds true for our discussion of the HTTP script context here. To refresh what we learned, recall that a script context has zero or multiple scopes; a scope is basically just a collection of name-value pairs. In the previous article, I discussed global and engine scopes.
So what's new about HTTP script context? Not much except that it is required to have three special scopes and has some methods for accessing configuration information, which I'll talk about later. The three special scopes are request scope, session scope, and application scope. Why do we need those three scopes and what do we do with them? Recall that in the previous article, I described a script context as a means for you to pass data back and forth between a host Java application and a script engine. Similarly, an HTTP script context is a means for you to pass data back and forth between a host Web application and a script engine. When a host Web application invokes a servlet upon an HTTP request, it passes the servlet the HTTP request and the corresponding HTTP response.
Archived Discussions (Read only)