JnlpDownloadServlet
JnlpDownloadServlet
JnlpDownloadServlet
is a servlet that simplifies
the process of deploying Java Web Start applications on a web
server as well as providing enhanced functionality.
JnlpDownloadServlet
is available in the
sample/jnlp/servlet
directory of the JDK, both as
compiled JAR files and as source code.
In the simplest case of JNLP deployment, you put your application files and a JNLP file on a web server. After you configure the web server for the JNLP MIME type, you have basic JNLP functionality — the user clicks on a JNLP file link in a browser and your application is downloaded and run.
However, this approach has some drawbacks. First, the explicit URL of the application codebase must appear in the JNLP file. This means it must be changed if you decide to host your application elsewhere, or if you're moving from a local test server to a more public production server. In addition, the file system time stamp on your application files will be used to report the time stamp of your application, which might not be what you want. Finally, only the most basic parts of the JNLP protocol are implemented through HTTP. Versioning and other features are not supported.
JnlpDownloadServlet
acts as a liaison between your
application files and the client. It provides the following
features:
To understand the useful features that
JnlpDownloadServlet
brings to application deployment,
you must first understand the simplest way an application can be
distributed using JNLP and Java Web Start.
The app1
example (in the
sample/jnlp/servlet
directory of the JDK) contains a
simple application and, perhaps more valuable, an Ant build script
that builds the application and bundles it in a WAR file for
distribution on a web server.
The application itself consists of a single class,
Pie
, and an image file, key-lime.jpg, which are
packaged into the pie.jar JAR file.
The pie.jar archive is packaged into a web application file, app1.war, which has these contents:
WEB-INF/web.xml index.html pie.jnlp pie.jar
The JNLP file describes the application, assuming it is deployed
on a server at http://localhost:8080/
, which works for
a locally installed Tomcat server.
<?xml version="1.0" encoding="UTF-8"?> <jnlp spec="1.0+" codebase="http://localhost:8080/app1"> <information> <title>Pie</title> <vendor>Example Vendor</vendor> </information> <resources> <j2se version="1.2+"/> <jar href="pie.jar" main="true" /> </resources> <application-desc/> </jnlp>
Consider the interaction between client and server as a dialog:
[User clicks a link in the browser.]
Client browser: May I please have pie.jnlp?
Server: Yes, here you go.
Client browser: I notice the MIME type is
application/x-java-jnlp-file
. Java Web Start, would
you please handle pie.jnlp for me?
Client Java Web Start: Let me see what resources are required for this application. Hey Server, can I please have pie.jar?
Server: Here you go.
Client Java Web Start: Now I'll launch the JAR file using its
Main-class
manifest attribute.
[Application appears on the user's screen.]
The app2
example shows how to bundle
JnlpDownloadServlet
with an application and how to use
it to perform simple substitutions in a JNLP file.
The app3
example shows how a versioned resource
request is handled by JnlpDownloadServlet
.
Both app2
and app3
will be referenced
from the following sections.
JnlpDownloadServlet
To take advantage of JnlpDownloadServlet
, perform
these steps.
JnlpDownloadServlet
in your web
application WAR file. You must use two JAR files to have the full
functionality, jnlp-servlet.jar
and
jardiff.jar
. These two JAR files are put in the
WEB-INF/lib
directory of your WAR file.*.jnlp
and *.jar
to
JnlpDownloadServlet
using your web application's
web.xml file. It must contain lines that identify
JnlpDownloadServlet
and makes it the handler for JNLP
and JAR files. Here is a complete example:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <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> <servlet-mapping> <servlet-name>JnlpDownloadServlet</servlet-name> <url-pattern>*.jar</url-pattern> </servlet-mapping> </web-app>
The app2
and app3
examples show how to
package JnlpDownloadServlet
in a web application.
Review the Ant build script app2/build.xml
or
app3/build.xml
for more information.
JnlpDownloadServlet
makes convenient substitutions
in your JNLP files. When the client requests a JNLP file, the
servlet reads the original file, substitutes values, and returns
the results.
If the first line of your JNLP file contains a time stamp,
JnlpDownloadServlet
uses the value as a time stamp for
your application. If you do not specify a time stamp,
JnlpDownloadServlet
uses the last modified time stamp
from the file system.
Using an explicit time stamp is useful if you copy a JNLP file to multiple servers for load balancing. The explicit time stamp ensures that clients see consistent results, regardless of which server they consult.
To use an explicit time stamp, add a line to the top of your
JNLP file. Begin the line with TS:
. The rest of the
line must contain a time stamp in ISO 8601 format, which has this
basic format:
YYYY-MM-DD hh:mm:ss
Here is one example:
TS: 2010-08-07 21:19:05
Consult the Reference section for a more complete description of the time stamp string.
JnlpDownloadServlet
makes substitutions for strings
that begin with two dollar signs. For example, consider this line
in a JNLP file:
<jnlp spec="1.0+" codebase="$$codebase">
When a client requests the JNLP file,
JnlpDownloadServlet
substitutes the correct value for
$$codebase
, wherever it is deployed. This is
convenient because you do not have to hardcode this value in the
JNLP file, making it easier to move from server to server.
The full list of substitutions is shown in the following table:
Name | Substituted value |
---|---|
$$codebase |
The URL of the request except for the name of the JNLP file |
$$name |
The name of the JNLP file |
$$context |
The base URL of the web application |
$$site |
The web server address |
$$hostname |
The name of the server |
For example, suppose the app2
example is deployed
at example.com
. The values of each substitution would
be as follows:
Name | Substituted value |
---|---|
$$codebase |
http://example.com/app2/ |
$$name |
pie.jnlp |
$$context |
http://example.com/app2 |
$$site |
http://example.com |
$$hostname |
example.com |
The app2/pie.jnlp
and app3/pie.jnlp
examples use only $$codebase
.
The JNLP specification supports requesting application resources with explicit version numbers or resources for certain locales, operating systems, and system architectures. This means that you can deploy an application that has different libraries for different operating systems or different resource files for different locales.
JnlpDownloadServlet
provides support for special
requests with two different mechanisms. The first is a scheme for
naming resource files where locales, operating systems, and other
parameters are embedded in the file name. The second mechanism
involves an XML file that describes the parameters of resource
files in the same directory.
JnlpDownloadServlet
enables you to specify
information about files by embedding it in a file name. If the file
name contains two underscores in a row, the file name is treated as
containing attributes. A prefix letter specifies the attribute
information, as shown here:
Prefix | Meaning |
---|---|
V |
Version number |
O |
Operating system |
A |
Architecture |
L |
Locale |
Only one version is allowed per file, but a file can be
associated with multiple operating system, architecture, or locale
attributes. For example, application__V1.2__Len_US__Len.jar
means that the resource application.jar
has a version
of 1.2
, and associated locales of en_US
and en
.
For example, consider a JNLP file that contains this resource line:
<jar href="app-lib.jar" version="2.0" />
When Java Web Start encounters this line in the JNLP file, it
sends a request to the server for version 2.0 of
app-lib.jar
. If you have placed a file
app-lib__V2.0.jar
in your web application,
JnlpDownloadServlet
returns it to the client as
version 2.0 of app-lib.jar
. Note how the actual file
name in your web application gets remapped to be visible to the
client as app-lib.jar
.
The file naming convention can be cumbersome, especially if you have multiple resource files that each have multiple associations for operating systems, architectures, or locales.
JnlpDownloadServlet
supports an alternate
mechanism, where all attributes are described in a separate XML
file. The servlet looks for a version.xml
file in the
same directory as the resource. The version.xml
file
contains information about the other files in the same
directory.
For example, the following version.xml
file
describes a resource that is available to a client as
application.jar
. The actual file is stored in the same
directory as application-1_2-us.jar
.
<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>
The app3
example shows how to respond to a
versioned request for a resource using the XML version file. In
particular, the JNLP file contains this resource line:
<jar href="app-lib.jar" version="2.0" />
The WAR file contains the library, app-lib.jar
, and
this XML version file version.xml
that describes the
library:
<jnlp-versions> <resource> <pattern> <name>app-lib.jar</name> <version-id>2.0</version-id> </pattern> <file>app-lib-2.0.jar</file> </resource> </jnlp-versions>
Note how the actual name of the file,
app-lib-2.0.jar
, is remapped so that the file name
visible from the client is app-lib.jar
.
JnlpDownloadServlet
generates and returns
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, and the
request is for a JAR file, then a JARDiff file is generated by the
servlet. The JARDiff file is returned if 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 web container. The servlet finds
the temporary working directory using the
javax.servlet.context.tempdir
context attribute.
Pack200 is an efficient compression technology for JAR files. Download and installation times for applications are important factors in how users perceive applications. Making your application resources as small as possible reduces the amount of time users must wait for your application to download.
JnlpDownloadServlet
can supply resources for
clients, such as Java Web Start, that support GZIP and Pack200
downloads. Place *.jar.pack.gz
or
*.jar.gz
files together with your original
*.jar
files on the server. For example,
JnlpDownloadServlet
chooses the best of the following
files, based upon what the client supports:
pie.jar pie.jar.gz pie.jar.pack.gz
You can create Pack200 files using the pack200
tool
that is included with the Java Development Kit. The
app3
example creates a Pack200 version of the
pie.jar
file. Look at build.xml
to see
how the Pack200 file is created. Because pie.jar
is
simple, the Pack200 file is negligibly smaller; however, for a
larger JAR file, the compression is much greater.
JNLP substitutions, Pack200 support, and file attribute support
are the most useful features of JnlpDownloadServlet
.
The servlet also supports a logging system and MIME type
mapping.
The servlet has logging capabilities that enable you to monitor its behavior. Logging messages are generated in different categories:
FATAL
means a malfunction or internal error
occurred inside the servlet.WARNING
indicates an error processing some of the
information in the WAR file or parsing the version.xml
file.INFORMATIONAL
logs all requests, replies,
directory scanning, and so on.DEBUG
displays detailed internal information about
how a request is processed.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
is written. If no path is specified, logging is done to the
standard log for servlets (using
ServletContext.log()
). Here is an 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. Substitutions
are made in JNLP files as desribed in Substitutions. A version-based request for a
JAR file can result in the generation of 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
. Here is
an 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 assigned:
Extension | Default MIME Type |
---|---|
.jnlp |
application/x-java-jnlp-file |
.jar |
application/x-java-archive |
.jardiff |
application/x-java-archive-diff |
To change the MIME type JnlpDownloadServlet
returns, use the <mime-type>
element in the
web.xml
file. Here is an example:
<web-app> ... <mime-mapping> <extension>jnlp</extension> <mime-type>text/ascii</mime-type> </mime-mapping> ... </web-app>
JnlpDownloadServlet
Most of the time, you will use JnlpDownloadServlet
directly. In rare cases, you might want to add functionality to
JnlpDownloadServlet
. The full source code is
available, and the build is relatively straightforward.
You must have GNU make
, a Java Development Kit
(JDK), and you must define environment variables. Here is one
example on a Linux system.
$ export CLASS_PATH=/home/edmond/Applications/apache-tomcat-7.0.2/lib/servlet-api.jar $ export FILE_SEPARATOR=: $ export TMPDIR=/tmp $ export SDK_HOME=/home/edmond/jdk1.7.0 $ make . . .
The output of the build is lib/jnlp-servlet.jar
and
lib/jardiff.jar
.
The general format of a time stamp is:
YYYY-MM-DD hh:mm:ss
The dashes, colons, and seconds are optional:
YYYYMMDDhhmm
The hh is in 24-hour notation. By default, the local time zone is used. Universal Time (UTC), also known as GMT time, can be specified by appending the capital letter Z to a time:
23:59:59Z or 235959Z
The strings +hh:mm
, +hhmm
, or
+hh
can be added to the time to indicate that the
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 in time:
12:00Z = 13:00+01:00 = 0700-0500
The complete document type definition (DTD) for the
version.xml
file is shown here:
<!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)>