Java

JNLP アプリケーションの Web アーカイブへのパッケージ化

Java TM Web Start 1.4.2

 

コメントおよびフィードバックは、Java Web Start のフィードバックまでお送りください。

目次

はじめに

サーブレットの設定
リソースの指定
要求からリソースへのマッピング
JNLP ファイルの処理

はじめに

Java Web Start の開発者向けパックに含まれているサーブレットを使えば、JNLP ファイルとその関連リソースを、Web アーカイブ (.war) ファイル内にパッケージ化できます。このサーブレットの目的は、JNLP アプリケーション用の単純で便利なパッケージ形式を提供することで、Tomcat などの Web コンテナや J2EE 互換のアプリケーションサーバに JNLP アプリケーションを簡単に配備できるようにすることです。

ダウンロードサーブレットがサポートする機能は、次のとおりです。

パッケージ化をサポートしているのは、単一のサーブレット JnlpDownloadServlet です。このサーブレットは jnlp-servlet.jar ファイル内に収められています。

以下に、このサーブレットの使用例を 2 つ示します。その後、このサーブレットの機能について詳しく説明します。

1 つ目の例では、バージョンベースのダウンロードプロトコルを使用せずにアプリケーションを WAR ファイル内にパッケージ化する方法を示しています。要求発生時に、JnlpDownloadServlet を使って実際の URL が JNLP ファイル内に挿入されます。2 つ目の例では、バージョンベースのダウンロードサポートを追加する方法を示しています。

バージョンベースのダウンロードプロトコルを使用しない WAR ファイル

example1.war に含まれるファイルは、次のとおりです。
   /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/<XML パーサの JAR ファイル> (サーブレットコンテナが J2SE 1.4 以上を実行している場合は必要なし)
アプリケーションの JNLP ファイルは、次のようになります。
   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>
TS タグが付いた最初の行には、サーブレットが JNLP ファイルに対して返すタイムスタンプが含まれています。タイムスタンプの形式は、
ISO 8601 形式です。この行が省略された場合、WAR ファイル内におけるこのファイルのタイムスタンプが使用されます。$$codebase 文字列は、JnlpDownloadServlet によって、要求時に使われる実際の URL に変更されます。

web.xml ファイルでは、すべての JNLP ファイル要求に対して JNLPDownloadServlet を呼び出すように、Web コンテナに指示しています。

  <web-app>
     <servlet>
        <servlet-name>JnlpDownloadServlet</servlet-name>
        <servlet-class>com.sun.javaws.servlet.JnlpDownloadServlet</servlet-class>
     </servlet>
     <servlet-mapping>
        <servlet-name>JnlpDownloadServlet</servlet-name>
        <url-pattern>*.jnlp</url-pattern>
     </servlet-mapping>
  </web-app>
JnlpDownloadServlet の実行には XML パーサが必要となります。サーブレットコンテナが J2SE 1.4 以上を実行している場合は、XML パーサがすでに組み込まれています。そうでない場合は、Java 用 XML パーサを実装した JAR ファイルを、WEB-INF/lib ディレクトリに追加してください。パーサのリファレンス実装は、http://java.sun.com/xml からダウンロードできます。

バージョンベースのダウンロードプロトコルを使用する WAR ファイル

example2.war に含まれるファイルは、次のとおりです。
   /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/<XML パーサの JAR ファイル> (サーブレットコンテナが J2SE 1.4 以上を実行している場合は必要なし)
/app ディレクトリには 2 つの JAR リソース (application.jarlib.jar) が含まれています。lib.jar には、ある命名規約に従ってバージョン ID 2.1 が関連付けられています (つまり、バージョン情報の関連付けが、ファイル単位で行われています)。application.jar ファイルのバージョン情報は、version.xml ファイル内に記述されています (つまり、バージョン情報の関連付けが、ディレクトリ単位で行われています)。version.xml ファイルは、次のようになります。
   <jnlp-versions>
      <resource>
         <pattern>
           <name>application.jar</name>
            <version-id>1.1</version-id>
         </pattern>
         <file>application.jar</file>
      </resource>
   </jnlp-versions>
アプリケーションの JNLP ファイルは、次のようになります。
   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>
最後に、web.xml ファイルで、すべての /app ディレクトリ要求に対して JnlpDownloadServlet が呼び出されるように設定しています。
  <web-app>
     <servlet>
        <servlet-name>JnlpDownloadServlet</servlet-name>
        <servlet-class>com.sun.javaws.servlet.JnlpDownloadServlet</servlet-class>
     </servlet>
     <servlet-mapping>
        <servlet-name>JnlpDownloadServlet</servlet-name>
        <url-pattern>/app/*</url-pattern>
     </servlet-mapping>
  </web-app>

サーブレットの設定

ここでは、WAR ファイルを設定して JnlpDownloadServlet を組み込む方法について説明します。また、このサーブレットの設定方法についても説明します。

WAR アーカイブへのサーブレットの追加

まず、必要なサーブレットコードをサーブレットコンテナから利用できるようにする必要がありますが、それには、WEB-INF/lib ディレクトリ内にコードを格納します。サーブレットを WAR アーカイブに追加するには、jnlp-servlet.jar ファイルを WEB-INF/lib/ ディレクトリ内に格納します。このサーブレットは XML パーサにアクセスする必要があります。サーブレットコンテナが J2SE 1.4 以上を実行している場合は、XML パーサがすでに組み込まれています。そうでない場合は、Java 用の XML パーサを実装した JAR ファイルも追加する必要があります。それらの JAR ファイルは、
http://java.sun.com/xml からダウンロードできます。

サーブレットコードが利用可能になったら、次に、適切な JNLP/JAR ファイルセットまたはサブディレクトリに対してそのサーブレットが呼び出されるように、Web コンテナに指示する必要があります。そうした設定はすべて、次のように、WEB-INF/web.xml ファイル内の <web-app> タグの内側に記述します。

   <web-app>
      ...
   </web-app>
最初にすべきことは、サーブレットの呼び出し方を Web コンテナに指示することです。それには、次のように <servlet> タグを使用します。
   <servlet>
      <servlet-name>JnlpDownloadServlet</servlet-name>
      <servlet-class>com.sun.javaws.servlet.JnlpDownloadServlet</servlet-class>
   </servlet>
次に、サーブレットを呼び出すタイミングを Web コンテナに指示する必要があります。それを行う方法は複数存在します。サーブレットの呼び出しは、特定のディレクトリ、特定の拡張子を持つファイルのいずれかに対して行えます。たとえば、JNLP ファイルに対して呼び出すには、次のコードを web.xml ファイルに追加します。
   <servlet-mapping>
     <servlet-name>JnlpDownloadServlet</servlet-name>
     <url-pattern>*.jnlp</url-pattern>
   </servlet-mapping>
一方、特定のサブディレクトリ (ここでは /app) に対して呼び出すには、次のコードを追加します。
   <servlet-mapping>
     <servlet-name>JnlpDownloadServlet</servlet-name>
     <url-pattern>/app/*</url-pattern>
   </servlet-mapping>

サーブレットの設定方法の具体例として、example1example2 も参照してください。

ログ機能

このサーブレットには、自身の動作を監視するためのログ機能が組み込まれています。生成されるログメッセージは、次の 4 種類に分類されます。
FATAL (致命的)
サーブレット内で発生した障害または内部エラー
WARNING (警告)
version.xml ファイルの解析中など、WAR ファイル内の情報を処理している間に発生したエラー
INFORMATIONAL (情報)
すべての要求/応答、ディレクトリの再走査などの情報
DEBUG (デバッグ)
要求の処理方法に関する詳しい内部情報
ログ出力は、2 つのサーブレット初期化パラメータ logLevellogPath によって制御されます。ログレベルに設定可能な値は、NONE、FATAL、WARNING、INFORMATIONAL、DEBUG のいずれかです。ログパスには、出力を書き込むファイルを指定します。パスが指定されなかった場合のログの出力先は、サーブレットの標準ログになります (ServletContext.log メソッドを使用)。次に例を示します。
 <servlet>
    <servlet-name>
      JnlpDownloadServlet
    </servlet-name>
    <servlet-class>
      com.sun.javaws.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>

ファイル拡張子と MIME タイプの設定

サーブレットは、JNLP ファイルと JAR ファイルを特別扱いします。後述するように、JNLP ファイルはマクロ展開されます。バージョンベースの JAR ファイル要求に対しては、差分更新用のファイルが生成される可能性があります。サーブレットは、あるファイルが JNLP ファイルまたは JAR ファイルであるかどうかを、拡張子に基づいて判断します。デフォルトの拡張子は、JNLP ファイルの場合は .jnlp、JAR ファイルの場合は .jar です。これらのデフォルトの拡張子を上書きするには、初期化パラメータ jnlp-extensionjar-extension を使用します。次に例を示します。
    <init-param>
      <param-name>
        jnlp-extension
      </param-name>

      <param-value>
        .xjnlp
      </param-value>
    </init-param>
特定のファイルに対して返される MIME タイプも、拡張子に基づいて決定されます。MIME タイプの検索は、Web コンテナおよび WAR ファイルの設定ファイル内で行われます。マッピングを指定しなかった場合のデフォルトの MIME タイプは、次のとおりです。
     拡張子      デフォルトの MIME タイプ
     -------------------------------------------
       .jnlp        application/x-java-jnlp-file
       .jar         application/x-java-archive
       .jardiff     application/x-java-archive-diff
マッピングを上書きするには、web.xml ファイル内で <mime-type> 要素を使用します。次に例を示します。
  <web-app>
     ...
     <mime-mapping>
        <extension>jnlp</extension>
        <mime-type>text/ascii</mime-type>
     </mime-mapping>
     ...
  </web-app>

リソースの指定

イメージ、JAR ファイル、JNLP ファイルなどのアプリケーションリソースは、WAR ファイル内に格納されます。WAR ファイルはそれ自身、階層ディレクトリ構造になっており、WAR ファイル内における各リソースの配置場所によって、検索時に使用される URL が決まります。

ここで、http://www.mytool.com/tool/ で始まるすべての URL 要求を処理するように、WAR ファイル (あるいはサーブレット) が設定されているものとします。このとき、http://www.mytool.com/tool/app/launch.jnlp が要求されたとすると、JnlpDownloadServlet は、WAR ファイルの app/ ディレクトリ内で、launch.jnlp リソースを検索します。

バージョン情報がない場合

アプリケーションの JNLP ファイルのように、バージョン情報が関連付けられていないリソースは、WAR ファイル内にそのまま追加されます。たとえば、上記の例であれば、WAR ファイル内に次のファイルが含まれているはずです。
    /app/launch.jnlp
一般に、あるファイルに対して返されるタイムスタンプは、そのファイルの WAR ファイル内における最終更新タイムスタンプです。ただし、JNLP ファイルだけは例外です。JNLP ファイルでは、タイムスタンプを明示的に指定できます (
以下を参照)。

バージョン関連情報がある場合

JNLP 仕様に規定されたバージョンベースのダウンロードプロトコルと拡張ダウンロードプロトコルを使えば、バージョン ID、オペレーティングシステム、システムアーキテクチャ、およびロケールに基づいたリソース検索を行えます。JnlpDownloadServlet には、これらの情報をリソースに関連付けるための方法が 2 つ用意されています。命名規約を使ってファイル単位で関連付ける方法と、設定ファイルを使ってディレクトリ単位で関連付ける方法です。同一のディレクトリに両方の方法を適用することも可能です。

リソースに関連付けることのできる情報は、次のとおりです。

パスは、リソースの WAR アーカイブ内における配置場所として指定されます。それ以外の情報はすべて、命名規約、version.xml ファイルのいずれかを使って指定されます。

リソースの命名

ファイル名に二重下線 (__) マーカが含まれていた場合、ファイルの命名規約が使用されます。ファイル名は、BNF 記法で記述された次の規則に従って解析されます。
	file    ::= name __ options . ext
	options ::= option ( __ options ) *
	option  ::= V version-id |
        	    O os |
            	    A arch |
            	    L locale
1 つのファイルに対して指定可能な version-id は、1 つだけです。これに対し、os、arch、locale の各フィールドは複数指定できます。次に例を示します。
	application__V1.2__Len_US__Len.jar
上記の例は、リソース application.jar のバージョン ID が 1.2 であり、ロケール en_USen をサポートしていることを意味します。

version.xml ファイル

特定のディレクトリ内に version.xml ファイルを配置すれば、そのディレクトリ内のファイルに対して、バージョン ID などの追加プロパティを記述できます。これが、ファイル命名規約に代わる、もう 1 つの方法です。

たとえば、ファイル application-1_2-us.jar と次の内容を持つ version.xml を、あるディレクトリ内に配置したとします。

       <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>
これは、ファイル application__V1.2__Len_US__Len.jar をそのディレクトリ内に配置するのと、同じ効果をもちます。

version.xml ファイルでは、特定のリソースにプラットフォームのバージョン ID を指定することも可能です。そのようなリソースは、特定の JRE プラットフォーム要求にマッチさせるために使用されます。プラットフォームのバージョン ID が関連付けられるリソースは、<platform> 要素を使って指定されます。次に例を示します。

	  <platform>
             <pattern>
                <name>J2RE</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>
プラットフォームバージョン要求は Java Web Start によって内部的に生成されますが、それが生成されるのは、アプリケーションから要求された特定バージョンの Java 2 プラットフォームがローカルシステム上にインストールされていなかった場合です。

version.xml の完全なドキュメント型定義 (DTD) を、次に示します。

   <!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)>

要求からリソースへのマッピング

JNLP 仕様では、Java Web Start (より一般的には JNLP クライアント) がリソース要求時にサーバに対して送信可能なダウンロード要求が、4 種類定義されています。

JNLPDownloadServlet は、要求に対して初期処理を施すことで、要求から次の情報を取り出します。

ここで、example2http://www.mytool.com/tool2/ に配置されているものとします。このとき、http://www.mytool.com/tool2/app/lib.jar&version-id=2.1 が要求されたとすると、リソースのパスは app/、名前は lib.jar、バージョン文字列は 2.1 であり、オペレーティングシステム、アーキテクチャ、ロケールの各リストはすべて空になります。

特定のディレクトリに対する要求、たとえば http://www.mytool.com/tool2/app/ には、末尾にデフォルトのファイル名である launch.jnlp が追加されます。したがって、この要求は http://www.mytool.com/tool2/app/launch.jnlp と同等になります。

基本ダウンロード要求の処理

バージョン ID が指定されていない要求 (version-idplatform-version-id のいずれのパラメータも指定されていない要求) は、基本ダウンロード要求として処理されます。

まず、要求に二重下線 (__) が含まれているかどうかと、要求対象のファイルが version.xml であるかどうかがチェックされます。このいずれかの条件に合致した場合、その要求は拒否され、HTTP 404 エラーコードが返されます。

続いて、JnlpDownloadServlet によって、指定されたパスと名前を持つリソースが WAR ファイル内で検索され、見つかった場合はそのリソースが返されます。リソースが見つからなかった場合、その要求に対して HTTP 404 エラーコードが返されます。

見つかったリソースが JNLP ファイルであった場合、そのリソースは後述の方法で前処理されてから返されます。

バージョンベースのダウンロード要求の処理

バージョン ID が指定されたリソースの検索方法は、バージョンベースダウンロード要求、拡張ダウンロード要求、プラットフォームバージョンダウンロード要求のすべてにおいて同一です。

まず、JnlpDownloadServlet は、URL 要求がアクセスしようとしている WAR ファイルディレクトリ内に配置されたすべてのリソースからなるデータベースを生成します (ディレクトリは要求のパスに基づいて決定されます)。データベースの生成時には、そのディレクトリ内にある version.xml ファイル (存在する場合) と、上述した命名規約を使用しているすべてのファイルが、走査されます。これらの情報は、サーブレットによって内部的にキャッシュされます。サーブレットによって再走査が実行されるのは、version.xml ファイルのタイムスタンプが、最後に行った走査時のタイムスタンプよりも新しい場合だけです。したがって、命名規約を使ったファイルを追加した場合は、必ず version.xml ファイルも更新してください。そうすれば、サーブレットによる再走査が起動されます。

続いて、サーブレットは、データベース内のエントリを走査することで、要求に一致するものを検索します (一致規則については後述します)。プラットフォーム以外に対する要求の場合、最初に version.xml ファイルの resource エントリがファイル内に指定された順番で走査されたあと、命名規約を使って指定されたエントリが走査されます。プラットフォームバージョン要求の場合、version.xml ファイルの platform エントリが、ファイル内に指定された順番で走査されます。要求に一致するエントリが複数見つかった場合、バージョン ID のもっとも高いものが返されます。一致するエントリのうち、バージョン ID のもっとも高いものが複数存在した場合、一番先に指定されていたエントリが返されます。

一致規則は次のとおりです。

  1. リソースの名前が要求の名前と一致する必要がある
  2. リソースのバージョン ID が要求のバージョン文字列と一致する必要がある
  3. オペレーティングシステム、アーキテクチャ、ロケールの各リストについては、次の規則が適用される
    1. リソースに空のリストが指定されていた場合、無条件に一致とみなす
    2. リソースに空でないリストが指定されていた場合、リソースに指定された値の少なくとも 1 つが、要求に指定された値の少なくとも 1 つに前方一致した場合に、一致とみなす
応答時に返される x-java-jnlp-version-id は、一致したリソースのバージョン ID です。ただし、プラットフォーム要求の場合だけは、version.xml ファイル内の <product-version-id> フィールドの値が返されます。

見つかったリソースが JNLP ファイルであった場合、そのリソースは後述の方法で前処理されてから返されます。

JARDiff の自動生成

サーブレットは、可能であれば、JAR ファイルの差分更新を自動生成し、それを要求元に返します。要求内に current-version-id パラメータが含まれており、(上記の一致規則に基づいて) current-version-id に一致するリソースと要求されたバージョンに一致するリソースの両方が見つかり、さらにその要求が JAR ファイルに対するものであった (たとえば、目的とするリソースの拡張子が .jar であった) 場合、サーブレットによって JARDiff ファイルが生成されます。ただし、JARDiff ファイルが返されるのは、そのサイズが要求されたバージョンのサイズよりも小さい場合だけです。

生成された JARDiff ファイルは、Web コンテナの一時ディレクトリ内に格納されます。サーブレットは、javax.servlet.context.tempdir コンテキスト属性を使ってこの作業用の一時ディレクトリを特定します。

JNLP ファイルの処理

JnlpDownloadServlet は自動的に、JNLP ファイル内の特定のテンプレート値をマクロ展開し、現在の要求に合った URL に置き換えます。これにより、JNLP ファイルを記述および配備する際に、ハードコードされた URL をファイル内に含める必要がなくなります。

マクロ展開

サーブレットは自動的に、JNLP ファイル内の特定のキー (先頭に $$ が付いたもの) を、現在の要求に基づく URL に置換します。これらのキーの目的は、配備位置に依存しない WAR ファイルを作成し、Web コンテナ内に自由に配備できるようにすることです。

次の表に、サーブレットが検索および置換する 3 つのキーを示します。

パターン       値
         ----------------------------------------------------------------
         $$codebase    要求時の完全な URL (JNLP ファイルの名前は除く)
         $$name        JNLP ファイルの名前
         $$context     Web アーカイブのベース URL.
次に例を示します。ここで、
example1 の WAR ファイルを取り上げます。このファイルが http://www.mytool.com/tool に配備されているものとします。このとき、http://www.mytool.com/tool/app/launch.jnlp を要求すると、その JNLP ファイルが返されます。キーのマクロ展開後の値は、次のようになっているはずです。
      $$codebase = http://www.mytool.com/tool/app/
      $$name     = launch.jnlp
      $$context  = http://www.mytool.com/tool/

サーブレットは、JNLP ファイルの形式が正しいかどうか、またその XML が整形式になっているかどうかを検証しません。値の置換は、純粋なテキスト整形処理として実行されます。

明示的なタイムスタンプ

JNLP ファイル内に明示的なタイムスタンプを含めると、Web サーバから一貫性のあるタイムスタンプを確実に返せるようになります。これが特に役立つのは、ラウンドロビン方式、負荷分散方式のいずれかを使って同一の URL を提供する複数の Web サーバ上に、単一の JNLP ファイルを複製するような場合です。ただし、JAR ファイルに対しては、そのような方法は提供されていません。代わりに、バージョンベースのダウンロードプロトコルを使用する必要があります。

JNLP 内の先頭行が TS: で始まっている場合、明示的なタイムスタンプが含まれています。その場合、ISO 8601 のタイムスタンプ形式に従って解析が行われます (以下を参照)。また、その先頭行はコンテンツから除外されます。

TS: 要素を含む JNLP ファイルの例として、前出の example1 および example2 を参照してください。

ISO 8601 形式

タイムスタンプの一般的な形式は、次のとおりです。
   YYYY-MM-DD hh:mm:ss
ダッシュ、コロン、および秒は、次のように省略可能です。
   YYYYMMDDhhmm
hh は 24 時間単位で表記します。タイムゾーンはデフォルトで、ローカルのものが使用されます。UT (Universal Time、GMT としても知られる) であることを示すには、次のように、大文字の Z を時刻の末尾に追加します。
     23:59:59Z または 235959Z
次の文字列を時刻に追加すれば、使用中のローカルタイムゾーンが UTC よりも、hh 時間と mm 分だけ進んでいることを示せます。
     +hh:mm、+hhmm、または +hh
経度ゼロより西にあるタイムゾーン (UTC より遅れているタイムゾーン) では、次の表記が代わりに使用されます。
     -hh:mm、-hhmm、または -hh
たとえば、CET (Central European Time) では +0100、米国およびカナダの EST (Eastern Standard Time) では -0500 となります。次の文字列はすべて、同じ時刻を表します。
     12:00Z = 13:00+01:00 = 0700-0500


Copyright © 2002 Sun Microsystems, Inc. All Rights Reserved.