JavaTM 製品のバージョン管理の仕様
1998 年 11 月 30 日
オープンな分散システムは、パッケージ間の多くの依存関係に基づいて的確に運用する必要があります。そのため、更新を注意深く管理する必要があります。 分散システム内の変更は、ユーザ、サポート組織、Web 管理者、および開発者を含む個々のグループに重大な影響を及ぼします。 分散システム内のパッケージの操作は、システム全体の状態に関する部分的な知識だけで正確に行う必要があります。 システムの各パッケージが更新される速度がそれぞれ異なるため、管理はそれだけ難しくなります。 オブジェクト指向の設計手法で個々のパッケージの更新を管理して、パッケージ間の依存関係を明示的に管理することにより、システムの更新が可能になります。 Java 言語は、一貫した更新単位に適したパッケージ、public インタフェースだけを公開し、かつほかのクラスの public インタフェースだけを使用するパッケージを定義します。
どのようなシステムでも、時とともに更新していくシステムにはサポートを提供する必要があります。 通常、既存のシステムには、変更の適用方法を指定する規約および機構が定められています。 これらのシステムは、ソフトウェアプログラムがコンピュータにインストールされていることを前提としています。 一般に、開発者は、必要とするほかのパッケージのバージョンを指定し、インストールプロセスは、システムの検証と設定を行います。
しかし、オープンな分散システムでは、既存システムが静的であるという仮定は当てはまりません。 パッケージが変化する方法と時期を制御することは不可能なため、その更新はさらに困難です。 正確な操作は、パッケージ間の莫大な依存関係にかかっています。 オープンで信頼性が高く、かつスケーラブルな分散システムの構築という目標を達成するには、システムパッケージの更新方法を規定する最新の規約と機構のセットが必要です。
このドキュメントでは、次の点を説明します。
- Java パッケージを構成するクラス、リソース、およびファイルのバージョンの設定方法を説明します。 パッケージは、開発、パッケージング、検証、更新、および配布が可能な一貫した単位を定義します。 パッケージごとのマニフェスト情報により、パッケージの内容を知ることができます。
- 製品は、パッケージをアーカイブファイルに収めた形式で配布されます。 アーカイブファイルには、製品のバージョンおよび含まれるパッケージを示すマニフェストが含められています。
- 開発者および管理者が使用する標準や規約について説明します。パッケージおよびそれが依存するパッケージの更新を行なっても安定して稼動する、信頼性の高い製品の構築および配置に使用されます。
分散システム内の変更は、次のグループに重大な影響を与えます。
グループごとに、更新を続けるネットワーク製品に対する異なる要件を満たさなければなりません。
エンドユーザには、時の経過とともに Java ベース製品は信頼性および互換性が向上していくという確信を与える必要があります。 ユーザがアップグレードを躊躇する場合、「Write Once, Run Anywhere」という哲学に対するユーザの確信を築くことが必要です。 Java では、「アップグレードしたらどこかに障害が生じる」とか「ほかのユーザが使用するデータを読み書きすることができなくなってしまう」という心配がないようにしなければなりません。
- ユーザは、アップグレードしても、ほかのプログラムを破壊したり、既存のデータが使えなくなったり、作成されるデータをほかのユーザが使用できないといった問題は発生しないことを理解する必要があります。
- ユーザは、基本的に、手持ちのバージョンの製品に必要な機能が組み込まれているか、特定の機能を使用するにはどのバージョンを入手する必要があるのかを知ることに関心があります。
- さらに経験を持つユーザは、特定のバージョンの製品のバグ情報を手に入れて、バグに対処したり、回避したりします。
製品サポート組織にとって、使用されている製品とその使用環境、および製品パッケージの完成度を正確にかつ容易に識別できることは非常に重要です。
- よく発生する問題およびその解決方法が格納されたデータベースは、製品 ID 情報によりインデックスが設定されています。
- 製品およびパッケージの相互運用は新種の問題を招くことがあるため、システム内のすべてのパッケージを識別しておく必要があります。 問題は、十分に仕様が定められていない public インタフェース、仕様に準拠しない実装、仕様に含まれない実装依存の部分を使用するクライアントで発生する可能性があります。
Web マスター、管理者、およびサービスプロバイダは、Web またはネットワークファイルシステムを介してクライアントにアプリケーションを配備するための、信頼性が高く、サポート可能な方法を求めています。
- サポートスタッフは、特定のパッケージの問題点およびパッケージ間の相互作用を正確に理解した上で、クライアントのサイトをサポートする必要があります。
- サイトの設定は、自動化されたサイト管理ツールによるサイトの拡張に対応可能でなければなりません。
- 更新されたパッケージのインストールにより、既存のパッケージまたはアクティブなユーザの訂正操作に問題が発生するようなことがあってはなりません。
製品開発者は、ユーザ、管理者、およびサポートスタッフの要求を満たすアプリケーションおよびライブラリの記述および配置方法を理解する必要があります。 開発者には、以下の要件を満たす製品およびパッケージの開発が求められます。
- Web のオープンかつ動的な環境で正確に動作する
- クライアントとの互換性を損なうことなくアップグレードが可能である
- 依存するパッケージがアップグレードされた場合、その機能を利用できる
- パッケージの動的拡張機能を利用できる
- 開発する製品やパッケージが依存するパッケージを特定して問題を報告できる
- ユーザ、Web マスター、およびサポート組織のニーズを満たすようにパッケージ化されている
- アプリケーションや組織に適した監査要件、セキュリティ要件を満たすパッケージとその組み合わせを理解している
オープンな分散システムでは、パッケージが拡大し、頻繁に更新される場合に、問題が発生することがあります。 public インタフェースを使用する際に、インタフェース固有の特定動作が維持されないと、予期しない方法でシステムに障害が発生する場合があります。 オープンシステムは、異なる会社や組織が作成したパッケージで構成されています。 これらの組織は、相互に連絡を取りながら運営されているわけではなく、独自のスケジュールで新製品を発表したり、アップグレードしたりします。 アップグレードされた製品の配布には時間がかかり、しかもアップグレードを採用するかどうかという問題もあります。
Java では、ローカルおよび分散システムのコンポーネントは、public インタフェースおよびほかのパッケージの動作規定に依存しています。 それぞれのパッケージは時とともに更新されます。 ほかのパッケージが依存するパッケージは、アップグレード後も期待される動作を継続して提供できなければなりません。
分散システムでは、システム全体の状態を把握することはできないため、部分的に整合性を保つことしかできません。 システムの各プロセスおよび各パッケージは、システムの現在の状態を部分的にしか見ておらず、分散システムのほかの部分に情報を要求することにより情報を蓄積していきます。 情報の断片は、それが起動したアプレット、ロードされたクラス、呼び出されたリモートメソッド、または取得された Web ページのどれからであっても、すでに得ているシステムの情報と一貫性を保って使用できるように、注意深く扱う必要があります。
ロードされたクラス内の不一致により、次のようなエラーが発生する可能性があります。 クラスの検証ができない、行われた不正なクラス計算を認識できない、ユーザが要求した機能が特定不能な障害を示すなどです。
これらの問題は、一般的に次の状況で発生することがあります。
- Web サーバの新しいバージョンへの更新時に、実行中のアプレットがクラスの一部だけをロードした場合。 アプレットがほかのクラスをロードすると、新たにロードされたクラスは、すでにロードされているクラスと整合性を保てなくなることがある
- 複数の Web サイトからのライブラリを使用するアプリケーションが、必要とする一部のクラスだけをロードした場合。ライブラリが更新されると、互換性を保てなくなることがある。 互換性が保てなくなると、アプレットまたはユーザのどちらかによる検出が必要になる
- 実行中のアプリケーションまたはアプレットが RMI 呼び出しを行ない、クラスをロードする必要のあるオブジェクトが返される場合。 ロードされるクラスは、すでにロードされたクラスと整合性を保てないことがある
- 実行中のアプリケーションまたはアプレットが RMI 呼び出しを行ない、より新しいまたはより古いバージョンのクラスに対応したオブジェクトが返されることがある
- ライブラリにバグが存在する場合。 クライアントの側でバグに対処してきた場合には、バグの修正時に問題が連鎖的に発生することがある
これらの問題は、動的にロードされたパッケージ間の非整合性から発生するため、予防したり、直接解決することはできません。これらのパッケージは 1 人のシステム管理者の管理下にあるわけではないため、現在の設定管理技術では特定することができません。
これらの問題に対処し、前述の要件を満たす鍵となるのは、パッケージおよびシステムのパッケージ化を注意深く設計し、一貫した単位ごとの更新、配布、およびロードを可能にすることです。 大量生産される製品で一般的なのは、現場での交換が可能な単位という概念です。 これは製品の最小単位で、仕様およびサプライヤによって識別されます。また配布、再配布、および障害がある場合には交換も可能です。 同様のモデルは、ソフトウェアの配布に利用されています。製品には名前やバージョン番号があり、1 つまたは複数の仕様に準拠し、ネットワークまたは CD-ROM によって配布されます。また問題点もサポート組織に報告することができます。 これらのパッケージは、配布、使用、検査、置換、また必要な場合にはアップグレードが可能な最小単位です。 パッケージはほかのパッケージと組み合わせることができますが、そのあともパッケージごとに識別、検証、および配布が可能です。
Java 言語ベースのパッケージ機構は、置き換え可能な単位という考え方とよく適合します。 Java パッケージは、public インタフェースだけを公開し、ほかのパッケージの public インタフェースだけを使用します。 JavaTM 言語仕様は、互換性を維持しつつ更新されるパッケージへのアプローチを定義しています。
Java 言語仕様は、適正な更新が期待されるパッケージ開発の基礎となります。 以前にコンパイルおよび配布したクラスと下位互換を保ちながら、クラスがどのように変化できるのかを定義するからです。 健全な更新にとって重要なのは、public、protected、および package インタフェースの安定性と、実装更新時の動作です。 Java 言語仕様では、「互換性」のある変化を「既存のインタフェースまたは動作を変更しない変化」と定義しています。 それで、あるクラスがメソッドを定義し、そのメソッドが特定の動作をする場合、同じ規約がクラスのそのあとのバージョンすべてでサポートされなければなりません。 詳細については、「JavaTM Language Specification」の第 13 章を参照してください。 ここでは、互換性のない変更が 1 つ追加されています。 public インタフェースへのメソッドの追加は、互換性がありません。
互換性のない変更は許可されませんが、新規または類似の機能はいつでも、新規または既存のインタフェースやクラスに追加できます。
Java パッケージを更新単位として選択することにより、パッケージおよびクラスのプライベートメソッドで変更できます。これにより、public および protected クラスとメソッドに外部インタフェースおよびセマンティクスを保ちつつ、パッケージの実装に柔軟性を持たせることができます。
コンポーネント間の記憶領域保持機能および通信機能が強力であることは、分散システムにとって重要です。 クラスを拡張しつつ記憶領域中の以前のデータをクラスが読めるようにするには、持続的な記憶領域を維持しつつコンポーネントを更新しなければなりません。 分散システムでは、各コンポーネントの更新速度はそれぞれ異なりますが、コンポーネント間の通信の信頼性は維持しなくてはなりません。
オブジェクトを直列化する際、互換性に関する要件に従うことにより、より新しいまたはより古いバージョンのオブジェクトが一般的かつ一貫した方法で通信することが可能になります。 詳細については、「JavaTM オブジェクト直列化仕様」の第 5 章を参照してください。
確認の必要な作成物のカテゴリがいくつかあり、それには仕様、実装、Java 仮想マシン、および Java Runtime Environment が含まれます。
オープンシステムは、仕様には複数の実装が含まれるという考えに基づいています。 仕様は、組織や企業の援助のもとに更新されます。 仕様に互換性のない複数のバージョンが含まれるというのは、望ましいことではありません。 仕様または実装の各バージョンは、単一の次期バージョンにだけ更新しなければなりません。 仕様に下位互換性を要求する考え方では、仕様を以前の仕様のスーパーセットとみなすことができます。 バージョンの配列順序は 1 通りしかないため、特定のバージョン番号は特定の仕様を意味するセマンティクスを備えています。 仕様のバージョン番号には、ピリオドで区切られた数字で構成されるデューイ 10 進数表記法が使用されます。
仕様は、次の項目で識別できます。
- 仕様の所有者
- 仕様の名称
- バージョン番号 - メジャー番号.マイナー番号.マイクロ番号
メジャーバージョン番号は、重要な機能変更を示します。
マイナーバージョン番号は、機能の小規模な拡張を示します。
マイクロバージョンは、バージョンをさらに細かく分類したものです。
続くバージョン番号には、現在のバージョンより大きな数字が使用され、仕様の追加が行われたことを示します。
Java 仮想マシンの実装は、仕様と実装の両方から識別する必要があります。 これらのプロパティは、java.lang.System.getProperties を使用してすでに利用可能なものに追加する必要があります。
java.vm.specification.version
例 1.3 java.vm.specification.vendor
例 Sun Microsystems Inc. java.vm.specification.name
例 JavaTM Virtual Machine Specification java.vm.version
例 Solaris 5.5 Native 1.0 build32 java.vm.vendor
例 Sun Microsystems Inc. java.vm.name
例 Solaris 5.x JVM これらのプロパティへは、java.lang.System.getProperty メソッドを使用してアクセスします。その結果、文字列が返されます。
JavaTM Runtime の識別に必要な情報は、すでに 「JavaTM Language Specification」の 20.18.7 で指定されたプロパティにより、java.lang.System.getProperties を使用して部分的に取得されています。
java.version
例 Solaris 1.3 java.vendor
例 Sun Microsystems Inc. 現時点では、これらのプロパティは、JavaTM Runtime の実装および利用可能なコアクラスを識別します。 これらのプロパティは、この JDKTM が実装する JavaTM 言語仕様を識別しません。
この実装が準拠する JavaTM Runtime Environment 仕様のバージョンの識別に必要なプロパティは、次のとおりです。
java.specification.version
例 1.1 java.specification.name
例 JavaTM Language Specification java.specification.vendor
例 Sun Microsystems Inc. これらのプロパティには、
java.lang.System.getProperty
メソッドを使用してアクセスできます。結果として、値が文字列で返されます。
各 JavaTM パッケージは、クラスファイルおよびオプションのリソースファイルで構成されます。 パッケージの中身を識別するために必要な情報も、パッケージの中に格納されています。
この仕様は、パッケージが JavaTM Runtime とともに配布される主要パッケージとして開発されたか、標準拡張として開発されたか、アプレットまたはアプリケーションパッケージとして開発されたかに関係なく、すべてのパッケージに適用されます。
仕様のバージョン番号と異なり、実装のバージョン情報は、パッケージに以前のバージョンと下位互換性があることを示すものではありません。 パッケージのバージョン番号は、バグなどの仕様と実装の相違を識別するためのものです。 実装の新バージョンは、望ましくない動作または不正確な動作を取り除くために作成されるもので、下位互換性を意図したものではありません。 パッケージのバージョンを示す文字列は、任意の固有値を持ち得るため、等価かどうかの比較だけが可能です。 詳細については、「実装のバージョン番号を識別用に限定する理由」を参照してください。
次の属性名は、パッケージごとに定義されます。 それぞれの属性の値は、文字列です。
Implementation-Title パッケージのタイトル Implementation-Version バージョン番号 Implementation-Vendor ベンダー企業または組織 Specification-Title 仕様のタイトル Specification-Version バージョン番号 Specification-Vendor ベンダー企業または組織
これらの属性は、マニフェストに保存され、次で説明する
java.lang.Package
API を使用したプログラムにより取得できます。JAR マニフェストフォーマット
現在のマニフェストフォーマットは拡張され、パッケージのバージョン情報属性の仕様に対応しました。 マニフェストエントリは、JavaTM パッケージごとに作成する必要があります。 エントリ名は、パッケージのクラスおよびリソースファイルを格納するアーカイブ内のディレクトリ名になります。 例を示します。
Manifest-version: 1.0 Name: java/util/ Specification-Title: Java Utility Classes Specification-Version: 1.3 Specification-Vendor: Sun Microsystems Inc. Implementation-Title: java.util Implementation-Version: build57" Implementation-Vendor: SunMicrosystems. Inc.マニフェストにこれらの属性を挿入するには、マニフェストファイルのプロトタイプを作成し、jar ツールの -m スイッチを使用して、マニフェストの構築時に属性をマニフェストにマージします。 今後、jar ツールはマニフェスト中でバージョン属性をブラウズおよび設定できるように拡張される予定です。
Java Plug-in 製品が Jar ファイルにアクセスするときに使用するマニフェスト情報については、「Java Plug-in 開発者ガイド」の「Java 拡張機能の配備」を参照してください。
ユーザは、バグの発生時に、使用中のパッケージの ID をレポートしなければなりません。 アプリケーション、アプレット、またはブラウザは、ユーザから要求されたときまたはエラーが発生したときに、入手可能な情報をユーザに公開しなければなりません。 利用可能な API により、次の情報がレポート可能です。
- どのパッケージがロードされたか
package.getPackages メソッドは、アクティブなパッケージの一覧を返します。
- パッケージのバージョンは何か
java.lang.Package メソッドを使用すると、パッケージのバージョン管理に一覧表示されている名前とバージョンの属性を調べることができます。
- JavaTM Runtime のどのバージョンがアクティブか
System.getProperties メソッドを使用すると、 Java Runtime のバージョン ID に一覧表示されている仮想マシンのプロパティを取得できます。
- どのバージョンの JavaTM VM がアクティブか
System.getProperties メソッドを使用すると、仮想マシンのバージョンに一覧表示されている 仮想マシンのプロパティを取得できます。
実装はそれぞれ独自に、バグの修正、パフォーマンスの向上、または仕様の最新リビジョンで規定された新機能の追加を目的として更新されます。 パッケージは、仕様を実装すると同時に、どのバージョンの仕様を実装したかを識別する必要があります。 パッケージ間のやり取りは、public および protected インタフェースおよびクラス経由でだけ行われます。 public API および動作は、時間が経過しても安定している必要があります。そのため、あるパッケージの実装の変更が、別のパッケージの動作に影響を与えないように注意する必要があります。
パッケージのクラスが常に仕様を忠実に実装している場合には、仕様を識別するだけで十分です。 しかし現実にはこのようなことはまれなので、バグに関係している可能性のあるパッケージが報告されるために、パッケージは自らの身分を明らかにする必要があります。
実装のバージョン識別子に何らかの意味を持たせるのには、重要な目的があります。 バグを追跡するのが目的である場合、固有の番号を付ければ十分目的を果たすことができます。 また、クライアントのパッケージがベンダーのパッケージの特定のバージョンに含まれるバグを回避する場合にも、固有の番号を付けると効果的です。該当する番号のバージョンをテストし、バグを回避できるからです。
ただし、1 つのパッケージがほかのパッケージに含まれるバグを回避しようとすると、多くの付加的な問題が発生することがあります。 ほかのパッケージは、仕様の一部ではない動作を識別する必要があり、実装にだけ属する動作を使用しようとするかもしれません。 そのような実装固有の動作は、開発者によって確認およびテストされた特定のバージョンでない限り、信用することはできません。
ベンダーパッケージのあるバージョンで初めて発生したバグは、次のバージョンでも障害になる場合と、ならない場合とがあります。 バグを含むパッケージのクライアントが、バージョン番号に基づくバグの回避を行うと、特定のバージョンのバグを正しく回避できる場合があります。 バグを含むパッケージが修正された場合、クライアントパッケージはバグが修正されたかどうかをどのようにして知ることができるのでしょうか。 あとのバージョンにもバグが含まれていると仮定した場合、クライアントは依然としてバグを回避する処置をとらなければなりません。 バグを含まないパッケージでは、バグの回避そのものが正しく機能しない可能性があります。 このため、バグの修正により一連のバグが発生する可能性があります。 新しいバージョンをテストすることにより、バグの回避が必要か、あるいはバグの回避が正常に動作しているパッケージに問題を発生させることになるのかを見極めることができるのは、開発者だけです。 また、あるバージョンにバグが存在することを知っているのは、開発者だけです。
Copyright © 1998 Sun Microsystems, Inc. All Rights Reserved.