This article is translated to Serbo-Croatian language by Vera Djuraskovic from Webhostinggeeks.com.
PolyJsp is an extensible JSP implementation designed to support multiple scripting languages and multiple JSP versions.
Completely based on XML and XSL, PolyJsp currently supports Java, Javascript and WebL as scripting languages. Support is provided for the latest JSP spec (0.92), with some exceptions documented below.
PolyJsp is a free, open source product. Developers are encouraged to contribute to its development and enhancement.
Comments and suggestions can be sent to
Ricardo Rocha.
PolyJsp is a direct descendant of ESP (EcmaScript Pages), a servlet used for authoring dynamic web pages in EcmaScript.
What started as a "simple" effort to make ESP JSP-compliant eventually led to a polyglot, extensible implementation.
ESP users are encouraged to upgrade to PolyJsp as its EcmaScript processor is backwards-compatible with ESP and no further enhancements to this product will be developed once PolyJsp is released.
PolyJsp aims at:
The first goal is relevant because most of current JSP implementations are based on the aging 0.91 spec and, despite their established code base, their syntaxes may be rendered obsolete as JSP continues to evolve.
Multiple language support, on the other hand, is desirable to leverage potential authors' previous familiarity with "legacy" languages. It is also called for to support web publishing of dynamic content generated by specialized applications written in field-specific languages.
In the case of Javascript, in particular, HTML authors will certainly benefit from using a single language for both server and client side scripting.
Note: throughout this document the names JavaScript and EcmaScript are used interchangeably
Thanks to PolyJsp's extensible design, new languages and versions can be easily added in a mostly declarative way.
In principle, any language for which a Java interpreter exists can be added to PolyJsp's repertoire. There are currently over 60 such languages ranging from the classic and simple to the experimental and sophisticated. For more information on language availability, see Robert Tolksdorf's Programming Languages for the Virtual Java Machine.
Languages for which there is no Java interpreter could be supported by means of simple inter-process communication (e.g. stdin/stdout, CORBA-based IPC). Another option is the JDBC-based execution of statement blocks written in procedural extensions to SQL, such as Oracle's PL/SQL.
New language processors can be easily added as specialized Java classes or as XML declarative language definitions "scripted" with Javascript. The scripted approach has been tested successfully to provide support for the Java language itself as well as for (Dartmouth) Basic.
Adding a new version is even easier as it just entails writing a declarative definition of JSP version tags (a small XML file) and one or more language-specific templates (XSL stylesheets optionally adorned with code generation Javascript extensions)
Version tag syntax files are dynamically loaded by the parser at runtime on a per-script basis; thus, PolyJsp can support multiple versions simultaneously.
Source code generators are implemented as XSL stylesheets that transform the DOM tree produced by the JSP parser into an equivalent program written in the target scripting language.
In its current alpha version, PolyJsp supports Java, Javascript and WebL, as well as the JSP 0.92 spec.
JSP directives (<%@%>), declarations (<SCRIPT RUNAT="server">), scriptlets (<%%>) and expressions (<%=%>) are fully supported.
Support for the <BEAN> and associated tags is currently under development together with the runtime library that provides bean management and introspection.
PolyJsp introduces a few (optional) extensions to JSP:
For the Java language, PolyJsp provides complete servlet generation, cataloging and compilation as well as automatic reloading. Currently, the built-in Sun compiler is used.
For Javascript, PolyJsp uses FESI and provides persistent source code generation, automatic reloading and evaluator pooling to speed up execution. Despite their interpreted nature, Javascript pages perform at speeds comparable to their Java counterparts.
For WebL, PolyJsp provides persistent source code generation and automatic reloading. Like in the Javascript case, WebL pages perform at speeds comparable to Java.
These components are integrated within the following flow of execution:
During this process, error conditions are trapped and reported to the user either through a script-specified error page or a servlet-generated HTML error message. Output buffering may be used to avoid garbling program output and servlet error pages.
As a general rule, version-specific JSP tags (such as <USEBEAN> or <DISPLAY>) are not built into the parser's lexical productions; rather, they are made special by means of a dynamically loaded XML version tag file. This is the esence of the version independence mechanism.
JSP directives (<%@ ... %>), scriptlets (<% ... %>) and expressions (<%= ... %>) are directly recognized by the parser.
Also recognized by the parser is the <SCRIPT RUNAT="server"> tag. This is a special case because the <SCRIPT> tag may be legitimately present in the client-side code as well.
Finally, NCSA directives (such as <!--# include>) are also recognized by the parser, though this may be disabled to allow for the underlying web server itself to process them.
JSP version selection is performed at runtime and on a per-script basis. Therefore, the same PolyJsp instance can support multiple versions simultaneously.
A PolyJsp propietary directive tag (<%@ version="..." >) has been added to allow scripts to specify a particular version. In absence of explicit version selection, the current implementation defaults to 0.92, though this can be overriden by setting the polyjsp.default.version system property.
In the same vein, and according to the spec, the language directive defaults to java; again, this can be changed by setting the polyjsp.default.language system property.
Depending on version selection, the parser dynamically loads the corresponding tag
definition xml file. For version 0.92 this file contains:
<tags>
<tag name="comment" empty="true" body="true"/>
<tag name="declaration" empty="false" body="false"/>
<tag name="errorpage" empty="true" body="false"/>
<tag name="import" empty="true" body="false"/>
<tag name="language" empty="true" body="false"/>
<tag name="boilerplate" empty="true" body="true"/>
<tag name="display" empty="true" body="true"/>
<tag name="excludeif" empty="false" body="true"/>
<tag name="expression" empty="true" body="true"/>
<tag name="include" empty="true" body="true"/>
<tag name="includeif" empty="false" body="true"/>
<tag name="loop" empty="false" body="true"/>
<tag name="scriptlet" empty="true" body="true"/>
<tag name="setfromrequest" empty="true" body="true"/>
<tag name="setoncreate" empty="true" body="true"/>
<tag name="usebean" empty="false" body="true"/>
<!-- Non-standard tags added by PolyJsp -->
<tag name="contenttype" empty="true" body="false"/>
<tag name="header" empty="true" body="false"/>
</tags>
where boolean attribute usage is:
Attribute | Meaning |
---|---|
empty | This is an empty tag, not containing nested subtags or text |
body | This tag is not a directive or declaration, must be made part of the generated source program |
Beyond this clasification (needed only to control parsing recursion and tree generation), the parser does not attempt to interpret the actual contents of JSP tags.
All remaining JSP script content (typically HTML tags and plain text) is treated as boilerplate and inserted verbatim into the generated DOM tree body.
For details about the structure and contents of JSP DOM trees, please see the JSP 0.92 DTD.
Version DTD's are used used to validate JSP tag attribute values as well as tag and boilerplate nesting during DOM tree construction.
Scripting languages are defined in an XML file loaded at startup. For Java
and Javascript this file contains:
<languages>
<language
name="java"
source-extension="java"
object-extension="class"
processor="org.plenix.jsp.language.java.JavaProcessor"
>
<version name="0.92" stylesheet="java-0.92.xsl"/>
</language>
<language
name="ecmascript|javascript"
source-extension="es"
processor="org.plenix.jsp.language.ecmascript.ESProcessor"
>
<version name="0.92" stylesheet="ecmascript-0.92.xsl"/>
<version name="0.91" stylesheet="ecmascript-0.91.xsl"/>
<param name="extension" value="FESI.Extensions.BasicIO,FESI.Extensions.FileAccess,FESI.Extensions.Database"/>
</language>
</languages>
where a processor is a Java class implementing the LanguageProcessor interface.
Alternatively, language processors may be defined embedding EcmaScript handlers in the
<language>
tag as follows:
<language name="..." source-extension="..." object-extension="..." />
...
<init-script>
// Init logic
...
</init-script>
<compile-script>
function compileProgram(baseName, path) { ... }
</compile-script>
<load-script>
function loadProgram(baseName, path) { ...; return objectProgram }
</load-script>
<unload-script>
function unloadProgram(objectProgram) { ... }
</unload-script>
<execute-script>
function executeProgram(objectProgram, request, response) { ... }
</execute-script>
</language>
Function names and signatures must be specified as shown above. However, only the loadProgram and executeProgram functions are required.
For an example of a scripted language processor, please see the simplified scripted Java language definition.
Source code is generated by applying XSL stylesheets to DOM trees built by the parser. A separate XSL stylesheet is needed for each language/version pair.
For an example of a code generation XSL stylesheet, please see the simplified EcmaScript 0.92 stylesheet.
Thus, given the following input JSP script:
<%@ version="0.92" %>
<%@ language="javascript" %>
<%@ contenttype="text/html" %>
<header name="expires" value="Tues, 01 Jan 1980 00:00:00 GMT">
<%@ import="util.es" %>
<SCRIPT RUNAT="server">
var accessCount = 0;
</SCRIPT>
<%
var today = new Date();
%>
<HTML>
<HEAD>
<TITLE>A PolyJsp Demo</TITLE>
</HEAD>
<BODY BGCOLOR="#ffffff">
<H1><FONT COLOR="navy">A PolyJsp Demo</FONT></H1>
<P>
This page has been accessed <%= ++accessCount %> times so far.
<P>
Generated by PolyJsp on <%= today %>
</BODY>
</HTML>
PolyJsp's parser will produce a DOM tree equivalent to the following XML document:
<jsp-script name="sample.jsp">
<version>0.92</version>
<language>javascript</language>
<import>util.es</import>
<contenttype>text/html</contenttype>
<header name="expires" value="Tues, 01 Jan 1980 00:00:00 GMT"/>
<declaration><![CDATA[
var accessCount = 0;
]]></declaration>
<body>
<scriptlet><![CDATA[
var today = new Date();
]]></scriptlet>
<boilerplate><![CDATA[\n\n<HTML><HEAD><TITLE>A PolyJsp Demo</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n]]></boilerplate>
<boilerplate><![CDATA[<H1><FONT COLOR=\"navy\">A PolyJsp Demo</FONT></H1><P>\n]]></boilerplate>
<boilerplate><![CDATA[This page has been accessed \n]]></boilerplate>
<expression><![CDATA[++accessCount]]></expression>
<boilerplate><![CDATA[ times so far.\n]]></boilerplate>
<boilerplate><![CDATA[<P>\n]]></boilerplate>
<boilerplate><![CDATA[Generated by PolyJsp on \n]]></boilerplate>
<expression><![CDATA[today]]></expression>
<boilerplate><![CDATA[</BODY></HTML>\n]]></boilerplate>
</body>
</jsp-script>
When the above mentioned EcmaScript 0.92 stylesheet is applied to this
DOM tree, the following Javascript source file will be generated:
// User imports
load("util.es");
// Declarations
var accessCount = 0;
function service(servletrequest, servletresponse) {
var headerCount = 0;
var headers = new Array();
var errorPage = null;
var contentType = "text/html";
var input = servletrequest.getReader();
var output = servletresponse.getWriter();
servletresponse.setContentType(contentType);
headers[headerCount++] = new Header("expires", "Tues, 01 Jan 1980 00:00:00 GMT");
for (var i = 0; i < headers.length; i++) {
servletresponse.setHeader(headers[i].name, headers[i].value);
}
// User code
var today = new Date();
output.print("\n\n<HTML><HEAD><TITLE>A PolyJsp Demo</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n");
output.print("<H1><FONT COLOR=\"navy\">A PolyJsp Demo</FONT></H1><P>\n");
output.print("This page has been accessed \n");
output.print(++accessCount);
output.print(" times so far.\n");
output.print("<P>\n");
output.print("Generated by PolyJsp on \n");
output.print(today);
output.print("</BODY></HTML>\n");
}
The adventurous may download the current alpha version in polyjsp.tgz (188k). Please note that, for now, this is only a (functional) daily snapshot.
The first beta version will be made available shortly with complete Javadoc documentation.
PolyJsp requires the following additional tools:
These libraries are included in the polyjsp.tgz distribution file. Note that,
currently, PolyJsp requires the specific versions of these products that have
been included in the distribution. Work is under way to upgrade PolyJsp to the
latest version of the XML and XSL processors.
To install PolyJsp you must have:
PolyJsp requires an installation directory that must be accessible to your servlet engine. This structure is contained in the polyjsp.tgz distribution file with the following subdirectories:
To configure PolyJsp in your web server/servlet engine environment follow these steps:
Parameter | Required? | Default Value | Contents |
---|---|---|---|
configurationDirectory | Yes |
Directory containing PolyJsp XML/XSL resource files.
This is normally subdirectory config under your PolyJsp installation directory |
|
stageDirectory | Yes |
Directory to place generated source and object files.
This is normally subdirectory stage under your PolyJsp installation directory |
|
defaultLanguage | No | java | Language to be used when JSP scripts do not explicitly specify a language |
defaultVersion | No | 0.92 | Version to be used when JSP scripts do not explicitly specify a version |
Special thanks to Peter Saitz (Optical Arts) for his invaluable quality control and implacable bug-hunting.
Special thanks to Alfonzo Forgione (AF Advanced Systems) for his sponsorship and continued support to PolyJsp.
Thanks, too, to all developers behind the free/open-source products used to develop PolyJsp: