Mapping Requests to Resources
Processing of JNLP Files
Java Web Start includes a servlet in the
of the JDK. It can be used on either a JNOP file and its associated
resources packaged in a Web Archive (
.war) file, or on an
unarchived directory. The purpose of the servlet is to provide
a simple and convenient packaging format for JNLP applications, so they
can be easily deployed in a Web Container, such as Tomcat or a Java EE-compliant
The download servlet supports the following features:
The packaging support consists of one servlet: JnlpDownloadServlet.
The servlet is packaged into the jnlp-servlet.jar file, which can be
found in the SDK under
Below are two examples of how to use the servlet followed by a detailed description of the functionality of the servlet.
The first example shows how an application can be packaged into a WAR file without using the version-based download. The JnlpDownloadServlet is used to insert the exact URL into the JNLP file at request time. The second example shows how to add support for version-based download as well.
The example1.war contains:
/index.html /app/launch.jnlp /app/application.jar /app/images/icon.gif /WEB-INF/web.xml /WEB-INF/lib/jnlp-servlet.jar /WEB-INF/lib/<jar files for XML parser> (not needed if the servlet container is running J2SE 1.4+)
The JNLP file for the application would look like this:
TS: 2002-04-23 19:21:05 <?xml version="1.0" encoding="UTF-8"?> <jnlp codebase="$$codebase"> <information> <title>Example 1</title> <vendor>Myself</vendor> <description>just an example</description> <icon href="images/icon.gif"/> </information> <resources> <j2se version="1.2+"/> <jar href="application.jar"/> </resources> <application-desc/> </jnlp>
The first line with the TS tag contains the timestamp that the servlet will return for the JNLP file. The format of the timestamp is in ISO 8601 format. If the line is omitted, the timestamp of the file in the WAR file is used. The $$codebase string is modified by the JnlpDownloadServlet to be the actual URL for the request.
The web.xml file instructs the Web container to invoke the JNLPDownloadServlet for all requests to a JNLP file.
<web-app> <servlet> <servlet-name>JnlpDownloadServlet</servlet-name> <servlet-class>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>JnlpDownloadServlet</servlet-name> <url-pattern>*.jnlp</url-pattern> </servlet-mapping> </web-app>
The JnlpDownloadServlet requires an XML parser in order to work. If your servlet container is running J2SE 1.4+, there is already a XML parser integrated in it. Otherwise please add jar files that implement a Java XML parser to the WEB-INF/lib directory. The reference implementation of the parser can be downloaded from http://java.sun.com/xml.
The example2.war contains:
/index.html /app/version.xml /app/launch.jnlp /app/application.jar /app/lib__V2.1.jar /app/images/icon.gif /WEB-INF/web.xml /WEB-INF/lib/jnlp-servlet.jar /WEB-INF/lib/<jar files for XML parser> (not needed if the servlet container is running J2SE 1.4+)
The /app directory contains two JAR resources: application.jar and lib.jar. The lib.jar uses a naming convention to associate the version-id 2.1, i.e., the version information is associated on a per-file basis. The version of the application.jar file is described in the version.xml file, i.e., on a per-directory basis. The version.xml file looks like this:
<jnlp-versions> <resource> <pattern> <name>application.jar</name> <version-id>1.1</version-id> </pattern> <file>application.jar</file> </resource> </jnlp-versions>
The JNLP file for the application looks like this:
TS: 2002-04-23 19:21:05 <?xml version="1.0" encoding="UTF-8"?> <jnlp codebase="$$codebase" href="$$name"> <information> <title>Example 2</title> <vendor>Myself</vendor> <description>just an example</description> <icon href="images/icon.gif"/> </information> <resources> <j2se version="1.2+"/> <jar href="application.jar" version="1.1"/> <jar href="lib.jar" version="2.1"/> </resources> <application-desc/> </jnlp>
Finally, the web.xml file configures the JnlpDownloadServlet to be invoked for all requests into the /app directory.
<web-app> <servlet> <servlet-name>JnlpDownloadServlet</servlet-name> <servlet-class>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>JnlpDownloadServlet</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping> </web-app>
This section shows how to configure a WAR file to include the JnlpDownloadServlet and also how the servlet can be configured.
First the necessary servlet code must be made available to the servlet container. This is done by populating the WEB-INF/lib directory. The servlet is added to a WAR archive by including the jnlp-servlet.jar file in the WEB-INF/lib/ directory. The servlet needs access to an XML parser. If your servlet container is running J2SE 1.4+, there is already a XML parser integrated in it. Otherwise JAR files implementing a Java XML parser must also be added. They can be downloaded from http://java.sun.com/xml.
Once the servlet code is available, the Web container must be told to invoke the servlet on the right set of JNLP and JAR files, or on a given subdirectory. This is all configured in the WEB-INF/web.xml file inside the <web-app> tag:
<web-app> ... </web-app>
The first thing to do is to tell the Web container how to invoke the servlet. This is done by using the <servlet> tag:
<servlet> <servlet-name>JnlpDownloadServlet</servlet-name> <servlet-class>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class> </servlet>
Secondly, the Web container must be told when to invoke the servlet. This can be done in several ways. It can be invoked for certain directories or for files with certain extensions. For example, to invoke it for JNLP files, add the following to the web.xml file:
<servlet-mapping> <servlet-name>JnlpDownloadServlet</servlet-name> <url-pattern>*.jnlp</url-pattern> </servlet-mapping>
Or for a given subdirectory:
<servlet-mapping> <servlet-name>JnlpDownloadServlet</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping>
See also example1 and example2 for examples on how to configure the servlet.
The servlet has built-in logging capabilities to monitor its behavior. Logging messages are generated in 4 different categories:
The logging output is controlled by two servlet initialization parameters, logLevel and logPath. The log level can be set to either NONE, FATAL, WARNING, INFORMATIONAL, or DEBUG. The log path specifies a file where the output will be written to. If no path is specified, logging is done to the standard log for servlets (using the ServletContext.log method). For example:
<servlet> <servlet-name> JnlpDownloadServlet </servlet-name> <servlet-class> jnlp.sample.servlet.JnlpDownloadServlet </servlet-class> <init-param> <param-name> logLevel </param-name> <param-value> DEBUG </param-value> </init-param> <init-param> <param-name> logPath </param-name> <param-value> /logs/jnlpdownloadservlet.log </param-value> </init-param> </servlet>
The servlet treats JNLP and JAR files specially. JNLP files will be macro-expanded as described in a section below. A version-based request for a JAR file might result in the generation for an incremental update. The servlet uses extensions to determine if a file is a JNLP or JAR file. The default extension of JNLP files is .jnlp and for JAR files is .jar. These default extensions can be overwritten by the initialization parameters: jnlp-extension and jar-extension. For example:
<init-param> <param-name> jnlp-extension </param-name> <param-value> .xjnlp </param-value> </init-param>
The MIME type that is returned for a file is also based on its extension. The MIME type is looked up in the configuration files for the Web container and the WAR file. If no mapping is specified, the default MIME types are shown below:
Extension Default MIME type ------------------------------------------- .jnlp application/x-java-jnlp-file .jar application/x-java-archive .jardiff application/x-java-archive-diff
A mapping can be overwritten by using the <mime-type> element in the web.xml file. For example:
<web-app> ... <mime-mapping> <extension>jnlp</extension> <mime-type>text/ascii</mime-type> </mime-mapping> ... </web-app>
Application resources such as images, JAR files, and JNLP files are stored in the WAR file. The WAR file itself is a hierarchical directory structure, and the location of a resource inside the WAR file determines what URL will be used to look it up.
Assume that the WAR file (or servlet) has been configured so it handles all URL requests that starts with http://www.mytool.com/tool/. If the following requests is made: http://www.mytool.com/tool/app/launch.jnlp. Then the JnlpDownloadServlet will look for the launch.jnlp resource in the app/ directory in the WAR file.
A resource that has no associated version information, such as a JNLP file for an application, is simply just added to the WAR file. For example, given the above example, then the WAR file should included the following file:
In general, the timestamp that will be returned for the file is the last-modified timestamp that the file has in the WAR file. The only exception is for JNLP files where it can be explicitly specified in the JNLP file (see below).
The version-based and extension-based download protocols in the JNLP specification allows a resource to be looked up based on version-id, operating system, system architecture, and locale. The JnlpDownloadServlet provides two mechanisms for associating this information with a resource. It can be done on a per-file basis, using a naming convention, or by a per-directory basis, using a configuration file. Both methods can be used for the same directory.
The following information can be associated with a resource:
The path is specified by the location of the resource in the WAR archive. The rest of the information is either specified by the use of a naming convention or in the version.xml file.
The file naming convention is used if a double underscore (__) marker is found in the filename. The filename is parsed according to the BNF notation shown below:
file ::= name __ options . ext options ::= option ( __ options ) * option ::= V version-id | O os | A arch | L locale
Only one version-id can be specified per file. However, multiple os, arch, and locale fields can be specified. For example:
will mean that the resource application.jar has a version-id of 1.2, and the following associated locales: en_US and en.
In each directory, a version.xml file can be placed to describe the additional properties, such as a version-id, for files in that particular directory. This is an alternative to the file naming convention.
For example, placing the file application-1_2-us.jar in a directory, along with a version.xml with the following content:
<jnlp-versions> <resource> <pattern> <name>application.jar</name> <version-id>1.2</version-id> <locale>en_US</locale> <locale>en</locale> </pattern> <file>application-1_2-us.jar</file> </resource> </jnlp-versions>
will be the same as having placed the file application__V1.2__Len_US__Len.jar in the directory.
A resource can also be specified with a platform version-id in the version.xml file. Such a resource is used to match a particular platform request for a JRE. A resource with a platform version-id is specified using the <platform> element. For example:
<platform> <pattern> <name>JRE</name> <version-id>1.3</version-id> <locale>en_US</locale> <locale>en</locale> </pattern> <file>j2re-1_3.0-us.jnlp</file> <product-version-id>1.3.0</product-version-id> </platform>
Platform version requests are generated internally by Java Web Start, when an application has requested a version of the Java platform that is currently not installed on the local system.
The complete document type definition (DTD) for the version.xml is shown in the following:
<!ELEMENT jnlp-versions <resource*, platform*)> <!ELEMENT resource (pattern, file)> <!ELEMENT platform (pattern, file, product-version-id)> <!ELEMENT pattern (name, version-id, os*, arch*, locale*)> <!ELEMENT name (#PCDATA)> <!ELEMENT version-id (#PCDATA)> <!ELEMENT os (#PCDATA)> <!ELEMENT arch (#PCDATA)> <!ELEMENT locale (#PCDATA)> <!ELEMENT file (#PCDATA)> <!ELEMENT product-version-id (#PCDATA)>
The JNLP specification defines four different kinds of download requests that Java Web Start (or more generally, a JNLP Client) can make to a server when requesting a resource:
A request is initially processed by the JNLPDownloadServlet, and it extracts the following information from the request:
Consider example2, and assume that it is being hosted at http://www.mytool.com/tool2/. If the following requests is made: http://www.mytool.com/tool2/app/lib.jar&version-id=2.1. Then the path of the resource would be, app/, the name would be lib.jar, the version string would be 2.1, and the lists for os, architecture, and locales would be empty.
A request to a directory, e.g., http://www.mytool.com/tool2/app/, will get appended the default filename: launch.jnlp. Thus, it would be the same as http://www.mytool.com/tool2/app/launch.jnlp.
A request for which no version-id is specified (neither version-id parameter or platform-version-id parameter is specified in the request) is handled as a basic download request.
The request is first checked to see if it contains a double underscore (__) or is a request to the version.xml file. If so, the request is rejected and a HTTP 404 error code is returned.
The JnlpDownloadServlet will then try to locate the resource with the given path and name in the WAR file, and if found return it. If the resource is not found, a HTTP 404 error code is returned for the request.
If a match is found and it is a JNLP file, then it is preprocessed as described below before returned.
The resource lookup for resources with a version-id is uniform across the version-based download protocol, the extension download protocol, and the platform-version download request.
First, the JnlpDownloadServlet will build a database of all the resources that are located in the WAR file directory that the URL request is accessing (based on the path in the request). The database is built by scanning the version.xml file (if present), and the list of files in the directory that is using the naming convention described above. The servlet caches the information internally. It only does a re-scan if the timestamp of the version.xml file is more recent than at the last scan. Thus, if you add a file using the naming convention, make sure to touch the version.xml file to force the servlet to do a re-scan.
Secondly, the servlet will scan through the entries in the database to find a match for the given request (the match rules are described below). For a non-platform request, first the resource entries in the version.xml file are scanned in the order they are specified, and then secondly the entries that are specified using the naming convention. For a platform-version request, the platform entries in the version.xml file is scanned in the order they are specified. If several entries matches the request, then the entry with the highest version-id is returned. If multiple matches is found with the same highest version-id, then the first one specified is returned.
The matching rules are as follows:
The x-java-jnlp-version-id returned in the response is the version-id for the matching resource, except for a platform request where it is taken from the <product-version-id> field in the version.xml file.
If a match is found and it is a JNLP file, then it is preprocessed as described below before returned.
The servlet will automatically generate and return incremental updates to JAR files, if possible. If the current-version-id parameter is included in the request and the servlet can find both a match on the current-version-id and the requested version (given the above matching rules) and the request is for a JAR file (e.g., the target resource has the .jar extension), then a JARDiff file will be generated by the servlet. The JARDiff file is returned as long as its size is less than that of the requested version.
The JARDiff file is generated and stored in a temporary directory that is specific to the given Web container. The servlet locates the temporary working directory using the javax.servlet.context.tempdir context attribute.
The JnlpDownloadServlet will automatically macro-expand certain template values in a JNLP file and replace them with URLs that are specific to the current request. This will enable JNLP files to be written and deployed without containing hard-coded URLs.
The servlet will automatically substitute certain fixed keys in the JNLP file (prefixed with $$) with URLs that are based on the current request. The keys are designed so location-independent WAR files can be created and deployed into a Web container.
The table below shows the 4 keys that the servlet will look for and substitute:
Pattern Value ---------------------------------------------------------------- $$codebase Complete URL for request, except name of JNLP file $$name Name of the JNLP file $$context Base URL for the Web Archive $$site Web site address without the WAR context portion
For example: Consider the example1 WAR file. Lets assume that it has been deployed at the following location: http://www.mytool.com/tool. Thus, a request to http://www.mytool.com/tool/app/launch.jnlp will return the JNLP file. The values of the macro-expanded keys would be:
$$codebase = http://www.mytool.com/tool/app/ $$name = launch.jnlp $$context = http://www.mytool.com/tool/ $$site = http://www.mytool.com/
The servlet does not validate the format of the JNLP file nor that the XML is well-formed. The value substitution is purely textual.
An explicit timestamp can be included in a JNLP file to ensure that a consistent timestamp will be returned from the Web Server. This is especially useful if a JNLP file is replicated onto multiple Web servers that are serving the same URL in a round-robin or load-balancing fashion. Note that a similar method is not provided for JAR files. The version-based download protocol should be used instead.
An explicit timestamp is included in the JNLP if the first-line starts with TS:. If so, it is parsed accordingly to the ISO 8601 formatting of timestamps (see below). The first line is also removed from the contents.
See example1 and example2 above for sample JNLP files using the TS: element.
The general format of a timestamp is:
The dashes, colons, and seconds are optional:
The hh is in 24h notation. By default, the local time zone is used. A Universal Time (UTC) (also know as GMT time) can be specified by appending the capital letter Z to a time as in:
23:59:59Z or 235959Z
+hh:mm, +hhmm, or +hh
can be added to the time to indicate that the used local time zone is hh hours and mm minutes ahead of UTC. For time zones west of the zero meridian, which are behind UTC, the notation
-hh:mm, -hhmm, or -hh
is used instead. For example, Central European Time (CET) is +0100 and U.S./Canadian Eastern Standard Time (EST) is -0500. The following strings all indicate the same point of time:
12:00Z = 13:00+01:00 = 0700-0500
You can now host
files together with your original
If the client supports the pack200-gzip or gzip file formats,
the servlet will return the compressed file if it is available on
the server. Java Web Start 5.0 supports both compression formats.
You must host both the original jar file and the pack file in the server,
otherwise the servlet will not pick up the pack file. The pack file
can be created with the pack200.exe command included in J2SE 5.0.
For more information on the pack200 compression technology, please see
and Compression for Network Deployment.