Eclipse 3.1 と 3.2 との非互換性

Eclipse の変更に伴い、3.1 と 3.2 との間の互換性が変更されたため、プラグインはその影響を受けます。以下の項目で、変更された領域、および 3.1 のプラグインを 3.2 にマイグレーションする手順について説明します。3.1 のプラグインを 3.2 で実行していて問題が生じた場合は、ここを調べるだけで十分です。

  1. リソースは、ローカル・ファイル・システム内で必要ではなくなりました
  2. MultiPageEditorSite に対する API の変更
  3. config.ini の内容の変更
  4. jnlp デプロイ済みアプリケーションの内容の変更
  5. Bundle.start() の明示的な呼び出しは、次の再始動時のバンドルの活動化を強制します
  6. プラグインのバージョン番号内の下線は、ハイフンに置換されなくなりました

1. リソースは、ローカル・ファイル・システム内で必要ではなくなりました

影響を受けるもの: リソースがローカル・ファイル・システム内で保管されたことを前提とする IWorkspace API のクライアント。

説明: Eclipse 3.2 より前では、各既存の IResource は、java.io.File によってアクセス可能なファイル・システム内に、対応するファイルまたはディレクトリーを持っていました。 Eclipse 3.2 では、任意のバッキング・ファイル・システム内にそのコンテンツを保管するリソースを作成するためのサポートが追加されました。このサポートを使用するリソースは、java.io.File として直接表すことができなくなりました。

必要なアクション: 古いメソッド IResource.getLocation() は、リソースのローカル・ファイル・システム・パスを戻します。このメソッドは、ローカル・ファイル・システム内に保管されていないリソースに対して、NULL を戻します。 getLocation() のほとんどの呼び出し元は、ローカル・ファイル・システム内に保管されていないリソースに対して使用されなくなった java.io.File のインスタンスを獲得するために、このようにしていました。

新規の org.eclipse.core.filesystem プラグインは、java.io.File の代わりに使用できる汎用ファイル・システム API を提供します。 特に、org.eclipse.core.filesystem.IFileStore のインスタンスは、java.io.File 上で使用可能なメソッドと同じメソッドのほとんどを提供します。以下のコードのスニペットは、指定されたリソースの IFileStore のインスタンスを獲得します。

   IResource resource = ...;//some resource
   IFileStore store = EFS.getStore(resource.getLocationURI());

以下のテーブルは、通常 java.io.File で行われる操作のために、IFileStore で同等のメソッドを提供します。

java.io.FileIFileStore
deletedelete
getNamegetName
getParentgetParent
list childNames
mkdirmkdir(EFS.SHALLOW, null)
mkdirsmkdir(EFS.NONE, null)
renameTomove
new FileInputStream(file)openInputStream
new FileOutputStream(file)openOutputStream

IFileStore API 内では、ファイルに関するほとんどの情報は、IFileStore.fetchInfo() を呼び出すことによって獲得される IFileInfo と呼ばれる構造内に保管されます。ファイルについての多くの属性は単一のファイル・システム・コールで獲得できることが多いので、この設計によって、java.io.File を使用するコードを大幅に最適化させることが可能になります。基礎ファイルが変更された場合、IFileInfo 内の情報は失効するため、インスタンスは必要がある間のみ保持されなければならないことに注意してください。以下に示すのは、IFileInfo 上に同等のメソッドがある、java.io.File 上のいくつかのメソッドです。

java.io.FileIFileInfo
canWriteisReadOnly
exists exists
getNamegetName
isDirectoryisDirectory
isFile!isDirectory()
isHiddenisHidden
lastModifiedgetLastModified
lengthgetLength
setLastModifiedsetLastModified
setReadOnlysetAttribute(EFS.ATTRIBUTE_READ_ONLY, true)

具体的な例として、以前は java.io.File.exists() を呼び出していたコードが、今は IFileStore.fetchInfo().exists() を呼び出すことができます。 IFileInfo が変更された場合は、結果は IFileStore.putInfo メソッドを使用して、保管し戻される必要があります。例えば、このスニペットはファイル上の読み取り専用属性を切り替えます。

   IFileStore store = ...;//some file store
   IFileInfo info = store.fetchInfo();
   boolean readOnly = info.getAttribute(EFS.ATTRIBUTE_READ_ONLY);
   info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, !readOnly);
   store.putInfo(info, EFS.SET_ATTRIBUTES, null);

IProjectDescription.getLocation()

getLocation() メソッドと同様に、プロジェクト記述のロケーションはローカル・ファイル・システム内ではなくなっている可能性があります。メソッド IProjectDescription.getLocationURI() が、任意のファイル・システム内でリソースのロケーションを獲得するために使用できます。

ローカル・キャッシング

ファイルのローカル表記を絶対に持たなければならないクライアントもあります。例えば、そのファイルに対してネイティブ・ツールを起動する場合、またはファイル・システム・リソースのみを取り扱う Eclipse 認識ではないライブラリー (java.util.zip.ZipFile など) を使用する場合などがあります。これらの場合、そのコンテンツのキャッシュ・ローカル・コピーを戻すように、IFileStore に求めることができます。

   IFileStore store = ...;//some file store
   //see if it can directly be represented as a local file
   java.io.File local = store.toLocalFile(EFS.NONE, null);
   //if not, ask for a cached local copy of the file
   if (local == null)
      local = store.toLocalFile(EFS.CACHE, null);

いったんファイルのキャッシュ・コピーが獲得されると、そのコピーは、それが得られた実際のファイル・システムと同期を取らなくなっていることに注意してください。キャッシュ・コピーの変更は、基礎となるファイルが変更される原因とはなりません。

安全な失敗

ローカル・ファイル・システムの外部にあるリソースを取り扱えないクライアントが、より安全に失敗するためにコードを適応しようとする場合があります。クライアントはリソースがローカル・ファイル・システムにあるかどうかをチェックして、取り扱えないリソースを検出したときに、リソースを無視するかまたはユーザーに警報することができます。リソースがローカル・ファイル・システムにあるかどうかを判別するには、そのファイル・システム・スキーム を検出することが必要です。これはリソースから、以下のように獲得できます。

   IResource resource = ...;//some resource
   URI uri = resource.getLocationURI();
   if (uri != null && EFS.SCHEME_LOCAL.equals(uri.getScheme())) {
      //file is in local file system
   } else {
      //file is not in the local file system
   }

IFileStore インスタンスを持っている場合は、以下のようにスキームを獲得することができます。

   IFileStore store = ...;//a file store
   store.getFileSystem().getScheme();

2. MultiPageEditorSite に対する API の変更

影響を受けるもの: MultiPageEditorSite.progressStart() または MultiPageEditorSite.progressEnd() を呼び出すクライアント。

説明: Eclipse 3.0 の開発中に、これらのメソッドは進行サポートの作業の一部として追加されていました。 3.0 より前のリリースでは、進行が取り扱われる方法は変更され、このメソッドは必要ではなくなりました。プログラマーのエラーのために、これらの public メソッドは 3.0 リリースに残りました。以下の 2 つのメソッドは、Eclipse リリース内ではどのような機能も提供したことがありません。従って削除されました。

必要なアクション: MultiPageEditorSite.progressStart() または MultiPageEditorSite.progressEnd() を呼び出すクライアントは、代わりに IWorkbenchSiteProgressService を使用するように切り替える必要があります。

3. config.ini の内容の変更

影響を受けるもの: カスタム config.ini があり、アプリケーションが 3.2 に移行されたクライアント。

説明: 3.2 より前は、config.ini に含まれている osgi.bundles の標準的な値は org.eclipse.core.runtime@2:start, org.eclipse.update.configurator@3:start でした。 実行時リファクタリングが原因で、アプリケーションを正常に始動するには、この値を更新する必要があります。

必要なアクション: osgi.bundles の値を、org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@3:start, org.eclipse.core.runtime@start が組み込まれるように変更します。

4. jnlp デプロイ済みアプリケーションの内容の変更

影響を受けるもの: RCP アプリケーションをデプロイし、値 osgi.bundles を指定したクライアント。

説明: 3.2 より前は、主な jnlp ファイルに含まれている osgi.bundles の標準的な値は org.eclipse.core.runtime@2:start, org.eclipse.update.configurator@3:start でした。 実行時リファクタリングが原因で、この値を更新しないと NullPointerException がスローされ、アプリケーションの始動を妨げる場合があります。

必要なアクション: osgi.bundles の値を、org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@3:start, org.eclipse.core.runtime@start が組み込まれるように変更します。

5. Bundle.start() の明示的な呼び出しは、次の再始動時のバンドルの活動化を強制します

影響を受けるもの: Bundle.start() を呼び出すクライアント。

説明: Eclipse では、Eclipse-LazyStart ヘッダー (または推奨されない Eclipse-AutoStart ヘッダー) を使用してバンドルを遅延開始バンドルに指定します。Eclipse 3.1 では、メソッド org.osgi.framework.Bundle.start() は遅延開始バンドルに永続的開始のマークを付けません。遅延開始バンドルは永続的開始のマークを得られないため、Eclipse の再始動時に自動的に開始されません。 Bundle.start() の javadoc には、メソッドの呼び出し時に以下が発生することが明記されています。

"このバンドルが開始したことを永続的に記録します。フレームワークが再始動した場合、このバンドルは自動的に開始されます。"

Eclipse 3.2 では、バンドルが遅延開始バンドルの場合でも、永続的開始のマークが正しく付けられるように Bundle.start() メソッドが修正されました。この修正は、OSGi フレームワークの仕様に準拠する必要がありました。その結果、Bundle.start() の呼び出し元は Eclipse の再始動時にバンドルの開始を強制します。Eclipse が再始動される度に不要なバンドルが活動化されるため、この方法は一般的には不適切な動作と考えられています。一部のケースでは、これが原因でバグ 134412 などの予期しない結果が引き起こされる場合があります。

必要なアクション: 再始動の度にバンドルを永続的に活動化するかどうかを、Bundle.start() のクライアントが評価する必要があります。活動化しない場合、クライアントはバンドルを活動化する別の方法を探す必要があります。ほとんどの場合、Bundle.start() の呼び出しは、クラスがターゲットのバンドルからロードされるときにゆるやかにそのバンドルを活動化することを許可するだけで、簡単に防ぐことができます。遅延開始バンドルの積極的な活動化を必要とするシナリオも稀にありますが、再始動時の活動化の永続的なマークは付けられません。こうしたシナリオでは、Bundle.start() の呼び出しではなく Bundle.loadClass() を使用して、活動化の必要なバンドルからクラスをロードします。

5. プラグインのバージョン番号内の下線は、ハイフンに置換されなくなりました

Eclipse 3.0 では、バージョン ID の修飾子セグメントにおける下線文字 ('_') の使用はサポートされていませんでしたが、強制もされていませんでした。プラグイン・バージョン ID の修飾子に下線が含まれている場合、この文字は、プラグインをファイル・システムにエクスポートする際、および更新サイトからプラグインをインストールする際に、ハイフン ('-') に変換されていました。
Eclipse 3.1 では、修飾子に使用できる文字の規則が緩和され、下線文字も含まれるようになったため、問題のプラグインのエクスポート時やインストール時にも、修飾子は元の状態から変更されなくなりました。この小さな変更点が、誤って 3.0 から 3.1 へのマイグレーション・ガイドに記載されていませんでした。さらに進んで Eclipse 3.2 では、Eclipse 3.1 およびバージョン修飾子に下線文字を使用しているプラグインとの互換性を維持しているため、古いバージョンのプラグインを使用する場合には、前述の変更について承知しておく必要があります (エクスポート時、および更新サイトに古いバージョンのプラグインが存在する場合)。つまり、例えば、更新サイトに古いバージョンのプラグインを置いているプラグイン・プロバイダーは、ファイル・システムの名前がプラグインの名前と必ず一致するようにする必要があります。