Home Downloads JSSP Docs JSSQL Docs Dervish Docs License Examples Feedback
JSSP (JavaScript Server Pages) is a Java runtime library to execute JavaScript on a web server similar to ASP, PHP or JSP. It requires a web server that can run Java Servlets (such as Tomcat, JBoss or others).
The current version of JSSP is 0.2beta. This version is considered fairly feature-complete. The functionality described here is not expected to change much any more.
If you don't have much Java experience, check out the JSSP tutorial which will tell you how to set up and use JSSP.
Any comments and bug reports are highly appreciated by leo_meyer@users.sourceforge.net!
Bug reports, feature requests and forum posts can be submitted on the JSSP Project Page.
Note: This document uses Google's code prettifier. In Internet Explorer you may get warning messages about active content. You can safely allow active content or simply ignore these messages.
JSSP allows you to mix HTML and JavaScript code in a way similar to ASP, PHP and JSP. Script code that is to be executed on the web server has to be put in sections enclosed by <% and %>.
Example:
hello.jssp
<html> <body> <% out.print("Hello JSSP!"); %> </body> </html> |
The words "page", "script" and "request" are used somewhat synonymously in this document. A "page" is the raw JSSP file (or "script file") that you edit. It is converted internally to a "script". When the script runs on a web server it is said to be executed as a "request". All these terms refer to the same thing, but their connotations are a little different.
There may be more than one request for the same page at a given time, i.e., the same script can run more than once simultaneously. To avoid certain problems arising from this situation, see the section Sharing common data.
To get started quickly you can fire up your Tomcat or other Java servlet container and deploy jssp_example.war from the download section. This example also contains instructions on how to set up a database to test the embedded SQL features. You can then play around with the example .jssp files to get acquainted with JSSP.
The JSSP tutorial will tell you how to set up and use JSSP without any previous experience with Java or Tomcat.
To use JSSP in your Java web application you can download the current distribution package from the download section. Unzip it and add the file jssp*.jar to your web application's Java library folder (WEB-INF/lib). Add the following lines to the <web-app> element of your web.xml file:
<servlet> <servlet-name>JSSPDefaultApplication</servlet-name> <servlet-class>net.sf.jssp.JSSPServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>JSSPDefaultApplication</servlet-name> <url-pattern>*.jssp</url-pattern> </servlet-mapping>
This will run the JSSP servlet for all files ending in .jssp.
Make sure that your JDBC driver is on the classpath if you are using the embedded SQL features. JDBC drivers typically come in .jar files that are put into the WEB-INF/lib folder.
For more information please see Configuring the JSSP servlet.
If you want to define data sources, use library modules or specify resource files for internationalized texts you will also want to add a jssp.xml file to the WEB-INF/lib folder. See the configuration file jssp.xml for more information.
JSSP web applications are usually deployed in a web archive (.war file). A .war file contains the application's code and libraries in a certain format. The file itself is a zip archive that gets the extension .war.
The structure of a .war file for JSSP deployment look like this:
/ <-- Top level folder. .html, .jssp and other files | go here. At least a file "index.html" should be there. + WEB-INF/ <-- Web information folder. Contains web.xml and | | jssp.xml files. jssp.xml is optional. | + lib/ <-- Java libraries (jar) folder. Must contain | | at least the jssp*.jar library. JDBC drivers | | should also be deployed here. | + resources/ <-- Folder for localized application resources. | | | + jssp/ <-- Folder for application libraries. This | includes Dervish libraries. + .../ <-- other folders containing images, style sheets etc.
.war files can be deployed to a servlet container like Tomcat, JBoss or Winstone. The deployment is server-specific. The JSSP tutorial can provide you with an example.
Code that is included in <% ... %> will be executed on the server when the page is called. Content outside of these tags will be sent to the web server 'as is'.
Currently the parsing is not context sensitive. The following example will be invalid syntax:
<h1> <% out.print("%>"); // syntax error! %> </h1>
In the unlikely event that you ever need this or similar code, use out.print("%" + ">");
After the <%= tag you can specify a JavaScript expression. Thus you can avoid the somewhat clumsy out.print(...); statements.
Do not put semicolons or line comments (//) into these tags. This will most likely generate an invalid script that can't be executed correctly. Block comments (/* ... */) are ok, though. For example, the following code is invalid:
<%= myValue // print it %>Internally this code will be converted to
out.print( myValue // print it );and you will easily see that this is invalid in JavaScript.
For easier debugging put <%= ... %> sections on separate lines wherever possible.
Code that is enclosed by <%COMMON ... %> will both be executed on the web server and sent to the client web browser by generating a <script> ... </script> section.
Use this special code tag to define functions that you need in the browser as well on the web server. This avoids code duplication.
Be careful with code in the COMMON tag, though. Use it only when generating HTML output (it won't be suitable for XML output, for example). Do not use it in loops. Remember that the programming models on the web server and in the browser are very different, so neither access server-specific objects like request or response nor browser-specific objects like window or document in common code sections. As a matter of fact, output routines like out.print() or alert() or file IO in general also won't work consistently.
Example:
<%COMMON type="text/javascript" function validateNonEmptyString(str, name) { if (str == "") return name + " must not be empty."; else return ""; } %>
The rest of the line after <%COMMON is reserved for client-specific information. It is not executed as part of the server side code. Rather it is sent to the browser as part of the opening <script> tag. The example above will be sent to the browser as the following output:
<script type="text/javascript"><!-- function validateNonEmptyString(str, name) { if (str == "") return name + " must not be empty."; else return ""; } //--></script>
The example page common_code.jssp and the library common_code_lib.jssp show you to use common sections with libraries.
Page directives are optional instructions about how the page is to be processed. Example:
<%@ encoding="utf-8" contentType="text/xml; charset=iso8859-1" charset="iso8859-1" %>
This example tells the JSSP engine to interpret the content of the script file as a UTF-8 character stream (directive encoding). The HTTP response content-type header will be set to "text/xml; charset=iso8859-1" (directive contentType). The encoding of the output that is sent to the browser will also be iso8859-1 (directive charset).
If page directives are used, they must start right at the beginning of the file and must appear only once.
Page directives are case sensitive. The following page directives are available:
Use this directive to specify how the bytes that make up the script file are converted into characters. You can specify a default encoding in the web.xml file as a parameter to the JSSP servlet. If unspecified, the system encoding will be used.
This value must be a valid Java charset name as defined by the class
Charset.
Specify the character set that is to be used for the script's output. If it is unspecified, the system's default character set is used. This directive has nothing to do with the encoding directive.
You can specify a default charset in the web.xml file as a parameter to the JSSP servlet.
It is recommended that the charset matches the one you have specified in the contentType directive. However, this is not mandatory, but be aware that client browsers may become confused if mismatching values are used.
This value must be a valid Java charset name as defined by the class Charset.
The value specified here is sent to the client as part of the HTTP response
headers. You can specify a default
content type in the
web.xml file as a parameter to the
JSSP servlet. If unspecified, "text/html;
charset=(default charset)" will be used.
Specify the JSSP version. At the moment this directive has no meaning. It may become important during further development of JSSP.
Include files are not supported by JSSP.
Include files can create lots of trouble. For example, cycle problems may
arise that have to be detected somehow. Include files mean external dependencies, so
a dependency tree has to be maintained and walked to detect changes to the
included files. In the end, it's not worth the hassle, as there is an easier
solution: use library code.
Library code is common code for all pages of a certain JSSP web application. It consists of one or more files that contain shared code. Library files are called modules. Modules must be defined in the configuration file (see Defining library modules below).
It is considered good practice to use library code because it makes the code easier to maintain. Resist the temptation to use copy and paste for multiple pages. If you find that you want to use identical functions or constants on more than one page, it's probably a good choice to put these into a library module.
If you want to use Dervish for client-server interoperability you need to put your server side Dervish code into library modules.
Libraries can be disabled. There is also a special type of unit test library that is automatically run when relevant application code changes.
Library code must follow some special rules to work correctly:
To avoid problems, you should modify libraries only while testing the application as a single user. If you are unsure whether changes require the removal of old code, restart the web application.
<% // mymodule.jssp // An example module demonstrating the "module pattern" myModule = (function() { // "private" functions and object definitions var MyObject = function(text) { this.text = text; this.print = function() { out.print(this.text); } } // "public" API of the module return { createObject: function(text) { return new MyObject(text); } } })(); // The library functions are now accessible globally // under the "namespace" myModule // test by writing to stdout myModule.createObject("Hello, here is the myModule library!\n").print(); %>
To use library code you must tell JSSP which files to use as library modules. A library module is a file that has been specified as a library code file.
It is recommended that you put all JSSP library modules into a WEB-INF/jssp folder to avoid accidental exposure of library code to clients.
To define library modules you must put a jssp.xml file into the WEB-INF folder of your web application (more information about the jssp.xml file).
Library modules are loaded and evaluated in the order of their appearance in the jssp.xml file.
WEB-INF/jssp/stringlib.jssp
<%@ encoding="iso8859-1"%> Loading JSSP String library at <%= new Date().toString() %>.<% // JSSP string library. // Contains functions that enhance the capabilities // of the String prototype. String.prototype.trim = function() { return this.replace(/^\s+/, "").replace(/\s+$/, ""); }; %> JSSP String library loaded at <%= new Date().toString() %>.
This short example demonstrates the use of a library file. The (optional) content outside of the code tags is printed to the standard output while the library is loaded.
While library files are being evaluated, the out object is set to stdout. This causes output to go to the web server console or log files. You can use this for testing library functions or for displaying info messages.
JSSP facilitates i18n by providing the messages object. The messages object is a convenient way of accessing resource strings that are defined in resource files.
You can define different resource files for different locales and languages. JSSP automatically selects the proper resource file depending on the browser's preferred languages. Alternatively, you can specify which resource file should be used.
JSSP also allows you to format locale-specific objects like dates or numbers using the messages.format function.
Example:
application.properties
# default application resource strings application.welcome=Welcome to our JSSP application! application.examples=The date is {0,date}, the string is ''{1}'', \ the int is {2,number,integer}, the float is {3}, and NaN is {4,number}.
i18n.jssp
<html> <body> <h1><% out.print(messages.application.welcome); %></h1> <p><% // example output for formatted objects var objects = new Array(new Date(), "test", parseInt(1), 1.1, NaN); out.print(messages.format(messages.application.examples, objects)); %></body> </html>
Example output:
For more information about messages see the messages object.
To learn how to define resource files for your application, see Defining resource files.
Several special objects are provided by the JSSP environment. They are available whenever a request for a JSSP script is being served.
The request object is a native Java object that implements the interface HttpServletRequest. You can use any of this interface's methods directly.
The request object provides convenient access to request parameters. For example, instead of
var user = request.getParameter("user");
you can use
var user = request.user;
Unlike in Java Servlets or JSP request parameters are never null in JSSP. There is no need to test against null to avoid errors in your code; simply compare against the empty string:
if (request.name != "") out.write("Hello, " + request.name + "!");
Sometimes you may want to know whether a parameter has actually been supplied but is empty. In this case you can use the request.isSet() or request.isNotSet()functions:
if (request.isNotSet("user")) out.write("Parameter user not specified!");
For more details about the request object see the Java API documentation for HttpServletRequest.
The response object supports all of the methods of the HttpServletResponse interface.
To generate output content use out.print(String). This method accepts a string as a parameter. Internally, before printing, objects are therefore converted to strings using their toString() method. out.print(String) uses the charset that has been specified for the page. The method out.println(String) behaves identical but adds a line feed to the end of a line.
Alternatively you can write binary data to the browser using the method out.write(Array). The array elements must be integers in the range 0 to 255. Using other objects will result in an error message.
Output may be either binary (write()) or encoded (print()), but not both. An attempt to use both methods on the same page will result in an error message.
Example (binary_test.jssp):
<%@ contentType="binary/raw" %><% response.setHeader("Content-Disposition", "attachment; filename=data.dat"); // test binary output. out.write(new Array(65, 0x09, 66, 0x0A)); %>
Note that the opening code tag <% must directly follow the page directives. There may be no line break in between; in fact, there must not be any 'as is' content at all because such content is always sent using print() - which doesn't work with binary output.
While loading a library the out object is set to stdout. This causes output to go to the web server console or log files. Binary output won't work in this case.
The session object stores session-specific data. You can use it to set and retrieve arbitrary values and to share data between different pages and different requests by the same browser session. It behaves just like a JSP session object (interface HttpSession), except that you can set and get properties directly. So, rather than using
var user = session.getAttribute("user");
you can use
var user = session.user;
Be aware that, unlike parameters from the request object, session attributes may be null or undefined.
The session object is a native Java object that implements the HttpSession interface. You can use any method of this interface directly.
If you are combining the JSSP technology with Java servlets or JSPs, you can use the session object to share information among the different languages. This allows for a smooth integration of JSSP into existing Java web projects.
JSSP does not implement a session identification of its own but relies on the session detection mechanism of the servlet container. This means that cookies probably need to be enabled in the client browser. If you want to use another session identification, such as URL rewriting, you will have to create your own implementation or configure your web server to do so.
Some web servers support session persistence by saving the session state to a file when they shut down.
When restarted, the sessions are restored. This works only if the objects
in the session are serializable. Complex JavaScript objects (and functions) may
cause errors because they may not be fully serializable. You should not store
such objects in the session if you need sessions to be persistent. Strings and numbers are
fine, though.
Dervish objects that have automatically
been stored in the session aren't not
persisted through a server restart, either.
The servlet object implements the interface HttpServlet. It is the JSSP servlet instance that executes the jssp page.
Via the servlet object you can obtain information about the environment the page is running in, just as you could in a regular Java servlet or a JSP page.
stdout and stderr are set to System.out and System.err before the page script is executed. They may be useful for printing log messages. It depends on your web server where the output actually goes - whether to a console window, a log file or nowhere at all. For this reason it is recommended that you use one of the servlet.log() methods for logging.
Due to the non-interactive mode of execution a stdin or System.in object is not available in JSSP.
The global application object is an initially empty JavaScript object that you can use to store global application data. The application data can be shared among different sessions. This object is created when the JSSP servlet first runs and maintains its content until the web application is stopped.
Access to this object is internally synchronized, i.e., multiple requests will not get in each other's way when reading or writing properties of this object. However, access to the property objects themselves is not synchronized. This can cause problems when you are storing more complex objects like arrays in the application object. Once you have obtained a reference to such an object, e.g.
var currentUserArray = application.currentUserArray;
race conditions may occur if more than one request is trying to read or modify its currentUserArray object simultaneously.
The section Sharing common data explains how to avoid this problem. First, however, you should understand how scoping works in JSSP because there are subtle differences to other JavaScript implementations.
The messages object encapsulates the strings of a resource file. Its purpose is to provide localized texts. For an example see Internationalization. The messages object's properties (except locale) are read-only.
JSSP's internationalization support must be enabled in the configuration file. See Defining resource files for more information.
The messages object has a format(String, Array) function that can be used to format objects in a language-specific way.
Example:
<% out.print(messages.format("The current
date is: {0,date}", { new Date() }); %>
The formatting is applied to the placeholders (e.g. {0,date}). Placeholders must be surrounded by curly braces. The number indicates the position of the object in the array.
Examples for format placeholders:
{0,date}: for dates {1}: for strings (uses toString() internally) {2,number,integer}: for integers {3,number}: for numbers
More information about format strings can be found in the MessageFormat javadoc.
The actual content of the messages object and the output from the format function depends on its current locale. The locale can be set by assigning a java.util.Locale object to the property messages.locale. If the locale is null or if there is no matching resource file the default resource file is used as specified in the configuration file.
By default the messages object selects the locale based on the language preferences of the requesting browser. If no matching locale is defined it uses the default locale as specified in the configuration file.
The locale is initialized before a page script is being run. It can be changed while the script is running. To reset it to the original value, use
messages.locale = messages.defaultLocale;
Resource strings in resource files are stored in the key=property format. Example:
application.welcome=Welcome to our JSSP application! application.examples=The date is {0,date,long}, the string is ''{1}'', the int is {2,number,integer}, the float is {3}, and NaN is {4,number}.
To access resource strings you can use their keys as if they were properties of the messages object:
<%= HTMLencode(messages.application.welcome) %>
A fallback mechanism for yet untranslated texts is provided. If a resource key cannot be found in the currently specified locale JSSP will try to load the string from the default locale's resource file if it has been specified in the configuration file.
If a resource is not found the result will be null.
The resource messages are not automatically HTML-encoded. They may not be safe for outputting directly. You can use the global function HTMLencode() to make them safe for HTML output or JSencode() to make them safe for use in a JavaScript string variable.
HTMLencode is a global function that returns the HTML-safe representation of a string. It is intended to be used with resource strings and user input. It will replace special characters in HTML such as <, > and & with their respective HTML entities <, > and &. Quotes are also encoded, making the result safe for use in tag attribute values. Example:
<input type="text" name="name" value="<%= HTMLencode(request.name) %>" size="20">
The second parameter of HTMLencode is an optional length restriction, e.g.:
<input type="text" name="name" value="<%= HTMLencode(request.name, 20) %>" size="20">
This will limit the size of the encoded input to 20 (the length restriction applies to the input characters, not the output characters. The output may be longer than 20 characters).
Numbers below 0 have no effect. The maximum string length returned by HTMLencode is limited to 2G-1 characters.
JSencode is a global function that returns the JavaScript-safe representation of a string. It escapes quotes, backslashes and whitespace. It is useful if you want to send server side content to the client as part of JavaScript code, e.g.:
<script> var welcomeMsg = "<%= JSencode(messages.welcome) %>"; </script>
The optional length restriction as defined under HTMLencode can also be used with JSencode.
To end a script immediately you can call the abort() function. The abort() function passes execution through finally blocks in your code.
On the top level of your script you can also use return to end processing.
The synchronize() function allows you to avoid problems when accessing common data. For more information, see Sharing common data.
The jsspInfo() function prints rather verbose information about the servlet, the environment, the loaded modules and scripts and data sources as HTML. It is meant to be used as a debugging tool. Example:
info.jssp
<html> <body> <% jsspInfo(); %> </body> </html>
Do not expose the jsspInfo() function in production environments as this may help hackers to learn about your system configuration.
JSSP uses JSSQL, an embedded SQL extension for JavaScript. More information about JSSQL can be found in the JSSQL Description and reference.
JSSP supports JSSQL in a special way. You can define data sources in the configuration file and JSSP automatically manages the database connections for you.
An additional benefit of defining data sources beforehand is that intelligent editors can provide you with code-assists and semantic checks for embedded SQL statements.
A scope is a place where JavaScript functions and variables are stored. Each function has its own scope, and JavaScript will try to find variables in the current scope first. Usually, in a JavaScript application there is also a top scope - the top scope is the last place to look for variables. When you create a variable without the var keyword, such as
x = 10;
the variable is created in the top scope. This means that all functions subsequently addressing x will eventually find it in the top scope, unless they have defined it locally using the var keyword - in this case the local variable x is used.
In JSSP things behave a little different. For performance reasons scopes are not created each time a request is executed. That would be a waste of time and memory. Instead, at the start of the web application a common shared scope is created. This scope is where library functions and variables - and also the functions generated from the .jssp files you write - find their place.
When a request is executed, the shared scope is linked to the request's scope. In this way the requested script is able to find global variables (like the application object) and library functions.
Now there is one important point to remember:
No objects may be created in
the top scope in scripts!
Allowing scripts to create objects (variables or functions) in the top scope would create major problems as far as memory use and concurrency are concerned. Objects could be created and never released, consuming valuable memory. Requests might simultaneously read and write these objects, which could lead to troublesome and hard-to-find bugs.
For this reason the top scope is made non-writable outside of library code. For you as a programmer there's one simple rule to follow: Always declare variables with the var keyword.
In fact it is considered good style in JavaScript to declare variables using var. Not only that, it also improves performance because finding those variables takes less time.
If you try to read a variable that has not been declared with var or is not otherwise accessible from function parameters or the shared scope, you will get an error. This is not an attempt to put restrictions on you; rather it is a necessity that arises from the highly concurrent nature of a web environment.
Sharing data between different sessions can be done using the global application object. You only have to take care that access to the properties of this object is properly synchronized.
Consider the following (admittedly somewhat contrived) example:
1: var help = application.userCount; 2: application.userCount = help + 1;
An important thing to understand is that the same or different JSSP scripts can be executed simultaneously by different requests. The execution scheduling is done by Java's internal threading mechanism, over which JSSP has no control. This means that a script which has just set the help variable in line 1 might be interrupted by a second script that reads, increments and sets the userCount value independently. Now if the first script continues at line 2 it will overwrite userCount with its old, now invalid value of help + 1. This situation is called a race condition, meaning a condition in which the result of a calculation depends on concurrency issues. Needless to say, race conditions must be prohibited because the results are unreliable.
To avoid such race conditions it is possible in JSSP to execute multiple statements as one atomic operation using the synchronize function:
synchronize(function() { var help = application.userCount; application.userCount = help + 1; });
The synchronize function takes a JavaScript function as a parameter. (This example uses an anonymous function.) This function's code is then executed as one atomic operation. No other code in this or another synchronize function can run simultaneously or interrupt this execution. When several scripts try to execute this code simultaneously, the first script that calls synchronize blocks all others until it returns from synchronize. The Java thread scheduler then decides about the next script that enters the section.
You will probably be familiar with this concept from the Java programming language. In fact, the synchronize function acts just like the synchronized keyword in Java, except for one important difference: It does not take a lock object, but locks application-wide. That means, nowhere in the same JSSP application can two scripts simultaneously execute code in synchronize functions.
Defining and using synchronize in this way avoids race conditions while prohibiting some deadlock scenarios. You should keep the code blocks in synchronize functions as short as possible; otherwise performance may suffer. Take care with loops in synchronize functions: An infinite loop will effectively prohibit all other scripts that use synchronize from running and your application will hang until you restart the web server. It is best not to use loops with synchronize at all.
JSSP's JavaScript implementation Rhino has the ability to access any Java class that is available through the classpath. To use Java classes, you can instantiate them using their fully qualified name prefixed with "Packages.", e.g.:
var javaVector = new Packages.java.util.Vector();
To avoid this clumsy syntax you can import Java classes using the importClass function:
importClass(Packages.java.util.Vector);
This example imports the class java.util.Vector. After that, it can be instantiated using its class name only:
var javaVector = new Vector();
Packages can be imported using the importPackage function:
importPackage(Packages.java.util);
This example imports all classes from the package java.util.
The java.util example is problematic, though, because JavaScript already defines a prototype Date which conflicts with java.util.Date. After importing the java.util package or the java.util.Date class, the native JavaScript Date prototype cannot be used any more. Not being aware of this can have strange side effects.
The same problem exists for some classes in the Java package java.lang, e.g., String or Number. JavaScript provides its own prototype objects with these names, so importing the java.lang packages will prevent you from instantiating the native JavaScript prototypes. This is something you will want to avoid.
For this reason it is recommended that you never import the java.lang and java.util packages or the java.util.Date, java.lang.String and java.lang.Number classes, but always reference these classes by their fully qualified names. In any case you won't probably need these classes very often.
More information about Java scripting in Rhino can be found here.
JSSP provides one imported Java package by default:
net.sf.jssp.jssql
This gives you access to the special JSSQL objects that are necessary to control databases using embedded SQL commands.
More information about JSSP's embedded SQL extension can be found in the
JSSQL Description and reference.
The class net.sf.jssp.JSSPServlet handles and processes requests for JSSP files. It assembles the source file to an intermediate file. The intermediate file gets an "i" appended to its file name (for "intermediate").
The JSSP servlet assembles the file only if an intermediate file does not yet exist, the modification time of the original file is newer than the intermediate file's time, or the servlet executes the script for the first time during its existence.
On assembly the code tags and page directives are evaluated and converted to JavaScript code. If a global shared scope does not yet exist it is created and initialized. A local scope is created for the script itself and the script is executed in the JSSQL engine.
To use the JSSP servlet it is necessary to define it in a <servlet> section under the <web-app> element of your WEB-INF/web.xml file:
<servlet> <servlet-name>JSSPDefaultApplication</servlet-name> <servlet-class>net.sf.jssp.JSSPServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>JSSPDefaultApplication</servlet-name> <url-pattern>*.jssp</url-pattern> </servlet-mapping>
The JSSP servlet can be configured using optional init parameters in web.xml. Init parameters must be added to the <servlet> section using the following syntax (example):
<servlet> ... <init-param> <param-name>encoding</param-name> <param-value>ISO-8859-1</param-value> </init-param> </servlet>
The following init parameters are recognized:
This optional parameter sets the default encoding that is used for reading script files. It tells JSSP how to interpret the bytes that make up the script file. This directive corresponds with the page directive encoding, except that it is a global preset. Specifying the page directive encoding in a script overrides this parameter. If encoding is not specified, the Java system property "file.encoding" is used as the default.
This optional parameter sets the default charset for script output. Specifying the page directive charset in a script overrides this parameter. If charset is not specified, the Java default charset is used as set by the system property "file.encoding".
This optional parameter sets the default content type for HTTP responses. Specifying the page directive contentType in a script overrides this parameter. If contentType is not specified, the default is "text/html; charset=" + charset, where charset is either the previously specified charset or the default charset if none has been specified.
This optional parameter sets the default version for scripts. Specifying the page directive version in a script overrides this parameter. The default version is "1.0". Setting this parameter has no effect at the moment.
By default verbose errors are sent to the client browser. The default error messages are those of the servlet container. Typically these include the Java and JavaScript error stack plus file and line number of the error, unless the servlet container has been configured to suppress them. These messages are very helpful during development.
In production environments it is recommended to set verboseErrors to false. This suppresses sending the error details to the client. Instead, a generic error message is sent:
A JSSP error occurred. See the server's log file for details.
The full stack trace of the error will be in the server's log file or on the console, depending on the server you are using.
JSSP tries to empty the output buffer before sending the error message. If the output buffer has already been flushed, however, the error message will be appended to the output. In some cases, if the error message is output in the middle of an HTML tag, it may not be visible in the browser. The page may then appear incomplete.
The verboseErrors setting of the servlet also affects the verbosity of Dervish error messages.
The configuration file jssp.xml is optional. It can be used to configure JSSP applications within a web application.
For clarity: A web server can run more than one web application. A web application can contain more than one JSSP application. Typically these would reside in different folders. Each JSSP application uses its own JSSP servlet; the different servlets are distinguished by their names. Different JSSP servlets do not share any information; they are completely separate applications.
Note: Tomcat as of version 6.0 does not implement a proper way to separate servlets by URL pattern (such as specifying different subfolders). Practically this means that you should not use more than one JSSP servlet per web application if you want to use Tomcat. Other servlet containers might better support servlet separation, but it would be wise to check that beforehand.
The jssp.xml file configures the JSSP servlets by referring to their respective names. Example:
<jssp-config> <jssp-servlet> <name>JSSPDefaultApplication</name> <defaultLocale>en_US</defaultLocale> <module> <name>JSSP String library</name> <file>WEB-INF/jssp/stringlib.jssp</file> </module> <resource> <locale>en_US</locale> <file>WEB-INF/resources/application.properties</file> <encoding>US-ASCII</encoding> </resource> <resource> <locale>de</locale> <file>WEB-INF/resources/application_DE.properties</file> <encoding>ISO-8859-1</encoding> </resource> </jssp-servlet> </jssp-config>
The jssp.xml file follows the rules for XML. It must start with a <jssp-config> element. Below this element you can specify any number of <jssp-servlet> elements, each configuring a different JSSP servlet. The servlets are identified using their names in the web.xml files within the <name>...</name> tag of a <jssp-servlet> element.
Each servlet can be configured with a default locale, a set of library modules, a set of language-specific resource files, and a set of data sources. All of these elements are optional.
Library modules must be defined with a descriptive name and a file path. The path should be relative to your web content folder. You can also specify an absolute path; however, this is not recommended. It is better to create a WEB-INF/jssp folder and put the libraries there in order to avoid accidental exposure to clients.
The tag for library modules is <module>. It must appear below the <jssp-servlet> tag.
An example for the definition of a library module is:
<module> <name>JSSP String library</name> <file>WEB-INF/jssp/stringlib.jssp</file> <enabled>true</enabled> <unittest>false</unittest> </module>
Enabled library modules are loaded when the servlet executes its first request. All output in the library file that isn't enclosed in <% ... %> goes to the server's standard output, allowing you to log debug messages. Whenever the content of a library file changes it is re-evaluated at the next request. This allows you to modify application code without restarting the web server.
Library modules are loaded in the order of their appearance in the configuration file.
Setting the content of the enabled tag to false allows you to disable a library. By default libraries are enabled.
If you set the content of the unittest tag to true, the libary will be reloaded at the next request if it is enabled and if it has been modified or any previously defined library has been reloaded. You should have at least one unit test library to test the other libraries in your application. Any failures of the unit tests should result in uncaught exceptions. The errors will then be visible in the browser that makes the request.
An example for a unittest library (unittest.jssp):
<% // JSSP unit tests for previously defined libraries. var s = " test "; if (s.trim() != "test") throw "Unit test failed: trim() doesn't work correctly"; out.println("Unit tests completed successfully."); %>
This library tests the function trim() that has been defined by the library stringlib.jssp. Now if either stringlib.jssp or unittest.jssp have been modified, unittest.jssp will be evaluated at the next requests until it passes without throwing exceptions. If it throws an error message you will see the error in the browser until the issue is resolved.
The defined data sources are available when the libraries are loaded. However, as the locale is not determined from the user's request they use the default system locale. Keep this in mind when writing locale-specific unit testing code.
In production environments you can disable the unit tests by setting enabled to false.
For more information about library modules, see the section Library code.
Resource files contain language-specific strings in the key=value (properties file) format. To define a resource you must tell JSSP which locale the file is to be used for. The file's name must be specified as well. The path should be relative to your web content folder. You can also specify an absolute path, however, this is not recommended.
The encoding parameter is optional. It specifies which encoding should be used for loading the resource file. If it is unspecified the default system encoding is used.
Resource files are defined using the tag <resource> which must appear below the <jssp-servlet> tag.
An example for the definition of a resource file is:
<resource> <locale>de</locale> <file>WEB-INF/resources/application_DE.properties</file> <encoding>ISO-8859-1</encoding>
</resource>
Resource strings can be accessed through the messages object. For an example see Internationalization.
A JSSP servlet has a defaultLocale property. When a request is executed JSSP tries to find out the actual locale by examining the preferred languages of the user's browser. If none of the browser's preferred languages matches the specified resource files, the defaultLocale property is used to determine the actual locale and the resource file to use. If the defaultLocale is not specified, the system's default locale is used.
If you specify a default locale, make sure that there is a matching resource file.
Defining data sources enables the JSSP servlet to manage database connections that are created and used in JSSP pages. It will also enable intelligent editors to provide context sensitive database help in the future.
A data source is a Java object that implements the DataSource interface as defined by the JDBC specification. The data source object has the ability to provide connections to a database. You must specify the Java class name plus additional initialization parameters in order to be able to use a data source.
JDBC drivers usually contain at least one implementation of a DataSource. The parameters needed for initialization depend on the driver. Please see your driver's documentation for details.
Currently only initialization using property setters is supported. That means that the DataSource class must have a public default constructor (without parameters) and that all relevant properties are accessible via set...(String) methods. This will usually be the case with most JDBC drivers.
Other ways of configuring data sources will be added in the future (e.g. JNDI lookups).
The following example jssp.xml file defines two data sources called pooledHsqldb and hsqldb:
<jssp-config> <jssp-servlet> <name>JSSPDefaultApplication</name> <datasource> <!-- Define a pooled HSQLDB data source. This is the preferred way. --> <name>pooledHsqldb</name> <class>org.logicalcobwebs.proxool.ProxoolDataSource</class> <param name="alias" value="pooledHsqldb"/> <param name="driver" value="org.hsqldb.jdbcDriver"/> <param name="driverUrl" value="jdbc:hsqldb:mem:jssp"/> <param name="user" value="sa"/> <param name="password" value=""/> </datasource> <datasource> <!-- Define a standard HSQLDB data source. This way offers less performance than a pooled data source. --> <name>hsqldb</name> <class>org.hsqldb.jdbc.jdbcDataSource</class> <param name="database" value="jdbc:hsqldb:mem:jssp"/> <param name="user" value="sa"/> <param name="password" value=""/> </datasource> </jssp-servlet> </jssp-config>
The first data source uses the pooled data source with the class name ProxoolDataSource. Proxool is an open source connection pool implementation; it is included in the standard JSSP distribution. It acts as a generic wrapper around any other JDBC DataSource object, adding pooling functionality to them.
It is recommended that you always use pooled data sources for real applications as this considerably improves performance.
The <name> and <class> attributes of a <datasource> element are mandatory. The parameters depend on the DataSource implementation you are using. When using Proxool always include the alias parameter which is used to distinguish the pools for different connections.
The data source name must be a valid JavaScript identifier. It will be available in scripts later. The class must be a DataSource implementation that is available on the Java classpath.
The second data source defined in the example is an unpooled HSQLDB data source. The example is provided for you to understand the difference between pooled and unpooled data sources. It is recommended that you start with an unpooled data source for a new application to test whether the database connection works and later on change to a pooled connection.
The data sources are created when the JSSP servlet initializes for the first time. This happens during the first script request. Any error messages will be visible in the browser. Connections will be made only if scripts request them, so defining a data source is not enough to test a database connection; you must actively use it.
After the data sources have been successfully created they are available in the JSSP scripts using their name, e.g.:
var stmt = pooledHsqldb.SELECT * FROM TEST;
This example creates an implicit connection. It is also possible to create connections explicitly. The JSSQL documentation covers this topic in detail.
JSSP internally monitors the connections you have created through the data sources and automatically frees them when the request has been served. All dependent resources such as statements and result sets are also automatically closed.
It is good coding style in JSSP not to close database resources in program code.
This section describes how to define a MySQL data source.
The required JDBC driver is called MySQL Connector/J. The latest version is available from the MySQL home page.
Include the file mysql-connector-java-5.1.5-bin.jar (or similar) in the WEB-INF/lib folder of your JSSP application. The data source can then be defined like this:
<datasource> <name>mysqldb</name> <class>com.mysql.jdbc.jdbc2.optional.MysqlDataSource</class> <param name="url" value="jdbc:mysql://localhost/mysqldb?user=mysql&password=mysql"/> </datasource>
This example connects to the database "mysqldb" on "localhost" with user "mysql" and password "mysql". Note the use of the entity & to mask the ampersand in the URL.
Adjust the URL to match your settings and test it. If this works well, use Proxool to make the connections poolable:
<datasource> <name>mysqldb</name> <class>org.logicalcobwebs.proxool.ProxoolDataSource</class> <param name="alias" value="pooledMysqldb"/> <param name="driver" value="com.mysql.jdbc.Driver"/> <param name="driverUrl" value="jdbc:mysql://localhost/mysqldb?user=mysql&password=mysql"/> <param name="user" value="mysql"/> <param name="password" value="mysql"/> </datasource>
Note that you have to specify the Driver class' name, not the DataSource implementation's. Note also that in this case you have to specify user and password once more as extra parameters (otherwise you'll get an error message).
<TODO>
<TODO>
<TODO>
JSSP currently uses the Rhino 1.6R5 JavaScript engine. This Rhino version supports all the features of JavaScript 1.5, including E4X (ECMAScript for XML - ECMA Standard E4X).
It is planned to integrate new versions of Rhino into JSSP as soon as possible.
JSSP has been tested on Sun's JDK 5.0 and JDK 6.0. It works on both.
Java 1.4 support has been dropped from version 0.2beta onwards. From that
version the Java 1.5 language features have been used, so the code won't compile
any more under JDK 1.4.2 and less. If you require binaries compatible with
versions < 1.5 you will need to compile the source with a backwards compiler
such as Retroweaver.
JSSP supports JDBC 3.0 (as of JDK 5.0).
Java SE 6 includes its own Rhino-based JavaScript implementation in the packages
javax.script.* which does not conflict with JSSP.
Tested servlet containers are:
- Tomcat 5.5.31 under JDK 5.0 (Windows XP)
- Tomcat 5.5.31 under JDK 6.0 (Windows XP)
- Tomcat 6.0 under JDK 6.0 (Windows XP)
- Tomcat 5.5 under gij 4.2.1 (SuSE Linux)
- Winstone 0.9 under JDK 6.0
(Windows XP)
Distributed JSSP binaries contain class files with JDK 5.0 compatibility.
JSSP specific performance tests have still to be made. All that can be said for now is that it doesn't look too bad, especially as pages need to be compiled only once. As they are compiled to native Java byte code there's a good potential for optimization by JIT compilers.
Database access is naturally extremely driver specific. If you suspect your JDBC driver to be the culprit, consider using an alternative if possible. There's a good deal of information about JDBC optimization available on the web.
Have fun with JSSP!
Document version: 0.7, 2008-03-03. Author: Leo Meyer, leo_meyer@users.sourceforge.net
This file is a part of the JSSP project documentation at http://jssp.sourceforge.net.
The JSSP project is hosted by Sourceforge.