GlassFish Server Open Source Edition 3.1 - App Client Container One Pager - JNLP Customization

1. Introduction

1.1. Project/Component Working Name:

App Client Container

1.2. Name(s) and e-mail address of Document Author(s)/Supplier:

Tim Quinn (tim.quinn@oracle.com)

1.3. Date of This Document:

03/11/2010
Rev. 06/15/2010
Rev. 06/16/2010
Rev. 06/28/2010
Rev. 07/07/2010 - clean-up from wiki migration
Rev. 08/03/2010 - add to owned/defaulted/merged discussion
Rev. 08/24/2010 - clarify note about not listing all JARs in custom JNLP

2. Project Summary

2.1. Project Description:

This one-pager describes changes and additions to app client support in GlassFish Server Open Source Edition 3.1, focusing on externally-visible changes (but with some comments on internal implementation choices). Currently the key change is to allow developers to influence the JNLP documents which GlassFish generates for Java Web Start support of launching app clients.

2.2. Risks and Assumptions:

3. Problem Summary

3.1. Problem Area:

  • Allow developers to influence and customized the generated JNLP documents for Java Web Start support

3.2. Justification:

  • Developers cannot currently influence, customize, or alter the automatically-generated JNLP in GlassFish 3.0 and earlier. Although the generated JNLP covers many common cases adequately, there are some significant cases which we cannot handle simply because the developer cannot influence the JNLP. (For example, including native libraries in the client.)

4. Technical Description:

4.1. Details:

Customizable JNLP

This feature is optional. A developer using it needs to tell GlassFish where the customizing JNLP file is located and needs to package that JNLP, any referenced JNLPs, and any JARs required by the client into the EAR.

Two Models

Developers can bring two different perspectives to this task.

App Client-centric

The developer knows about writing and packaging app clients, particularly understanding that JARs needed by the app client will reside within the EAR following the normal EAR packaging model. GlassFish will automatically serve any extra JNLPs and JARs the developer references from the custom JNLP.

Web app-centric

The developer has written Java Web Start apps previously and is familiar with packaging and deploying the JNLP files and JARs in web applications. GlassFish will serve any extra JNLPs and JARs referenced from the developer's custom JNLP through the normal web app support.

Design Center for 3.1

The app client-centric model is the design center in GlassFish 3.1 for allowing customization of the JNLP.

Rationale: The original driver behind support for Java Web Start launches was to give developers who have existing app clients or are building new ones a simple, automatic way for end users to launch those app clients using Java Web Start. That is, the starting point has been an app client-centric approach. We have seen steady (although not huge) usage of this feature, judging from forum traffic, with that model. We have not seen requests for the web app-centric model, which could be either because no demand exists or because the demand that does exist is invisible to us. The proposal for 3.1 is to implement the app client-centric model in a way that does not preclude us from also supporting the web app-centric model in a future release if the we learn of demand for it. (some notes on the web app-centric model )

User Experience

Identifying the Custom JNLP File

A developer can add an optional element to an app client's glassfish-application-client.xml descriptor to point to a JNLP document within the application. When GlassFish loads the application it will combine this JNLP document with JNLP content which GlassFish controls, producing the resulting JNLP that will launch the app client.

The glassfish-application-client.xml descriptor already supports the optional <java-web-start-access> element. This element now adds a new optional subelement, <jnlp-doc>. Its text value is a relative URI within the application pointing to the developer's custom JNLP document. (By using the tag "jnlp-doc" rather than "jnlp" we intend to reduce the chance that a developer might think the entire custom JNLP document would be placed into the descriptor itself.)

The value of the <jnlp-doc> element is a relative path:

[path-to-JAR-in-EAR ! ] path-to-JNLP-in-JAR

where the default path-to-JAR-in-EAR is the current app client JAR.

That is, the developer can put the custom JNLP document into the app client JAR, say at custom/myInfo.jnlp. Then the glassfish-application-client.xml descriptor would look like this:

...
   <java-web-start-access>
      <jnlp-doc>custom/myInfo.jnlp</jnlp-doc>
...

This works both if the client is deployed stand-alone or if it is inside an EAR.

If the app client is inside an EAR, the developer can choose instead to place the custom JNLP file inside some other JAR in the EAR. If that other JAR is packaged in the EAR as other/myLib.jar, then the descriptor would contain

...
   <java-web-start-access>
      <jnlp-doc>other/myLib.jar!custom/myInfo.jnlp</jnlp-doc>
...

Note that specifying where the custom JNLP resides is from the developer's perspective when he or she builds the app client JAR and/or the EAR. The paths are in the context of the app client JAR itself or the containing EAR if there is one. Further, the custom JNLP is always packaged as part of the app client or the EAR. GlassFish does not support specifying a custom JNLP document that lies outside the deployment unit.

Writing the Custom JNLP File

A developer can write the custom JNLP file almost as if he or she were writing a separate JNLP application; GlassFish completely determines a small part of the resulting JNLP content regardless of what the developer writes.

As with any JNLP document, the developer's custom JNLP for GlassFish can refer to JARs which the app client requires.

The developer should not specify every JAR on which the client depends. GlassFish will automatically handle JARs that the Java EE spec requires to be available to the app client. This includes JARs listed in the app client JAR's manifest Class-Path and JARs in the EAR's library directory (if any) and their transitive closures. The developer's custom JNLP document should specify only those JARs which the client needs that GlassFish would not otherwise include.

The developer packages these JARs - as with any JAR required by an app client - in the EAR. The developer uses relative URIs in his or her <jar href="..."> and <nativelib href="..."> elements to point to the JARs. The codebase which GlassFish will assign for the final client JNLP document corresponds to the top-level of the EAR, so relative hrefs correspond directly to the relative path to the JARs within the EAR.

Note that neither the Java EE spec nor GlassFish supports packaging JARs inside the app client JAR itself. The developer is free to do so, but GlassFish does no special processing of such JARs. They will not appear in the runtime class path and they cannot be referenced from the developer's custom JNLP document.

The developer's JNLP can also refer to other developer-written JNLP documents using <extension href="..."/> elements. To be consistent with relative hrefs to JARs, the developer's relative hrefs to JNLPs are resolved within the EAR. The developer can place these JNLPs directly in the EAR or inside JARs which the EAR contains. The developer can use the same format for these hrefs as for the <jnlp-doc> element:

path-to-JAR-in-EAR ! path-in-JAR-to-JNLP
path-in-EAR-to-JNLP

Location of JNLP Referenced JNLP location href from developer's JNLP
in the EAR stuff/extra.jnlp stuff/extra.jnlp
in a JAR other/a.jar contains stuff/extra.jnlp other/a.jar!stuff/extra.jnlp

where the JNLP-inside-JAR URI format follows the standard entry-within-a-JAR URI syntax and semantics. Support for this syntax comes from the GlassFish Grizzly adapter which serves requests from the automated Java Web Start support. This is not a feature of Java Web Start or the JNLP standard.

Because GlassFish will always set the codebase of all JNLP documents to correspond to the EAR, the developer will need to remember this in writing multiply-nested JNLPs and the hrefs within them, realizing that all relative hrefs will be resolved with respect to the EAR.

How GlassFish Combines Developer-provided JNLP with GlassFish-generated JNLP

If the developer provides his or her own JNLP file, GlassFish combines that content in a predictable way with its own generated JNLP to come up with the final JNLP used to launch the app client.

GlassFish creates the various portions of the final JNLP in one of three ways:

  • owned - GlassFish owns the content and ignores any developer-provided content for that portion
  • merged - GlassFish merges the GlassFish-generated content and the developer's content for that portion
  • defaulted - GlassFish uses only the developer's content if it is present; otherwise GlassFish provides default content for that portion

This means that the developer can (but does not have to) compose a complete JNLP document and package it with the application. GlassFish will know how to combine the right parts from it with the GlassFish-generated JNLP. This is not what we recommend but it will work. Rather, we expect developers will provide small bits of content which will specify only what they want to add to what GlassFish generates. Keep in mind that the developer-provided content must still conform to the general structure of the JNLP format so that GlassFish can tell where in the final JNLP document the custom content belongs. For example, if the developer simply wants to specify a single native library to be included only for Windows systems, the new element he or she wants to add might be

<nativelib href="windows/myLib.jar"/>

But the developer needs to let GlassFish know where in the overall document this element belongs. The actual custom JNLP would need to look something like this:

<jnlp>
   <resources os="Windows">
      <nativelib href="windows/myLib.jar"/>
   </resources>
</jnlp>

in order to "place" the <nativelib> element in the right part of the final JNLP document.

Generally, developers can:

  • Override, for <information> elements with no attribute settings for os, arch, platform, and locale, the GlassFish defaults for child elements. (These children can be <title>, <vendor>, <description>, <icon>, etc.)
  • Add <information> elements with os, arch, platform, or locale settings and children of such <information> elements.
  • Add child elements under the GlassFish-provided <resources> element. (The GlassFish-provided <resources> element does not specify os, arch, or locale.)
  • Add new <resources> elements that specify at least one of os, arch, or locale and children under such <resources> elements.

In particular, this flexibility allows developers to add JARs to the application (including platform-specific native libraries) and set properties to control the behavior of their clients.

The following tables give more detail about what parts of the JNLP the developer can add and modify.
Owned

JNLP fragment Notes
<jnlp codebase="xxx"...> GlassFish controls this in the app client-centric case; the host and port are inserted dynamically with each request and the path is GlassFish-private, indicating that the request is for Java Web Start support and identifying which app and client are being addressed; the developer controls this for the web app-centric model.
<jnlp href="xxx"...> URL to the JNLP itself - GlassFish controls the actual URL where the JNLP is reachable in the app client-centric model so it must control this attribute value; the developer owns this value in the web app-centric model.
<jnlp>
  <security>
GlassFish must control the permissions requested for each JNLP document - all permissions are needed for the main document (which launches the ACC) and the permissions requested for other JNLP documents depend on whether the JARs referenced in those documents are signed or not
<jnlp>
  <application-desc>
    <argument>...
GlassFish sets the main-class and the arguments to be passed to the client

Defaulted

JNLP fragment Notes
<jnlp spec="xxx"...> JNLP spec version
<jnlp>
  <information (no-attrs)>
This element contains app title, vendor, homepage, various description text values, icon images, and whether offline execution should be allowed.
<jnlp>
  <resources (no-attrs)>
    <java version="xxx" java-vm-args="yyy" ...>
The Java SE version and/or selected VM parameter settings.

Merged

JNLP fragment Notes
<jnlp>
  <information (attrs)>
Developer specifies one or more of os=, arch=, platform=, locale= on the <information> element and provides all children; GlassFish provides no default children.
<jnlp>
  <resources (no-attrs)>
    <jar ...>
Developer adds JAR files to be included in the app to the GlassFish-provided ones
<jnlp>
  <resources (no-attrs)>
    <nativelib ...>
Developer refers to a native library
<jnlp>
  <resources (no-attrs)>
    <property ...>
Developer adds system property settings to the GlassFish-provided ones
<jnlp>
  <resources (no-attrs)>
    <extension ...>
Developer refers to another developer-provided JNLP document
<jnlp>
  <resources (attrs)> ...
Developer specifies one or more of os=, arch=, locale= on the <resources> element and provides all children; GlassFish provides no default children.
<jnlp>
  <component-desc...>
Developer "includes" additional JNLP documents from the app

Again, the developer will write the custom JNLP knowing that GlassFish will assign the final JNLP document's codebase so relative {{href}}s will resolve correctly within the EAR. (The codebase value is "owned" by GlassFish.) For example, if the developer wants to refer to a native library at windows/myLib.jar then he or she can include

<nativelib href="windows/myLib.jar" .../>

in the developer-provided JNLP document. (Each entry in a JAR listed in a nativelib element must be a native library for the correct platform. The full syntax of the nativelib element lets the developer specify the platform for that native library.)

Note that GlassFish provides default <information> and <resources> elements, without specifying attributes such as os, arch, platform, or locale attributes (shown as no-attrs in the table). GlassFish merges its own content within those elements with developer-provided content under those elements. Further, the developer can provide his or her own <information> and <resources> elements (and fragments within them) that do specify at least one of the attributes.

Some Design/implementation Details

These topics do not need to be documented; they are not part of the published, supported interface of this feature.

Controlling how JNLP is Combined

Which portions of the JNLP are handled in which way is governed by a properties file client-jnlp-config.properties. GlassFish installs this file into ${installDir}/config. If at deployment time GlassFish finds a copy at ${domainDir}/config then it will use that one instead of the one at ${installDir}/config. We do not expect users to routinely make domain-specific copies of the config file or to edit the copy at ${installDir}. The location and contents of the config file are not part of the published and documented interface to GlassFish.

The contents of the properties file assign XPath expressions to properties to indicate what parts of the JNLP document are owned, which are merged, and which are defaulted. The JNLP generation code uses these XPath expressions to extract the relevant parts of the developer's JNLP and the GlassFish-generated JNLP and then combine them properly to get the resulting client JNLP.)

Security for User-referenced files

The Java Web Start support in GlassFish has always enforced "positive file service," meaning that GlassFish serves (via the Java Web Start support URLs) only those files that it recognizes as part of the application needed by the app client. This prevents malicious users from using the Java Web Start-related URLs to try to fetch content that should not be exposed over HTTP. For each application, GlassFish recognizes the app client JAR file and any library JARs in the application's library directory as well as JARs referenced from manifest Class-Path entries of referenced JARs.

To preserve this protection with developer-provided JNLP content - which can itself add JARs to the client - GlassFish scans the developer-provided JNLP (and any other JNLP documents it in turn refers to) for references to JARs within the application's code base. GlassFish adds each such JAR to the approved list of files that can be served via the Java Web Start URLs. GlassFish does the same for extension JNLP documents to which the developer's JNLP content refers: any extension JNLP documents that lie within the application's codebase are added to the known content so it can be served.

4.2. Bug/RFE Number(s):

Issue 1118
Issue 4113

4.3. In Scope:

Combination of developer-provided and GlassFish-generated JNLP content, according to well-defined rules for which parts of the resulting JNLP are owned by GlassFish, merged from both sources, and defaulted by GlassFish in the absence of developer-provided content.

4.4. Out of Scope:

Support for references from JNLP in one application to another application. Developers might code such references in an unsupported way by using some of the existing undocumented, unpublished placeholders GlassFish already uses in the generated JNLP documents. We will not support such cross-referencing.

4.5. Interfaces:

4.5.1 Exported Interfaces

  • Interface: glassfish-application-client.xml (formerly sun-application-client.xml)
  • Stability: evolving
  • Former Stability (if changing):
  • Comments: Revised to add optional jnlp-doc child element of java-web-start-access. Note that in earlier releases of GlassFish developers could set the

<java-web-start-access> <vendor>

value to specially-formatted strings to point to icon images. This feature is continued but we urge developers instead to specify their icon settings (which they can do with more precision) using their own JNLP document which contains icon image URIs.

  • Interface: classification of the parts of the JNLP as owned, merged, and defaulted
  • Stability: evolving
  • Former Stability (if changing):
  • Comments:
  • Interface: relative references from developer's JNLP to JARs and other JNLPs
  • Stability: evolving
  • Former Stability (if changing):
  • Comments: The use of straightforward relative path-to-JAR hrefs is consistent with the JNLP spec. The added aspect of path-to-JAR!path-within-JAR.jnlp is supported by the GlassFish Grizzly adapter which serves requests from the generated Java Web Start. This might or might not be supported by Java Web Start itself in other settings.

4.5.2 Imported interfaces

Disclose interfaces this project imports.

  • Interface: JNLP specification
  • Stability: standard
  • Exporting Project: Java Network Launching Protocol (JSR-56)
  • Comments: This link shows the format of the JNLP document in a table. The formal spec is downloadable here.

4.5.3 Other interfaces (Optional)

  • Interface: Location and format of the config files controlling which JNLP fragments are treated how
  • Stability: private
  • Exporting Project:
  • Comments: Obviously the location and content of the file is visible to users, but the format and contents are not part of the official supported interface of GlassFish.

4.6. Doc Impact:

Application Development Guide
[ Application Deployment Guide |ApplicationDeplyomentGuide], Appendix B, Enterprise Server Deployment Descriptor Files

4.7. Admin/Config Impact:

No admin impact

4.8. HA Impact:

No HA impact

4.9. I18N/L10N Impact:

No impact.

4.10. Packaging & Delivery:

No impact.

4.11. Security Impact:

No impact other than that described earlier, requiring GlassFish to scan user-provided JNLPs and add any referenced JARs to the legal content to serve.

4.12. Compatibility Impact

No incompatibilities.

The new XML element is optional and so does not invalidate existing glassfish-application-client.xml descriptors.

No upgrade or migration requirements imposed.

4.13. Dependencies:

No dependencies on other projects or modules.

5. Reference Documents:

See earlier list of issues.

6. Schedule:

6.1. Projected Availability:

With GlassFish 3.1.