レベル: 中級 Robert Weisz, Advisory Software Engineer, IBM Toronto Lab
2009年 03月 24日 この記事では、Eclipse プラットフォーム上に構築されている IBM Rational® Application Developer の中でカスタムの Ant タスクを作成する方法を説明します。また、なぜその必要があるかについても説明します。この記事で紹介する例では、現在 IDE (Integrated Development Environment: 統合開発環境) では提供されていない便利な機能として、カスタムの Ant タスクを作成する機能を提供します。この Ant タスクを使うと、派生ファイルに分類されるすべての生成ファイルを削除することができます。
はじめに
IBM Rational® Application Developer のベースとなっている Eclipse プラットフォームには、機能を拡張するための方法が数多く用意されています。そうした方法には、独自のプラグインを作成する方法から (これらのプラグインは Eclipse の API をすべて利用することができ、また Eclipse の拡張ポイントを使用することができます。詳細は「参考文献」を参照)、外部ツール (例えば自分自身のビルダーとしての Javadoc や Ant スクリプトなど。詳細は「参考文献」を参照) を呼び出す方法まであります。
この記事で説明する例では、その両方を組み合わせて使います。つまり (Eclipse API を使用する) カスタムの Ant タスクを含むプラグインを作成し、その後でこの Ant タスクを Ant スクリプトから呼び出すのです。後ほど説明するように、このスクリプトを手動で GUI から呼び出すこともでき、あるいはこのスクリプトをビルダー・リストに追加し、Rational Application Developer と Eclipse をビルドする際にこのスクリプトを呼び出すこともできます。この Ant タスクは Rational Application Developer の GUI からもコマンドラインから (ヘッドレスで) も実行することができるため、バッチ・ビルドや無人ビルド、夜間ビルドなどに機能を追加するための強力なメカニズムとなります。
添付サンプルの背景
Eclipse では慣習的に、自動で生成されるすべての成果物には「派生 (Derived)」フラグにチェックが付けられます (「参考文献」を参照)。「派生」にチェックが付けられる最も一般的な例は、コンパイルされた Java™ クラス・ファイル (*.class) です (図 1)。
図 1. 「派生 (Derived)」フラグを含め、ファイルのプロパティーを表示する画面のスクリーン・キャプチャー
自動生成されるファイルの別の例は Java のソース・ファイル (*.java) です。Java ソース・ファイルはアノテーションから、または (Web サービスのクライアントの場合など) WSDL (Web Services Description Language) ファイルから生成されます。さらにもう 1 つ、自動的に生成される成果物の例として、IBM WebSphere® Application Server (または別のサーバー) にアプリケーションをデプロイする際に ejbDeploy によって生成される EJB (Enterprise JavaBeans™) スタブがあります。
この記事で紹介する例のポイントは、このように生成されるファイルの大部分が、(メニュー・アクションで「プロジェクト」 > 「クリーン」の順に選択することで呼び出される) 「クリーン」ビルドを行っても削除されない、という点です。なぜかと言うと、「クリーン」コマンドでクリーンアップされるのは通常は出力フォルダーですが、生成されるファイルは普通、出力フォルダーには置かれないからです。
生成されたソース・ファイルは「クリーン」コマンドを実行しても削除されませんが、それには理由があります。ほとんどの場合、自動生成されるソース・コードを再生成することは、主にパフォーマンス上の理由から、なるべくなら避けたいからです。
しかし、(例えば夜間に) 完全なビルドを行いたい、という要求も正当なものです。また、元のソース・ファイル (例えば WSDL ファイルなど) や (自動生成の元となる) アノテーション・ファイルが変更された場合にも完全なビルドを行う必要があります。こうした場合には確実を期すために、生成されたファイルも削除し、それまでに生成されたファイルが残らないようにした方が賢明です。なぜなら、そうした残りファイルによって、コンパイル・エラーからランタイム・エラーに至るまで、ありとあらゆる発見困難な問題が起こる可能性があるからです。
冷静に見てみましょう。例えば夜間のビルドの場合、各ビルドが確実に新しいワークスペースで行われるようにすれば、完全なビルドを容易に実現することができます。つまり最初に古いワークスペースを削除してから新しいワークスペースを作成し、ソース管理システム (など) からさまざまなプロジェクトをチェックアウトしてそのワークスペースに追加するのです。この方法は、自動生成されたファイルは元々ソース管理システムにチェックインされない、ということを前提としています。実際、「派生」にチェックが付けられたファイルは本来ソース管理システムにチェックインしてはならないものです (Eclipse のドキュメントの「Derived resources (派生リソース)」の項に書かれているとおりです)。
その一方、個々の開発者にとっては、新しいワークスペースを作成するという方法は確かに可能ですが、そのために必要な時間を考えると、あまり現実的ではありません。ここで紹介する例は、「派生」にチェックが付けられたすべてのファイルをカスタムの Ant タスクを使って削除する上で役立つはずです。このタスクは、Ant をビルドする際に GUI またはコマンドラインから呼び出すことができます。この新しい Ant タスクは現在の「クリーン」コマンドを補完するものであり、「クリーン」コマンドによってどのようなクリーンアップが行われたかによらず、すべての派生ファイルを確実に削除します。
この新しい Ant タスクの実装を紹介する前に一言注意しておきます。「派生」フラグの使い方に関する Eclipse の定義は非常に明確ですが、さまざまな製品グループが「派生」フラグの使い方を実際にどう実装し、どう解釈した上で Eclipse を使って製品を構築しているかは、誰にもわかりません。つまり、「派生」にチェックを付けてはならないファイルに、チェックが付けられている (そのため、この Ant タスクによって削除される) ケースがあり得るということです。また、「派生」にチェックを付ける必要がありながらチェックが付けられておらず、そのため削除されないファイルもあるかもしれません。また、Eclipse の Bugzilla 126354 の項 (「参考文献」を参照) にある、「クリーン」コマンドで派生リソースも削除する必要があるのか、という議論も参考になります。
派生リソースを削除するためのコード
ここで紹介するコードは Eclipse の Java プロジェクトとして作成されたもので、このコードを JAR (Java archive) に組み入れて Ant タスクのプラグインの中にパッケージ化しています。リスト 1 はこのコードの重要な部分を示しています。この部分は Eclipse の API を使ってワークスペースを再帰的に検索し、「派生」にチェックが付けられたリソースを見つけ、それらのリソースを削除します。この Ant タスクの中で、この 2 つのメソッドは最も重要なものです。
注:
サンプル・コードは (Eclipse V3.2 をベースとする) Rational Application Developer V7 でテストされています。
ソース・ファイルを含む完全なコードは .zip ファイルとしてパッケージ化されており (「ダウンロード」セクションの DeleteDerivedAttachments.zip を参照)、Eclipse のプラグインとして、そのまま既存の Rational Application Developer と Eclipse のシステムにデプロイすることができます。そのためには DeleteDerivedAntTaskPlugin_1.0.0.jar を Rational Application Developer のインストール・ディレクトリーの /SDP70/plugins フォルダーの中にドラッグします。この .zip ファイルには、後ほど説明する build.xml ファイルも含まれています。
リスト 1 のコードは下記の 2 つの場合を考えたものです。
- 現在のプロジェクト (つまり Ant スクリプト・ファイル
build.xml が置かれているプロジェクト) の中にある派生リソースのみを削除する場合。
- ワークスペース全体の中にある派生リソースを削除する場合。
後ほど示すように、上記のいずれかを build.xml ファイルの中で選択することができます (デフォルトでは現在のプロジェクトのスコープで削除します)。
リスト 1. 派生リソースを検索し、削除する
/**
* Performs the "derived resources" deletion.
*
* @exception BuildException thrown if a problem occurs during execution.
*/
public void execute() throws BuildException
{
log = ResourcesPlugin.getPlugin().getLog();
IProject[] project = null;
IProject currentProject = null;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();
if (cleanWorkspace) // delete derived resources in the whole workspace
{
System.out.println("DeleteDerivedResourcesAntTask.execute()-
clean all the workspace");
project = root.getProjects();
int length = project.length;
for (int i = 0; i < length; i++)
{
if (project[i].isOpen())
{
System.out.println("delete all derived resources in project: " +
project[i].getName());
try
{
IResource[] resourcesInProject = project[i].members();
int projectMembers = resourcesInProject.length;
for (int j = 0; j < projectMembers; j++)
{
try
{
if (resourcesInProject[j].exists())
{
deleteAllDerivedResources(resourcesInProject[j]);
}
}
catch (CoreException e)
{
e.printStackTrace(System.out);
}
}
}
catch (CoreException e)
{
e.printStackTrace(System.out);
System.out.println("CoreException reading project members");
}
}
}
}
else // delete derived resources only in the current project
{
antProject = getProject();
baseDir = antProject.getBaseDir().getName();
currentProject = root.getProject(baseDir);
if (currentProject.isOpen())
{
try
{
IResource[] resourcesInCurrentProject = currentProject.members();
int currentProjectMembers = resourcesInCurrentProject.length;
for (int j = 0; j < currentProjectMembers; j++)
{
try
{
if (resourcesInCurrentProject[j].exists())
{
deleteAllDerivedResources(resourcesInCurrentProject[j]);
}
}
catch (CoreException e)
{
e.printStackTrace(System.out);
}
}
}
catch (CoreException e)
{
e.printStackTrace(System.out);
}
}
}
}
/**
* Delete a resource (file or folder) if it is derived.
* (By definition, anything inside a derived folder is derived too.)
* If it is a non-derived folder, keep on recursing down the tree looking
* for derived resources.
*/
public static void deleteAllDerivedResources(final IResource resource)
throws CoreException
{
if (resource.isDerived()) // only Files and Folders can be derived.
{ // Projects cannot be marked derived.
deleteResource(resource);
}
else
{
if( resource.getType() == IResource.FOLDER )
{
IResource[] members = ((IFolder)resource).members();
for( int i=0, length=members.length; i<length; i++ )
{
deleteAllDerivedResources(members[i]);
}
}
}
}
|

 |
Ant タスクを含むプラグインを作成する
まず、Ant タスクの実装を含む非常に単純なプラグインを作成し、JAR ファイルの中にパッケージ化する必要があります。各プラグインには plugin.xml ファイルがなければなりません。plugin.xml は Eclipse フレームワークへのプラグインを定義し、JAR ライブラリー・ファイルを指定します。この場合は plugin.xml ファイル (リスト 2) の中で Ant タスクの宣言も行っています。
新しいカスタムの Ant タスクを宣言する方法については Eclipse Ant タスクの仕様 (「参考文献」) を参照してください。
plugin.xml ファイル
リスト 2. plugin.xml ファイルの内容
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension id="deleteDerived" name="deleteDerivedResources"
point="org.eclipse.ant.core.antTasks">
<antTask name="deleteDerived"
class="com.rw.sample.DeleteDerivedResourcesAntTask"
library="antLib/AntLib.jar" headless="true" eclipseRuntime="true"/>
</extension>
</plugin>
|
予想外の問題が発生しない限り、Eclipse は新しい Ant タスクを認識するはずです。Eclipse で、「ウィンドウ」 > 「設定」 > 「Ant」 > 「ランタイム」 > 「タスク」の順にメニューを選択すると新しい Ant タスクが表示されるはずです (図 2)。
注: 特に注目すべき点として、Ant タスク・ライブラリーをプラグインの JAR ファイルとは別の場所に置く必要があります。AntLib.jar ファイルはクラスローディングの問題を避けるためにプラグインのサブフォルダーに置かれます。そして Ant タスクをロードする際には、プラグインの classloader ではなく Ant の classloader を使う必要があります (これは「参考文献」に挙げた Eclipse Bugzilla 34466 にあるとおりです)。
図 2. 新たに作成された Ant タスク deleteDerived を Eclipse で表示する
build.xml ファイル
Ant のビルドを実行するためには、Ant ランタイムを実行するための Ant スクリプトが必要です。Ant スクリプトは .xml ファイルであり、通常このファイルには build.xml という名前が付けられます。一例として、リスト 3 は新たに作成されたカスタムの Ant タスクを呼び出すための build.xml を示しています。この build.xml ファイルは、クリーンアップ対象の派生リソースがあるプロジェクト (.project ファイルがあるプロジェクトのフォルダー) のルートに置く必要があります。
サンプルの Ant タスクを柔軟なものにするために、cleanCurrentProjectOnly オプションを追加します。このオプションが true の場合、Ant タスクは build.xml スクリプト・ファイルが置かれていたプロジェクトの中にある派生リソースのみを削除します。それ以外の場合、つまりこのオプションが false の場合には、この Ant タスクはワークスペース全体の中にある派生リソースを削除します。
リスト 3. build.xml ファイルの内容
<?xml version="1.0" encoding="UTF-8" ?>
<project name="customAntTaskBuild" default="deleteDerivedTarget" basedir=".">
<taskdef name="deleteDerived"
classname="com.rw.sample.DeleteDerivedResourcesAntTask">
</taskdef>
<target name="deleteDerivedTarget" cleanCurrentProjectOnly="true" />
</target>
</project> |
Ant のビルドを手動で実行する
build.xml ファイルが作成できたら、今度はこのファイルを実行して動作を確認することができます。build.xml を手動で実行するためには、build.xml ファイルを右クリックして、「実行」 > 「Ant ビルダー」の順に選択します (図 3)。
図 3. Ant ビルドを手動で呼び出す
ほとんどの場合は起動構成ウィザードのデフォルトをすべて受け入れてビルド・ファイルを実行することができます。例外は「JRE」タブです。カスタムの Ant タスクのコードが Eclipse の API を利用するためには、Rational Application Developer および Eclipse と同じ JRE の中でビルドを実行する必要があります。図 8 はこのために必要な設定を示しています。
Ant のビルドを Eclipse ビルダーとして自動的に実行する
Ant のビルドを手動で実行すると、いつでも好きな時に派生リソースを削除することができます。
その一方、ビルドを自動的に行った方が望ましい場合があります (例えば「クリーン」操作にリンクさせ、「クリーン」を呼び出すと必ず派生リソースが削除されるようにしたい場合など)。そのためには Eclipse に対して、ビルダーのリストに build.xml を追加するように命令します (図 4)。
build.xml ファイルを保存したプロジェクトを選択します。
- 「プロパティー」 > 「ビルダー」の順に選択します。
- 「新規」ボタンをクリックします。
図 4. 新規ビルダー・ウィザードを呼び出す
- 構成タイプとして「Ant ビルダー (Ant Build)」を選択します (図 5)。
図 5. 「Ant ビルダー (Ant Build)」の構成を選択する
以下のステップでは、「Ant ビルダー」構成のさまざまなプロパティーを設定します。
- 「メイン (Main)」タブで、ビルダーの名前を設定し、そして作成した
build.xml ファイルの場所を指定します (図 6)。
図 6. 「メイン (Main)」タブで「Ant ビルダー」構成を設定する
- 「メイン」タブでの設定が終わったら、「ターゲット (Targets)」タブの設定欄に入力します (図 7)。
いつビルダーを呼び出すかに関して、Eclipse プラットフォームには次のようにさまざまな選択肢が用意されていることに注目してください。
- 「クリーン」を実行した後 (「「クリーン」の後 (After a "Clean")」)
- 手動ビルドを行う都度 (「手動ビルド (Manual Build)」)
- 自動ビルドを行う都度 (「自動ビルド (Auto Build)」)
- 「クリーン」を実行する間 (「”クリーン” 中 (During a "Clean")」)
図 7 に示すように、この例では「クリーン」を実行する間にのみ派生リソースを削除するオプションを使っています (build.xml でのデフォルト・ターゲットは deleteDerived という Ant タスクです)。これはパフォーマンス上の理由から、「クリーン」を実行する間にのみ派生リソースを削除したいためです。
- そのためには「ターゲットの設定 (Set Targets)」ボタンをクリックし、ターゲットを選択します。
この機能は「クリーン」コマンドで通常行われることを行うだけではなく、生成されたすべてのコードも確実に削除します。
図 7. ビルダーのターゲット
「ターゲット」タブでの設定を終えたら「JRE」タブに進みます。
- 「ワークスペースと同じ JRE で実行 (Run in the same JRE as the workspace)」オプションが選択されていることを確認します (図 8)(Ant タスクのコードが Eclipse の API を利用するためにはこのオプションを選択する必要があることを思い出してください)。
図 8. Ant ビルダーの JRE 構成を選択する
- この時点でビルダーの構成が完了したことになります。そこで「OK」をクリックします。これにより、新しく定義したビルダーがリストの中に表示されるはずです (図 9)。
図 9. 更新されたビルダー・リスト
ここで、もう 1 つ考慮しなければならないことがあります。それは、他のビルダーやコンパイラーなどが実行される前に、生成された (派生された) リソースが必ず削除されるようにする必要があるということです。
- ビルダーの呼び出し順序を変更するために、このビルダー (Delete Derived resources Ant Builder: 派生リソースを削除する Ant ビルダー) を選択し、このビルダーが一番上に来るまで「上へ (Up)」ボタンを繰り返しクリックします (図 10)。Eclipse がビルダーを呼び出す順序は、一番上が最初、一番下が最後です。
図 10. プロジェクトのビルダーの呼び出し順序を変更する
同様に、ワークスペース全体の中にある派生リソースを削除することが目的の場合には、他のどのプロジェクトよりも前に、この build.xml ファイルを含むプロジェクトを必ず最初にビルドする必要があります。そうすることで、他のどのプロジェクトがビルドされるよりも前に、ワークスペース内にあるすべての派生リソースが削除されます。
- このプロジェクトを最初にビルドするためには、「ウィンドウ」 > 「設定」 > 「一般」 > 「ワークスペース」 > 「ビルド順序」の順に選択し、このプロジェクトを適切な順番に割り当てます (図 11)。
図 11. ワークスペース内でのプロジェクトのビルド順序を設定する
まとめ
この記事では、製品の機能を拡張するための強力で柔軟な手法を説明しました。この手法を利用すると、皆さんのチームの要件に特有の新しい目標を達成することができます。
この点に焦点をあてた資料として、.epf ファイルのインポートとエクスポートを行う Ant タスクや、比較とマージ (compare-and-merge) によってモデリングを自動化する Ant タスクなど、カスタムの Ant タスクによる手法を使って特定の要件に対応する他のアプリケーションへのリンクを「参考文献」セクションに挙げてありますので参考にしてください。
謝辞
この記事を校閲してくださった IBM Toronto Lab の Bob Dytyniak 氏に感謝いたします。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Sample Ant task for this article | DeleteDerivedAttachments.zip | 6KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | 
|  | Robert Weisz は IBM Toronto Lab の Rational Premium Support チームの一員として Eclipse と Rational Application Developer のサポートを行っています。 |
記事の評価
|