Java Server Pages (JSP) technology is extremely useful in web application implementation. Static page elements can be coded with literal HTML, and scripts for dynamically generated page elements can be interleaved with static elements in a formal syntactical structure that facilitates tooling.
Java is not, as one might assume, the only language which can be used as a scripting language for JSPs. The Sun Java Server Pages specification ties the definition of JSP quite closely to the Java Runtime Environment (JRE) as a target platform, but it leaves the door open for scripting languages other than Java.
This paper describes how Smalltalk can be used as a scripting language for JSPs, with VisualAge Server Smalltalk (SST) an the intended runtime environment. This approach is not claimed to be compliant with the JSP specification. Specifically, we do not indicate JRE as a target platform.
Nevertheless, the use of Smalltalk as a scripting language for JSPs has all of the general benefits of using Java as a scripting language for JSPs. In particular, web page authoring tools which recognize JSP syntax may be used to build pages which make use of Smalltalk as the page scripting language.
The JSP compiler for Smalltalk presented here will be referred to as 'JSPS'. Source for the implementation and sample deployment code, for VisualAge Smalltalk (VAST) version 6.0, is provided in an accompanying ENVY/Manager export (".dat") file. Sample JSP source is provided as well.
The remainder of this paper assumes some basic familiarity with Java Server Pages and with the SST web application server (or servlet container).
An SST web application server is configured to support JSP requests by including the JSP compiler servlet in a web application configuration. This is illustrated in the source for the following method.
SstJspDevelopmentSupport class>>#exampleWebAppSpec
As configured in this example method, our sample web application will have a servlet context path of '/ssteg' and will have a DocumentRoot indicating a subdirectory of the image startup directory named 'htdocs'.
An SST web application server hosting this web application can be configured according to the example in the following method.
SstJspDevelopmentSupport class>>#exampleWebServerSpec
Using these two helper methods, we can start an SST web application server with JSP support by evaluating the Smalltalk expression below. (Be sure and inspect the result, to facilitate server shutdown).
SstJspDevelopmentSupport exampleWebServerSpec instantiateAndRun
Now consider the following example JSP source.
<%@ page language='Smalltalk' %> <HTML><BODY> <H1>Example Time Server</H1> The time is now <%= DateAndTime now %> </BODY></HTML>
Note that this JSP includes a Smalltalk JSP expression that will generate the current date and time on demand.
We will place this source in a file named 'TimeNow.jsp', and place this file in the web application DocumentRoot directory - 'htdocs'. Then we can get to our time server from a local browser via the following URL.
http://localhost:9080/ssteg/TimeNow.jsp
JSPS has a number of limitations. These limitations are not a result of Smalltalk being the scripting language, but rather reflect the incomplete status of the development of JSPS. This section amplifies the JSP Core Syntax to note JSPS implementation details, and to identify areas where JSPS is incomplete.
There are three types of JSP elements: directive elements, scripting elements, and action elements. The JSP compiler for Smalltalk presented here supports only directive elements and scripting elements, and it supports all three defined types of scripting elements: scriptlets, declarations, and expressions.
Directives have the following syntax.
<%@ directive { attr=‘value’ } * %>
JSPS supports only the 'page' and 'include' directives. The ‘page’ directive’s ‘language’ attribute must appear in the JSP code before any other tag.
<%@ page language=‘Smalltalk’ %>.
The 'include' directive provides for dynamic inclusion of static content from files residing on the servlet container's filesystem. An include directive might look like the following.
<%@ include file=‘acme_boilerplate.html’ %>.
JSPS includes file contents at request time. Included content is not parsed by the JSP translator, and therefore may not contain JSP source.
Scripting elements have start and end tags <% and %>, respectively. There are three types of JSP scripting elements.
JSPS declarations are enclosed within <%! and %> tags and are used to declare page-scope variables (i.e., variables whose binding persists across requests).
Eg: <%! | index count | %>
JSPS expressions are enclosed within <%= and %> tags. The result of evaluating the Smalltalk code between these tags is written to the output stream. By default, evaluation results are written using #printOn:; class-based custom formatting for HTML can be provided by implementing #jspPrintOn: as an instance method on the evaluation results class.
Expressions must not be terminated with a full-stop.
Eg: <%= DateAndTime now %>
JSPS scriptlets are Smalltalk statements enclosed within the tags <% and %>. They may contain local variable declarations (request-scope variables), conditionals, loop constructs - in general, any portion of syntactically correct Smalltalk code.
Eg: <% out nextPutAll: 'Hello, World!'. %>
A scriptlet which is used to declare request-scope variables must appear on the page before any other scripting elements (page directives may appear before it).
The following example declares a request-scope variable named 'credentials'.
Eg: <% | credentials | %>
JSPS supports the implicit objects 'request' and 'out'.
The 'request' implicit object corresponds to the Smalltalk class SstHttpServletRequest.
The 'out' implicit object is a stream and understands the messages #nextPutAll and #cr. It's output is automaticaly flushed when page processing is complete.
It is illegal to assign to either variable (use either in the left-hand side of an assignment statement).
As noted above, JSPS scriptlets are snips of Smalltalk source. This source may include comments according to Smalltalk language conventions.
Eg: <% "go smalltalk" %>
HTML comments are supported, but may not include JSP source delimiters.
JSPS does not support any JSP standard actions.
Here we describe a few implementation-specific features of JSPS source compilation.
JSPS has two configuration switches that aid in error handling and debugging for JSP source that does not compile. The first of these is:
SstJspErrorHandler class>>trapExceptions
If the #trapExceptions flag is set, then a request for a page containing a compiler error causes a Workspace to appear with the source in error highlighted.
This Workspace window provides a menu pick for "Show JSP Error" which opens an inspector on an instance of CompilerError.
The second of these switches is:
SstJspErrorHandler class>>forwardExceptions
If the #forwardExceptions flag is set, then a request for a page containing a compiler error causes an HTML response page to be returned to the user agent (i.e., browser), with JSP source and the source in error highlighted. Otherwise, a default error page is returned to the user agent.
Error 500
Jsp compilation error
Compiled JSP source pages are cached. On each request for a page, the page's source file modification time is checked to determine whether the cached code is valid.
The size of the compiled code cache can be configured, as follows.
SstJspCodeCache default size: 128.
During development, The cache can be cleared or disabled.
SstJspCodeCache default clear. SstJspCodeCache default disable.
Page-processing debugging techniques for JSPS are similar to those for SST servlets. Breakpoints cannot be set in the compiled JSP page. However, breakpoints can be set in methods invoked from the JSP page, and breakpoints can be set just prior to invocation of the compiled JSP page.
SstJSPServlet>>#service:
In addition, scriptlets can send the #halt message to suspend page processing and invoke the VAST interactive debugger.
Compiled JSPS pages are executed by the SST servlet container. Page-processing exceptions are handled by the servlet container as it would handle a similar exception in a servlet.
Generally, packaging and deployment for JSPS is best considered an extension of packaging and deployment for an SST web application server. With this in mind, the procedure presented below is derived from the the SST web application server packaging example.
We will build a "base platform" image component (IC) which extends the shipped example by inclusion of the application SstJspSupport. We then package a "startup" IC using the shipped example instructions. In contrast to the servlet packaging example, our example JSP server requires only these two ICs. There is no application-specific function in our example other than what is provided by the JSP source files.
JSPS generates Smalltalk source code and employs the Smalltalk compiler to compile this source. Runtime deployment of JSPS, therefore, requires runtime deployment of the Smalltalk compiler.
Runtime deployment of the Smalltalk compiler is a supported feature of VAST/6.0, but requires a patch for EmSystemConfiguration>>#startUpClass. This patch is available for download from the VAST product support website - http://www.ibm.com/software/ad/smalltalk/support. To locate the source for the patch, search for the words "packaging compiler".
Ensure that the product feature "ST: Server, SST" is loaded in the development image.
In the development image, ensure that the application SstPackagingExamples is loaded. Create a new XD passive image for the intended target platform. Include the following features in the new passive image.
Load the application SstJspSupport into the new passive image. Open the Packager Control Panel.
Using the procedure described below, base and startup IC files will be written to different subdirectories of the directory specified by the image configuration file ("abt.ini") property "PackagingRootDirectory". By default, this is the subdirectory of the product install directory named "icspk600".
On multi-user platforms, this directory is not typically writable by individual users. In this case, the "PackagingRootDirectory" property will have to be modified (and the image restarted) before proceeding.
Select "Instructions in Database". Expand "SstPackagingExamples". Select "SstEgServletBaseICInstructions". Modify the instructions short description, as desired. (For example, "SSTEG Servlet-JSPS Base Platform IC").
Select "Modify Instructions". Add the application "SstJspSupport". Select "Reduce", and then "Examine and Find Problems".
Select "Save Instructions". Provide a class name for your new instructions. (For example, "SstEgServletJSPBaseICInstructions"). Specify the instructions superclass as SstEgServletBaseICInstructions. Specify a development-time application to be the controller for your new instructions class.
Select "Output Image".
Select "Instructions in Database". Expand "SstPackagingExamples". Select "SstEgServletStartUpICInstructions". Modify the instructions short description, as desired. (For example, "SSTEG Servlet-JSP Platform StartUp IC").
Select "Modify Instructions". Select "Default ICs". Add the application "SstJspSupport". Add your base platform IC as a prerequisite IC. Select "Reduce", and then "Examine and Find Problems".
Select "Save Instructions". Provide a class name for your new instructions. (For example, "SstEgJSPSStartUpICInstructions"). Specify the instructions superclass as SstEgServletStartUpICInstructions. Specify a development-time application to be the controller for your new instructions class (likely, the same application used for the base IC instructions).
The SST servlet container used here required a configuration file at runtime. This configuration file is expected to be a dumped instance of SstWebServerSpecification. To create this file, evaluate the following expression in your development image.
SstJspDevelopmentSupport exampleWebServerSpec swapToDisk
For this example, we will use the filename "sstjsps.cfg".
The base and startup IC files will have been written to the following subdirectories, respectively, of the "PackagingRootDirectory".
ssteg/startup/sstegse.ic ssteg/base/sstwww_base.ic
These should be copied to a common runtime startup directory. For purposes of this tutorial, we will refer to this directory as "/sstjsps".
Copy "sstjsps.cfg" and "abt.ini" to "/sstjsps". Rename the ".ini" file "sstegse.ini".
Create an 'htdocs' subdirectory, and copy "Time.jsp" to this directory.
Open an OS shell window. Change directory to "/sstjsps". Ensure that the VAST "bin" directory is in your command path.
nodialog -lsstegse.log -isstegse.ic --conf sstjsps.cfg
Many thanks to Cohan Carlos for his original work on the JSP support for VisualAge Smalltalk presented here.
<%@ page language='Smalltalk' %>
<HTML><BODY>
<H1>Example 1</H1>
<H3>A Table with dynamically-generated rows</H3>
<TABLE border="1">
<TR>
<TH rowspan="2">
<TH colspan="2">Average
<TH rowspan="2">Red<BR>eyes
</TR>
<TR><TH>height<TH>weight</TR>
<%
#(
('Males' 1.9 0.003 40)
('Females' 1.7 0.002 43)
)
do: [:rowData|
%>
<TR>
<TH><%= rowData at: 1 %>
<TD><%= rowData at: 2 %>
<TD><%= rowData at: 3 %>
<TD><%= rowData at: 4 %>%
</TR>
<% ]. %>
</TABLE>
</BODY></HTML>
<%@ page language='Smalltalk' %>
<HTML><BODY>
<!-- Page-scope Variable Declaration -->
<%! | hitCount | %>
<%
[ hitCount isNil
ifTrue: [hitCount := 1]
ifFalse: [hitCount := 1 + hitCount]
] critical.
%>
<H1>Example 2</H1>
<H3>A page-scope variable declaration</H3>
<P>
<%
hitCount = 1
ifTrue: [ out nextPutAll: 'This is the first request to this page.'.]
ifFalse: [
%>
There have been a total of <%= hitCount %> requests to this page.
<% ]. %>
</BODY>
</HTML>