Microsoft VM と Java 2 アプレットの互換性問題


この付録では、Microsoft VM (仮想マシン) と Sun の Java 2 VM のアプレットの互換性に関する既知の問題について説明します。

ClassFormatError

この問題は、古い JDK 1.0.2 または 1.1 コンパイラによって生成されたバイトコードが原因で発生します。このバイトコードが Java VM 仕様に準拠していないからです。 最近の J2SE リリースのべリファイアは不正なクラスフォーマットに関して非常に厳しくなっているため、こうした不正なクラスファイルがロードされたら VM によって ClassFormatError がスローされます。

不正なクラスファイル形式をもついくつかのアプレットを Java 2 で実行できるようにするために、Java Plug-in には、不正なクラスファイルを正しいものに変換するバイトコード変換プログラムが取り入れられています。 現時点では、以下の ClassFormatError による不正なクラスファイルだけが変換されます。

残念ながら以下の ClassFormatError は、バイトコード変換プログラムでは修正されません。したがって、これらの既知の問題を抱えるクラスファイルはどれも Java 2 では実行されません。

sun.audio によるセキュリティ例外

JDK 1.1 のアプレットでは sun.audio パッケージにアクセスできました。 しかし、Java 2 ではアプレットサンドボックスが閉じられたため、sun.audio パッケージのクラスライブラリにアクセスしようとしたアプレットは SecurityException になります。

アプレットの互換性を最大限にするため、Java Plug-in ではアプレットサンドボックスが開けられ、アプレットが再び sun.audio パッケージにアクセスできるようになりました。

AppletContext.getAudioClip() および AppletContext.getImage() のリソースが検索できない

Microsoft による実装と Sun による実装では、AppletContext.getImage() および AppletContext.getAudioClip() のリソースルックアップシーケンスが異なっています。

Microsoft VM では、リソースは以下の順序で検索されます。

  1. HTML の archive または cabbase パラメータで指定されたアーカイブ
  2. codebase の URL

Sun による実装では、リソースは codebase の URL に基づいて検索されます。

この結果、Microsoft VM のリソースルックアップシーケンスに依存したアプレットの中には、Java 2 ではリソースを正しくロードできないものもあります。

アプレットの互換性を最大限にするため、Java Plug-in ではリソースルックアップシーケンスが以下のように変更されました。

  1. HTML の archive パラメータで指定されたアーカイブ
  2. codebase の URL

ClassLoader 共有ポリシー

ClassLoader 共有ポリシーは、Microsoft による実装と Sun による実装で異なっています。

Microsoft VM では、以下のすべてに当てはまる場合だけ ClassLoader オブジェクトがアプレット間で共有されます。

Sun による実装では、以下の場合だけ ClassLoader オブジェクトがアプレット間で共有されます。

Microsoft VM の共有ポリシーに依存するアプレットの中には、潜在的なクラス定義の競合のために Java 2 では正しく実行されないものもあります。

アプレットの互換性を最大限にするため、Java Plug-in では ClassLoader 共有ポリシーが以下の要件に変更されました。

セキュリティモデル - Java 2 と Microsoft

Java 2 の備えている新しいセキュリティモデルは、JDK 1.1 よりもはるかにすぐれた機能と柔軟性を提供しています。 Microsoft VM セキュリティモデルは、JDK 1.1 と独自の技術に基づいています。

この問題は解決不能であるため、Microsoft のセキュリティモデルに依存したアプレットは Java 2 では正しく実行されません。

アプレットのパッケージ化

Java 2 および JDK 1.1 におけるアプレットのパッケージ化は、.jar ファイルを通じて実行されます。 しかし、Microsoft VM ではアプレットのパッケージ化が、.jar ファイルおよび独自の .cab (cabinet) ファイルを通じてサポートされています。

この問題は解決不能であるため、Microsoft の .cab ファイル形式でパッケージ化されたアプレットは Java 2 にロードされません。

Java 言語仕様の厳密さ (null と長さゼロの String)

JDK 1.1 では、クラスライブラリにおける null と長さがゼロの文字列の取り扱いに関する Java 言語仕様が緩やかでした。 API によっては null を、長さゼロの String として扱うものもあれば、null そのものとして扱うものもありました。 Java 2 では Java 言語仕様が厳密になり、正確な動作を指定するようになりました。

この問題は解決不能であるため、null を長さゼロの String として処理する API に依存しているアプレットは、Java 2 では例外となります。

アプレット署名 - RSA と Authenticode

Java 2 では、アプレット署名を RSA および .jar ファイルを通じてサポートしていますが、Microsoft ではアプレット署名を、独自の Authenticode および .cab テクノロジを通じてサポートしています。

この問題は解決不能であるため、Microsoft の Authenticode および .cab テクノロジに依存する署名アプレットは、java 2 では正しくロードされません。

AWT クラスライブラリにおける実装の変更

JDK 1.1 では、AWT クラスライブラリが開発者によって、スレッドに対して安全なライブラリとして使用されていました。つまり、アプレットは複数のスレッドで AWT を通じて多くのアクションを実行し、クラスライブラリが同期化の問題を処理するものと見なしていました。 Java 2 では AWT クラスライブラリの実装が変更され、AWT イベントディスパッチスレッドによって呼び出された場合だけスレッドの安全性が保証されるようになりました。

この問題は解決不能であるため、スレッドの安全性に関する問題を配慮せずに AWT クラスライブラリを呼び出した Java 2 のアプレットは、デッドロックまたは競合状態に陥ります。

Java と javaScript の間の通信

Microsoft による実装では、HTML ページの JavaScript で公開されるアプレットのメソッドとプロパティは、アプレットオブジェクトのメソッド/フィールドとまったく同じものです。 Java Plug-in では、HTML の JavaScript で公開されるアプレットのメソッドとプロパティは、JavaBeans のイントロスペクションを通じて取得されます。JavaBeans のイントロスペクションは、アプレットオブジェクトの命名規則によってメソッドとプロパティの分析を行います。 これによる影響として、アプレットのフィールドがそれぞれ異なる方法で処理されます。

この問題は Java Plug-in の今後のリリースで解決される予定です。現在のところ、Java 2 ではアプレットオブジェクトのフィールドにアクセスする JavaScript は正しく動作しません。

Microsoft 独自の Java クラスライブラリ

Microsoft による VM の実装では、J/Direct、AFC、WFC など多くの独自のクラスライブラリが提供されています。

この問題は解決不能であるため、Microsoft の独自の Java クラスライブラリに依存したアプレットは Java 2 では正しく動作しません。

Applet.getParameter() から返される文字列内の空白文字

Microsoft による実装では、文字列が Applet.getParameter() 内でアプレットに返される前に、空白文字が取り除かれます。 しかし、Sun による実装では、文字列は HTML パラメータで指定されたとおりに返されます。 この結果、JDK 1.1 アプレットの中には Java 2 で実行できないものがあります。JDK 1.1 アプレットのロジックでは、空白を想定していないためです。

アプレットの互換性を最大限にするため、Java Plug-in では Applet.getParameter() の実装が変更され、戻り値から空白文字が取り除かれています。

java.util.Hashtable.hashCode() における設計変更

JDK 1.1 では Hashtable.hashCode() はオブジェクト ID に基づいて実装されているので、hashCode() が呼び出された場合、Hashtable オブジェクトはそれぞれ一意の値を返します。 Java 2 では Hashtable.hashCode() の実装が、Java Collection Framework の一部として値に基づくものに変更されました。 Hashtable オブジェクトは、格納しているオブジェクトに基づいてハッシュコードの値を返します。

この変更によって、JDK 1.1 のアプレットのいくつかは、Hashtable オブジェクトをそれ自身に追加した場合に中断してしまいます。なぜなら、この変更は Collection Framework の基本設計を乱し、StackOverflowError が発生するからです。 同じ Hashtable オブジェクトから一定の値を返すために、Hashtable.hashCode() に依存しているいくつかのアプレットで、コードのロジックが破壊されてしまいます。

アプレットの互換性を最大限にするため、Hashtable.hashCode() の実装が変更され、こうした特別なケースをチェックしてスタックのオーバーフローを回避するようになりました。

アプレットからフレームへのアクセス

マウスイベントの追跡やその他の理由により、アプレットがそのフレームにアクセスしようとすることがあります。 Microsoft による実装と Sun による実装では、フレームとアプレットの間でコンテナ数が異なります。

Microsoft VM における特定の包含レベルにあるフレームの位置に依存する (AWT 階層コンポーネントツリー全体をナビゲートしない) アプレットは、Java 2 では失敗する可能性があります。最もよく見られる症状は、AWT ディスパッチイベントスレッドからの ClassCastException です。

この問題は解決不能であるため、この問題の影響下にあるアプレットは Java 2 では正しく実行されません。

MAYSCRIPT

Netscape Navigator と Java Plug-in では、JavaScript にアクセスするアプレットはアプレットタグで MAYSCRIPT パラメータを指定する必要があります。 しかし Microsoft による実装ではこのパラメータが重視されないため、アプレットはあらゆる条件下で JavaScript にアクセスすることができます。 インターネット上のアプレットのほとんどは、Microsoft VM をターゲットにしているため、MAYSCRIPT が指定されていません。

アプレットの互換性を最大限にするため、Java Plug-in から MAYSCRIPT のチェックが削除されました。

HTTP ユーザエージェント

Microsoft と Sun による実装では、HTTP 接続が要求されたときに、異なる HTTP ユーザエージェントの文字列がサーバに渡されます。 多くの Web サイトが Sun ではなく Microsoft VM をターゲットにしているため、こうした Web サイトでは Sun の HTTP ユーザエージェントを認識せず、失敗が起こります。

この結果、Java Plug-in で使用される HTTP ユーザエージェントがブラウザで使用されるものと同じものに変更されました。これで、Web サーバのほとんどが、Java Plug-in で実行するアプレットによって作成された要求を認識するようになります。

アプレットの起動および停止時のイベント

Microsoft と Sun による実装では、アプレットの起動時と停止時に発生するイベントは完全に同じではありません。 たとえば、アプレットのロジックが Applet.start() または Applet.stop() の呼び出し時に表示されるアプレットに依存することは、Microsoft による実装には当てはまりますが、Sun による実装には当てはまりません。

Microsoft VM においてアプレットが起動または停止するときの特定のイベントに依存しているアプレットは、Java 2 では正しく機能しません。最もよく見られる症状は、AWT ディスパッチイベントスレッドからの NullPointerException です。

この問題は解決不能です。

Java クラスライブラリの互換性

Java 2 の Java クラスライブラリでは多くの変更が行われました。API の中には実装において明確になったもの、切り下げられたもの、置き換えられたものがあります。 以下は、Microsoft の VM で実行されるアプレットが Java 2 では失敗することの原因となっているものです。

java.awt.Graphics.drawString()

Microsoft VM では、drawString()null を空の文字列として扱います。 Java 2 では、drawString()null をそのものとして扱うため、NullPointerException がスローされます。

java.awt.Graphics.drawImage()

Microsoft VM では、drawImage() null イメージを無視します。 Java 2 では、drawImage()null をそのものとして扱うため、NullPointerException がスローされます。

java.awt.Color コンストラクタ

Microsoft VM では、Color コンストラクタに境界値を上回ったり下回ったりする値が渡された場合、コンソールで警告メッセージが出力されますが、値は最大値または最小値に自動的にリセットされます。 Java 2 では Color コンストラクタが不正な値をチェックし、IllegalArgumentException をスローします。

Thread.stop()Thread.suspend()Thread.resume()

Microsoft VM では、デッドスレッドの停止、中断、再開に関する呼び出しは無視されます。 Java 2 では、デッドスレッド上でこうしたメソッドを呼び出すと AccessControlException が発生します。

これらの問題はすべて解決可能ですが、まだ解決されていません。 現時点では、これらの問題の影響下にあるアプレットは例外となり、Java 2 では正しく実行されません。