JavaTM プラットフォーム V 1.2 での拡張機能とアプリケーションのサポート |
このドキュメントでは、拡張機能を扱うための Java プラットフォームの新しい機構について説明します。拡張機能は、1 つまたは複数の JAR ファイルにまとめられたパッケージの集まりで、Java プラットフォームを拡張する API を実装します。拡張クラスはプラットフォームを拡張して、Virtual Machine が、クラスパスに存在しないクラスをプラットフォームのコア API のクラスであるかのように発見し、ロードできるようにします。拡張機能の実装は、Java プログラミング言語で記述されたコードですが、まれに、プラットフォーム固有のネイティブコードが含まれる場合もあります。さらに、プロパティ、地域対応のカタログ、イメージ、直列化されたデータ、およびその他のリソースなど、その拡張機能に固有の各種リソースが含まれることもあります。
Internet Explorer や Netscape NavigatorTM などのブラウザでは、拡張機能は Java Plug-in によってサポートされます。
標準拡張機能は、オープンで標準的な API を実装したものです (Sun が提供する標準拡張機能の例は、JavaServlet、Java3D、JavaManagement など)。例外もありますが、標準的な拡張機能パッケージの多くは javax.* の名前空間に割り当てられます。
アーキテクチャ
拡張機能機構は、次の要素を含むように設計されています。したがって通常、アプリケーションでは、必要な拡張機能 (より一般的な言い方をすれば、ライブラリ) を指定して、さらに提供する必要があります。システムは、インストールされている拡張機能 (およびライブラリ) がある場合は、それを選び、ない場合は、参照されている拡張機能 (およびライブラリ) クラスの検索とロードをアプリケーションのクラスローダに委譲します。
- JAR ファイルにまとめた拡張機能またはアプリケーションは、ほかの JAR ファイルとの依存関係を宣言できるようになっています。このため、アプリケーションを複数のモジュールで構成できます。
- クラスローディング機構を拡張して、インストール型拡張機能 (およびほかのライブラリ) からクラスを検索できるようになっています。検索に失敗すると、アプリケーションで指定したパスからクラスを検索します。
このアーキテクチャでは、アプリケーション、アプレット、およびサーブレットがそれら自体のクラスパスを拡張できるので、それらを複数の JAR ファイルとしてまとめ、配置することも可能になります。
それぞれの拡張機能またはアプリケーションは、少くとも 1 つの JAR ファイルで構成されます。JAR ファイルにはマニフェスト、コード、各種リソースが含まれることもあります。後述するように、この主 JAR ファイルには、ほかの JAR ファイルとの依存関係を記述するため、そのマニフェストに付加情報を含めることもできます。拡張機能を JAR ファイルにまとめるためには ZIP 互換のアーカイブツールも利用できますが、JDK ソフトウェアに付属のコマンド行ツール jar を利用すると便利です。(jar ツール の参照ページ: [Win32][Solaris])
拡張機能またはアプリケーションは、主 JAR ファイルから参照される別の JAR ファイルを参照することもあります。これらの JAR ファイルには、JAR ファイルごとに独自の依存関係情報を含めることもできます。
拡張機能を含むパッケージは、拡張機能の実装時には、標準的なパッケージ命名規約に従って命名する必要があります。この命名規約は Java 言語仕様で大筋が示されていますが、ドメインの接頭辞はすべて大文字で指定するという規則はなくなりました。たとえば、COM.sun.server というパッケージ名は com.sun.server とも指定できます。アプリケーションと拡張機能は同じクラスローダを共有する場合があるので、名前の衝突を避けるため、パッケージには一意の名前を付けることをお勧めします。
拡張機能の配置
拡張機能は、アプリケーションにバンドルする (バンドル型) 方法と、すべてのアプリケーションで使用できるように JRE にインストールする (インストール型) 方法があります。バンドル型拡張機能はアプリケーションと同じコードベースに置かれ、ネットワークアプリケーション (アプレット) の場合は自動的にダウンロードされます。したがって、バンドル型拡張機能は、「ダウンロード型」拡張機能と呼ばれる場合があります。インストール型拡張機能は、最初に使用されるときにロードされ、その JRE 上で動作するすべてのアプリケーションによって共有されます。
拡張機能をまとめる場合には、JAR ファイルのマニフェストはベンダーおよびバージョン情報を識別するために使用されます (「パッケージのバージョン管理の仕様」を参照)。
インストール型拡張機能のクラスは、同じ Java 1.2 Virtual Machine 上のすべてのコードによって「共有」されます。したがって、インストール型拡張機能はそのプラットフォームの (rt.jar の) コアクラスに似ていますが、インストール型拡張機能は、後述するように、専用のクラスローダと事前に構成されたセキュリティポリシーを持ちます。
バンドル型拡張機能のクラスは、当該アプリケーション、アプレット、またはサーブレットのクラスローダだけが使用します。アプレットなどのネットワークアプリケーションの場合、バンドル型拡張機能は必要に応じて自動的にダウンロードされます。現時点では、クラスローダは特定のコードベースに関連付けられているので、同じコードベースに置かれたアプレットであれば実装 (JAR) を共有できます。
バンドル型拡張機能
アプリケーションまたは拡張機能のマニフェストでは、必要な拡張機能 (およびその他のライブラリ) が含まれる JAR ファイルとディレクトリを参照する相対 URL を 1 つ以上指定できます。これらの相対 URL は、アプリケーションまたは拡張機能が含まれている JAR ファイルのロード元であるコードベースと相対的な位置関係にあるものとして扱われます。アプリケーション (より一般的には、JAR ファイル) は、必要な拡張機能 (およびライブラリ) の URL を、マニフェスト属性 Class-Path で指定します。この属性では、ホストの Java Virtual Machine にインストールされた拡張機能の中から目的の拡張機能 (またはその他のライブラリ) の実装が見つからなかった場合に検索する URL を列挙します。この相対 URL には、アプリケーションまたは拡張機能が必要とするライブラリまたはリソースが含まれる JAR ファイルとディレクトリを含めることができます。「/」で終わらない URL は、JAR ファイルを参照しているものと見なされます。例を次に示します。
Class-Path: servlet.jar infobus.jar acme/beans.jar images/Class-Path ヘッダを複数指定することもできます。複数指定した場合は、順に連結されます。
現時点では、セキュリティ上の理由により、URL は JAR ファイルのコードベースから「相対的」に指定する必要があります。したがって、リモート拡張機能は、アプリケーションと同じコードベースを元にして指定します。将来的には、ほかの URL にある JAR ファイルを参照できるように、Java 1.2 Security API の機能が利用できるようになる予定です。
それぞれの相対 URL は、アプリケーションまたは拡張機能が含まれている JAR ファイルのロード元であるコードベースと突き合わせる形で解決されます。解決された URL が無効であるか、参照するリソースが見つからない場合、その URL は無視されます。
解決された URL は、アプリケーション、アプレット、またはサーブレットのクラスパスの拡張に使用され、クラスパスの、そのアプリケーション、アプレット、またはサーブレットが含まれる JAR ファイルの URL の直後に挿入されます。重複する URL は 取り除かれます。たとえば、次のようなクラスパスが指定されているとします。
a.jar b.jar拡張機能 b.jar に、次のようなマニフェスト属性 Class-Path が含まれている場合、Class-Path: x.jar a.jar最終的なアプリケーションクラスパスは次のようになります。a.jar x.jar b.jarもちろん、x.jar に依存情報が含まれる場合は、依存ファイルはこれと同じ規則に従って追加されます。あとに続く URL についても同様です。実際の実装では、JAR ファイルの依存関係は先に処理されるのではなく、JAR ファイルは実際に必要になったときまで開かれません。インストール型拡張機能
Sun による Java 1.2 Virtual Machine の実装では、インストール型拡張機能の JAR ファイルは、次の標準のローカルコードソースに置かれます。そのネイティブコードライブラリは、存在する場合は、次の場所に置かれます。<java-home>¥lib¥ext [Win32] <java-home>/lib/ext [Solaris]<java-home> は、ランタイムソフトウェアがインストールされているディレクトリ (JRE のトップレベルディレクトリまたは JDK ソフトウェアの jre ディレクトリ) を参照します。<arch> は、Solaris プロセッサアーキテクチャ (sparc または i386) を参照します。<java-home>¥bin [Win32] <java-home>/lib/<arch> [Solaris]インストール型拡張機能は、さらに 1 つ以上の共有ライブラリ (.dll ファイルなど) と実行可能ファイルを含んでいます。また、ネイティブライブラリは、Win32 と Solaris の両方の jre/lib/ext/<arch> ディレクトリに置かれます。Win32 システムでは <arch> は i386 です。jre/lib/ext/<arch> ディレクトリは、jre¥bin (win32) または jre/lib/<arch> (Solaris) の次に検索されます。
現時点では、ネイティブコードが含まれる拡張機能は、信頼できるコードか信頼できないコードかにかかわらず、実行時にネットワークコードにより Virtual Machine にダウンロードすることはできません。ネイティブコードが含まれ、ネットワークアプリケーションにバンドルされた拡張機能は、JRE または JDKTM ソフトウェアにインストールする必要があります。
デフォルトでは、この標準のディレクトリに置かれたインストール型拡張機能は信頼されます。つまり、このディレクトリに置かれたインストール型拡張機能には、コアプラットフォームクラス (rt.jar 内のクラス) の場合と同じ権限が与えられます。このデフォルトの権限はシステムポリシーファイルで指定されますが、適切なポリシーファイルエントリを追加することで、特定の拡張機能の権限をオーバーライドできます。
なお、信頼できるエンティティによりインストール型拡張機能の JAR ファイルに署名が付けられている場合、その拡張機能には、署名を付けたエンティティに与えられている権限が与えられます。
システムプロパティ java.ext.dirs を使用すると、インストール型拡張機能を置く場所をほかにも指定できます。このプロパティには、インストール型拡張機能を検索するディレクトリを指定できます。複数のディレクトリを指定する場合は、File.pathSeparatorChar で区切ります。このプロパティのデフォルトの設定値は、上に示したインストール型拡張機能の標準のディレクトリになっています。
JAR ファイルとパッケージは、同一バージョン内で整合性が保たれるように「シール」することができます。JAR ファイル内のパッケージをシールした場合、そのパッケージ内で定義されているすべてのクラスは、同一の JAR ファイルが元になっていなければなりません。そうでない場合は、SecurityException がスローされます。
JAR ファイルをシールした場合、その JAR ファイルで定義されているすべてのパッケージは、特別に設定をオーバーライドしない限り、シールされます。
パッケージをシールするかどうかは、新しいマニフェスト属性 Sealed で指定します。このマニフェスト属性は、true か false の値をとります。大文字小文字は区別されません。例を次に示します。
このように指定すると、javax.servlet.internal がシールされ、このパッケージに含まれるすべてのクラスは同一の JAR ファイルからロードされなければなりません。Name: javax/servlet/internal/ Sealed: trueこの属性が指定されていない場合は、パッケージのシール属性は、そのパッケージが含まれる JAR ファイルのシール属性と同じになります。
JAR ファイルをシールするかどうかは、上と同じ新しいマニフェストヘッダ Sealed で指定します。このマニフェストヘッダも、同じく true か false の値をとります。例を次に示します。
このように指定すると、このアーカイブに含まれるすべてのパッケージは、マニフェストエントリの中で Sealed 属性により明示的に設定をオーバーライドしない限り、シールされます。Sealed: trueこの属性が指定されていない場合は、下位互換性を保つため、そのモジュールはシールされていないものと見なされます。このあと、システムはシール情報を見るため、パッケージのヘッダのチェックを継続します。
パッケージをシールすると、パッケージ保護されたメンバへのアクセスは、同一の JAR ファイルが元になるパッケージで定義されているクラスに制限されるため、パッケージのシールはセキュリティの上でも重要です。たとえば、実行時 JAR の rt.jar では、sun.io と java.text.resources の 2 つのパッケージを除く標準コア Java パッケージすべてがシールされています。
パッケージのシールのチェックは、ダウンロード型拡張機能だけでなくインストール型拡張機能についても行われ、違反があった場合は SecurityException がスローされます。また、null パッケージはシールできないので、シールすべきクラスはその独自のパッケージ内に置く必要があります。
インストール型拡張機能のコードソース (<java-home>/lib/ext) には、事前に構成されたセキュリティポリシーが割り当てられています。Sun の実装では、このディレクトリに置かれた JAR ファイルに与えられる正確な信頼度レベルは、次の標準のセキュリティポリシー構成ファイルによって指定されます。デフォルトのポリシーは、インストール型拡張機能が、コアプラットフォームの一部である場合と同じように動作できるようにするためのものです。これは、インストール型拡張機能がネイティブコードをロードするという一般的な必要性に基づいています。<java-home>/lib/security/java.policyJava 1.2 Security Model は、インストール型拡張機能のコードが信頼できないコードから呼び出された場合のために、ある種の安全策を提供しています。しかし、拡張機能のコードが特権ブロックを使用する場合は必ず、潜在するセキュリティ上の危険がないかどうかコードを十分に確認する必要があります。
リモートからロードされる拡張機能で、正常な動作のため、アクセスチェックが行われるシステムサービス (ファイル入出力など) を使用する必要があるものについては、信頼できるエンティティによる署名が付けられたものであるか、信頼できる場所からロードされたものでなければなりません。
新しいセキュリティ機能を利用して拡張機能やアプリケーションのコードを記述する方法の詳細については、Java 1.2「セキュリティ」を参照してください。
バージョン 1.2 のプラットフォームでは、新しい拡張機能機構をサポートするため、以下のクラスが変更または追加されています。
- public class java.lang.ClassLoader (変更)
このクラスは、クラスとリソースのロードのための新しいクラスローダ委譲モデルをサポートするため更新されました。このクラスローダ委譲モデルは、クラスまたはリソースのロード時に、それをローカルにロードするのを試みる前にいつでも必ず最初に検索される、「親」クラスローダを指定できるようにするものです。新しいクラスローダの実装では、クラスとリソースをローカルにロードする方法を指定するため、findClass と findResource の 2 つのメソッドがオーバーライドされています。
新しい委譲モデルをサポートするため、以下のメソッドが変更または追加されました。
- getSystemClassLoader
委譲のためのシステムクラスローダを返します。これは、新しい ClassLoader のインスタンスに対するデフォルトの委譲の親で、通常このクラスローダはアプリケーションの起動に使用されます。
- loadClass
クラスがすでにロードされている場合は、単にそれを返します。クラスがロードされていない場合は、親クラスローダ (親が指定されていない場合は、ブートストラップクラスローダと呼ばれる Virtual Machine の組み込みクラスローダ) からクラスのロードを試みます。それでも見つからない場合は、findClass メソッドを呼び出して、クラスをローカルにロードします。
- findClass
指定されたクラスをこのクラスローダから探します。このメソッドは、新しいクラスローダの実装の中でオーバーライドしてください。このメソッドのデフォルトの実装は、ClassNotFoundException をスローします。
- getResource
親クラスローダ (親が指定されていない場合はブートストラップクラスローダ) からリソースの取得を試みます。それでもリソースが見つからない場合は、getLocalResource メソッドを呼び出して、リソースをローカルにロードします。
- findResource
指定されたリソースをこのクラスローダから探します。このメソッドは、新しいクラスローダの実装の中でオーバーライドしてください。このメソッドのデフォルトの実装は、null を返します。
- getResources
指定されたリソース名に一致するすべてのリソースの URL を列挙したリストを返します。このリストには、親クラスローダが返したすべての一致リソースに findResources が返した列挙を続けたものが含まれます。
- findResources
指定された名前に一致する全ローカルリソースの URL を列挙したリストを返します。このメソッドは、新しいクラスローダの実装でオーバーライドしてください。このメソッドのデフォルトの実装は、null を返します。
新しい委譲モデルでは、クラスとリソースのロードのための一貫性があって良く定義された検索ポリシーが提供されており、クラスローダの実装が容易に行えるようになっています。これらの変更は下位互換性を持っており、既存のクラスローダの実装には影響しません。しかし、独自のクラスローダを作成するとともに拡張機能を利用するアプリケーションの場合は、新しい委譲モデルを使用しなければなりません。
簡単なネットワーククラスローダの例を次に示します。
public class NetClassLoader extends ClassLoader { URL url; public NetClassLoader(URL url, ClassLoader parent) { super(parent); this.url = url; } protected Class findClass(String name) throws ClassNotFoundException { .. load class from URL ... } protected URL findResource(String name) { try { URL u = new URL(url, name); if (u.openConnection() != null) { return u; } else { return null; } } catch (java.net.MalformedURLException mue) { // handle exception } catch (java.io.IOException ioe) { // handle exception } } }この例では、指定された URL をチェックする前に、クラスとリソースを親クラスローダ (親が指定されていない場合はブートストラップクラスローダ) から探します。クラスとリソースは、前述した新しい委譲モデルに従ってロードされます。
- public class java.lang.Package
このクラスには、シールされたパッケージに関する情報にアクセスするためのメソッドが 2 つ追加されています。isSealed メソッドを使用すると、パッケージがシールされているかどうかをチェックでき、シールされている場合は true が返されます。このメソッドの 2 番目の形式では、URL をとり、指定された URL についてパッケージがシールされていれば true を返します。このメソッドは、クラスローダの実装の中で使い、新しいクラスのロード時に、現在シールされているパッケージを見失うことがないようにする目的で使用できます。
- public class java.net.URLClassLoader
このクラスでは、拡張機能とアプリケーションのための基本的なクラスローダサポートが提供されています。このクラスでは、クラスとリソースの 1 つまたは複数のベース URL を検索するため、findClass メソッドと findResource メソッドがともにオーバーライドされています。URL は必要になるまで開かれないため、検索はただちに行われるわけではありません。
URLClassLoader は、クラスとリソースのロードに使われる URL の検索パスを管理します。最初、検索パスはクラスローダが作成されたときに指定された URL に設定されますが、前述したように、マニフェスト属性 Class-Path によって拡張できます。
URLClassLoader は、Java バージョン管理の仕様で規定されている、バージョン管理のためのマニフェスト属性をすべてサポートしています。
さらに、以下の主要なマニフェスト属性がサポートされています。
- Main-Class: <classname> (デフォルト値: なし)
アプリケーションのメインクラスを指定します。この属性は、アプリケーションの JAR ファイルの呼び出しに使用されます。
- Class-Path: <urls..> (デフォルト値: なし)
クラスとリソースをロードするため、JAR ファイルとディレクトリの URL のローカル検索パスを相対 URL で指定します。「/」で終わらない URL は、JAR ファイルを参照しているものと見なされます。
- Sealed: <true|false> (デフォルト値: false)
「null」パッケージを除き、この JAR ファイルで定義されているすべてのパッケージがシールされます。 「null」パッケージをシールすることはできません。このヘッダは、個々のパッケージのシールにも使用できます。
概要
バージョン 1.2 の JRE および JDK ソフトウェアでは、拡張機能を使用するスタンドアロンアプリケーションをサポートするため、java コマンドに変更が加えられました。これまでは、アプリケーションクラスはシステムクラスローダからロードされていましたが、新しい java コマンドでは、アプリケーションをロードするために URLClassLoader のインスタンスが作成されます。委譲の親は、インストール型拡張機能のロードのためシステムが管理する共用クラスローダに設定されます。使用されるアプリケーションクラスローダは、アプリケーションが使用するインストール型拡張機能とバンドル型拡張機能のどちらのロードも処理します。アプリケーションのクラスパス
アプリケーションをロードするために、URLClassLoader のインスタンスを作成するときには、使用される URL の検索パスは、java.class.path プロパティから読み出されます。このプロパティは、アプリケーションのクラスとリソースをロードするアプリケーションのクラスパスを指定するものです。クラスまたはリソースのロード時、クラスローダは最初にシステムクラスパスを探し、次にインストール型拡張機能を、最後にアプリケーションのクラスパスを探します。この変更の結果、java.class.path プロパティにはブートストラップクラスパスからのエントリは格納されないようになりました。システムクラスパスは、システムプロパティ sun.boot.class.path から別個に得られるようになりました。
環境変数 CLASSPATH は、java.class.path プロパティのデフォルト値を指定するものです。この環境変数を設定しない場合、java.class.path のデフォルト値は現在のディレクトリに設定されます。
-classpath オプションは、java.class.path プロパティを簡単に設定するための手段となっています。以前は、このオプションはシステムクラスの検索パスをオーバーライドするために使用されていました。新しい java コマンドでは、システムクラスパスを設定する必要はありません。
-cp オプション
-cp オプションは、jre コマンドでだけ使用できるオプションでしたが、java コマンドにも追加されました。ただし、新しい java コマンドではシステムクラスパスを設定する必要はないため、このオプションは単に -classpath の別名になっています。たとえば、次の 3 つのコマンドはどれも同じ意味です。
java -classpath foo.jar:bar Foo java -Djava.class.path=foo.jar:bar Foo java -cp foo.jar:bar Fooセキュリティプロパティの設定
デフォルトでは、アプリケーションはセキュリティマネージャなしで起動され、ポリシーのチェックは有効になりません。この動作は、すべてがシステムクラスパスからロードされる以前のコマンドの動作と同じです。アプリケーションの起動時にセキュリティマネージャをインストールするには、次のように、コマンド行オプション -Djava.security.manager を使用します。
java -Djava.security.manager Fooデフォルトのシステムポリシーファイルは、{java.home}/lib/security/java.policy です。{user.home}/.java.policy のポリシーファイルを使用することで、ユーザは個々にデフォルトのポリシーファイルを強化できます。デフォルトのポリシーに加えて使用するポリシーファイルを指定するには、次のようにします。
java -Djava.security.policy=somePolicy Fooポリシーファイルの詳細は、「Default Policy Implementation and Policy File Syntax」 を参照してください。
-jar オプション
JAR ファイルにまとめられたアプリケーションを簡単に実行できるように、java アプリケーション起動ツールに -jar オプションが新たに追加されました。このオプションを使用すると、JAR ファイル内のアプリケーションを java コマンドで直接実行できます。-jar オプションを使用するときは、java.class.path プロパティに実行する JAR ファイルを設定すると、これが -classpath コマンド行オプションまたは -cp コマンド行オプションで指定したほかの定義をオーバーライドします。このようにすることで、JAR ファイルのマニフェストが参照され、マニフェスト属性 Main-Class で指定されたアプリケーションのメインクラスの名前が検出されます。たとえば、server.jar のマニフェストで次のような属性が指定されているとします。
この場合、次のどちらのコマンド行でも、server.jar を実行できます。Main-Class: com.sun.server.Mainjava -jar server.jar java -Djava.class.path=server.jar com.sun.server.Main実行可能 JAR ファイル
Win32 システムでは、インストールプログラムが JAR ファイルと、デフォルトで対応付けられます。その結果として、デスクトップ上で JAR ファイルをダブルクリックするだけで java -jar により JAR ファイルが自動的に起動されます。アプリケーションにバンドルされた、アプリケーションが依存している拡張機能も自動的にロードされます。このため、Win32 システムではエンドユーザにとって JRE が使いやすくなっています。Solaris 2.6 のカーネルは、JAR ファイルを表す特別な「マジック」ナンバーを認識するようにすでに拡張が施されており、java -jar で JAR ファイルを Solaris のネイティブ実行可能ファイルであるかのように起動できるようになっています。JAR ファイルにまとめられたアプリケーションも、コマンド行から、または CDE デスクトップ上でアイコンをクリックすることで直接実行できます。
jre コマンド
JRE 1.2 では jre コマンドはなくなり、java ツールに併合されました。JRE 1.2 でも使用できる唯一の環境変数は CLASSPATH で、この環境変数は、java ツールの -classpath オプションか -cp オプションを使用してオーバーライドできるようになっています。新しい java コマンドでは、JRE のシステムクラスパスの設定に使用されていた -cp オプションは -classpath と同じ意味になりました。互換性
独自のクラスローダまたはセキュリティマネージャをインストールするアプリケーションは、バージョン 1.2 のプラットフォームに対応するようにアップデートされるまで、新しい java コマンドでは実行できない可能性があります。このようなアプリケーションは、バージョン 1.2 の JRE および JDK ソフトウェアで導入された新しいセキュリティ機能と委譲クラスローダを使用するよう、アップデートする必要があります。互換性のため、バージョン 1.1 の Java プラットフォームと同じようにシステムクラスパスからアプリケーションを実行する、旧式の起動コマンド oldjava が用意されています。しかし、oldjava コマンドでは拡張機能はサポートされていません。
Copyright © 1997, 1998
Sun Microsystems, Inc.
All Rights Reserved.
コメントの送付先: Java ソフトウェア |
|