JnlpDownloadServlet ガイド


 

目次

はじめに

サーブレットの構成
リソースの指定
リソースへの要求のマッピング
JNLP ファイルの処理
Pack200 のサポート

はじめに

Java Web Start では、JDK の sample/jnlp ディレクトリにサーブレットが含まれています。このサーブレットは、Web アーカイブ (.war) ファイルにパッケージ化された JNLP ファイルとその関連リソース、またはアーカイブされていないディレクトリで使用できます。このサーブレットの目的は、JNLP アプリケーション用の簡単で利便性の高いパッケージング形式を提供することによって、Tomcat や J2EE 準拠のアプリケーションサーバなどの Web コンテナに JNLP アプリケーションを容易に配備できるようにすることです。

ダウンロードサーブレットは、次の機能をサポートします。

パッケージ化をサポートしているのは、JnlpDownloadServlet という 1 つのサーブレットです。このサーブレットは、jnlp-servlet.jar ファイルにパッケージ化されています。jnlp-servlet.jar ファイルは、SDK の samples/jnlp/servlet/ の下にあります。

以下に、サーブレットの使用方法を示す 2 つの例、およびサーブレットの機能の詳細を説明します。

1 つ目の例では、バージョンベースのダウンロードを使用せずに、アプリケーションを WAR ファイルにパッケージ化する方法を示します。JnlpDownloadServlet を使って、要求時に正確な URL (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>jnlp.sample.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+ を実行している場合は、J2SE に XML パーサが統合されています。J2SE 1.4+ を実行していない場合は、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>

最後に、/app ディレクトリへのすべての要求に対して JnlpDownloadServlet が呼び出されるように、web.xml ファイルを構成します。

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


サーブレットの構成

このセクションでは、JnlpDownloadServlet を含めて WAR ファイルを構成する方法、およびサーブレットの構成方法を説明します。

 

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

まず、必要なサーブレットコードをサーブレットコンテナから利用できるようにする必要があります。これは、WEB-INF/lib ディレクトリを生成することにより行われます。WEB-INF/lib/ ディレクトリに jnlp-servlet.jar ファイルを格納することによって、WAR アーカイブにサーブレットが追加されます。サーブレットは XML パーサにアクセスする必要があります。サーブレットコンテナが J2SE 1.4+ を実行している場合は、J2SE に XML パーサが統合されています。J2SE 1.4+ を実行していない場合は、Java XML パーサを実装する 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>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class>
   </servlet>

次に、サーブレットをいつ呼び出すかを Web コンテナに指示します。これには、いくつかの方法があります。1 つの方法として、特定のディレクトリ、または特定の拡張子を持つファイルが指定された場合に呼び出すことができます。たとえば、JNLP ファイルに対してサーブレットを呼び出す場合は、次のコードを web.xml ファイルに追加します。

   <servlet-mapping>
     <servlet-name>JnlpDownloadServlet</servlet-name>
     <url-pattern>*.jnlp</url-pattern>
   </servlet-mapping>

特定のサブディレクトリに対してサーブレットを呼び出す場合は、次のコードを追加します。

   <servlet-mapping>
     <servlet-name>JnlpDownloadServlet</servlet-name>
     <url-pattern>/app/*</url-pattern>
   </servlet-mapping>

サーブレットの構成方法の例については、example1example2 も参照してください。

ログ

サーブレットには、その動作を監視するためのログ機能が組み込まれています。生成されるログメッセージは、次の 4 つのカテゴリに分けられます。

FATAL (致命的)
 
サーブレット内部で発生した機能不全エラーまたは内部エラー
WARNING (警告)
WAR ファイル内の情報の処理中 (version.xml ファイルの構文解析など) に発生したエラー
INFORMATIONAL (情報)
すべての要求、応答、ディレクトリの再走査などのログ
DEBUG (デバッグ)
要求がどのように処理されているかを示す詳細な内部情報

ログ出力は、2 つのサーブレット初期化パラメータ logLevellogPath によって制御されます。ログレベルは、NONE、FATAL、WARNING、INFORMATIONAL、DEBUG のいずれかに設定できます。ログパスには、出力の書き込み先のファイルを指定します。パスを指定しない場合、ログはサーブレットの標準ログに書き込まれます (ServletContext.log メソッドを使用)。次に例を示します。

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

ファイル拡張子と 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 が決まります。

WAR ファイル (またはサーブレット) が、http://www.mytool.com/tool/ で始まるすべての URL 要求を処理するように構成されている場合を考えてみましょう。このとき、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

バージョン ID は、ファイルごとに 1 つだけ指定できます。ただし、os、arch、locale の各フィールドは複数指定できます。次に例を示します。

	application__V1.2__Len_US__Len.jar

この例では、リソース application.jar には、バージョン ID 1.2 とロケールen_US および en が関連付けられています。

version.xml ファイル

各ディレクトリに version.xml ファイルを配置することにより、特定のそのディレクトリ内のファイルの追加情報 (バージョン ID など) を記述できます。このファイルは、ファイル命名規約の代わりに使用することができます。

たとえば、ディレクトリ内にファイル application-1_2-us.jarversion.xml を配置し、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 2 プラットフォームのバージョンをアプリケーションが要求すると、Java Web Start はプラットフォームバージョン要求を内部で生成します。

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 仕様には、4 種類の異なるダウンロード要求が定義されています。Java Web Start (より一般的には JNLP クライアント) は、リソースの要求時に、サーバに対してこれらのダウンロード要求を実行できます。

要求は、最初に JNLPDownloadServlet によって処理され、次の情報が抽出されます。

example2 の事例で、それが http://www.mytool.com/tool2/ に配置されている場合を考えてみましょう。このとき、http://www.mytool.com/tool2/app/lib.jar&version-id=2.1 が実行されるとします。この場合、リソースのパスは app/ に、名前は lib.jar に、バージョン文字列は 2.1 に、OS、アーキテクチャ、ロケールの各リストは空になります。

ディレクトリへの要求 (http://www.mytool.com/tool2/app/ など) には、デフォルトのファイル名launch.jnlp が追加されます。このため、この要求は http://www.mytool.com/tool2/app/launch.jnlp と同じになります。

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

バージョン ID が指定されていない要求 (version-id パラメータも platform-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 で置き換えます。これにより、ハードコードされた URL を含めずに、JNLP ファイルを記述および配備することができます。

マクロ展開

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

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

         パターン       値
         ----------------------------------------------------------------
         $$codebase    要求の完全な URL (JNLP ファイルの名前は除く)
         $$name        JNLP ファイルの名前
         $$context     Web アーカイブのベース URL.

例:example1 の WAR ファイルを考えましょう。この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 サーバが返すタイムスタンプを一定にできます。JNLP ファイルが、ラウンドロビン方式または負荷均衡方式で同一の URL のサーバとして稼動する複数の Web サーバ上で複製される場合、特に有用です。同様の手法は、JAR ファイルには適用されないことに注意してください。JAR ファイルの場合、バージョンベースのダウンロードプロトコルを代わりに使用する必要があります。

最初の行が TS: で始まる場合、明示的なタイムスタンプが JNLP に含まれます。この場合、タイムスタンプは ISO 8601 形式に基づいて構文解析されます (次の節を参照)。最初の行は、コンテンツからも削除されます。

TS: 要素を使用したサンプル JNLP ファイルの例については、前述の example1 および example2 を参照してください。

ISO 8601 形式

一般的なタイムスタンプの形式は、次のとおりです。

   YYYY-MM-DD hh:mm:ss

次に示すように、ダッシュ、コロン、および秒を付けずに記述することもできます。

   YYYYMMDDhhmm

hh は 24 時間単位で表記します。デフォルトでは、ローカルタイムゾーンが使用されます。次に示すように、時刻の最後に大文字の Z を追加することにより、UTC (世界標準時、GMT としても知られる) を指定することもできます。

     23:59:59Z または 235959Z

次の文字列を時刻に追加することにより、使用するローカルタイムゾーンが、UTC に hh 時間 mm 分を追加したものであることを指定できます。

     +hh:mm、+hhmm、または +hh

経度ゼロより西のタイムゾーン (UTC よりも前の時間になる) の場合は、次のように表記します。

     -hh:mm、-hhmm、または -hh

たとえば、中央ヨーロッパ標準時 (CET) は +0100、米国およびカナダの東部標準時 (EST) は -0500 となります。次の文字列は、すべて同じ時刻を指します。

     12:00Z = 13:00+01:00 = 0700-0500

Pack200 のサポート

*.jar.pack.gz または *.jar.gz ファイルを元の *.jar ファイルとともに収容できるようになりました。クライアントが pack200-gzip または gzip ファイル形式をサポートしている場合、サーバで圧縮ファイルを使用できれば、サーブレットは圧縮ファイルを返します。Java Web Start 5.0 では、どちらの圧縮形式もサポートしています。元の jar ファイルとパックファイルは両方ともサーバに収容する必要があります。そうでない場合、サーブレットはパックファイルを取り出しません。パックファイルは、J2SE 5.0 に含まれる pack200.exe コマンドを使って作成できます。pack200 圧縮テクノロジの詳細については、「Pack200 and Compression for Network Deployment」を参照してください。