レベル: 中級 Jie Tang, Software Engineer, IBM China Li Li Lin, Software Engineer, IBM China
2008年 12月 22日 Eclipse のデフォルトのプラグイン・テンプレートは、ユーザーのニーズに応えることができる場合には便利なものです。しかし特定の要件に対してデフォルトのテンプレートでは対応できない場合には、テンプレートをカスタマイズする必要があります。この記事では、Eclipse のプラグイン・プロジェクトのテンプレートをカスタマイズする方法、テンプレートの中でマルチセクションを実装する方法と制御する方法、UI コンポーネントをカスタマイズして使いやすさを改善する方法、UI 側に入力検証機能を追加する方法、そしてプラグイン・プロジェクトのディレクトリー構造を自動的に構成する方法などについて説明します。
Eclipse でプラグイン・プロジェクトを作成したことがある人であれば、Eclipse で使われるプラグイン・プロジェクトのテンプレートをよく理解しているはずです。こうしたテンプレートは新しいプロジェクトの出発点として重宝します。既存のプラグイン・テンプレートを使うと大幅に時間を節約することができますが、これらのテンプレートは万能ではありません。
既存のテンプレートを使う場合、ユーザーの要件を満たすテンプレートをどのように見つけるかという問題があります。しかしテンプレートが提供する機能は限られている一方でユーザーの要件は多様なため、テンプレートの作成者が完璧にユーザー要件を予測することはほとんど不可能です。テンプレートをカスタマイズすればユーザーが必要とするプラグインをゼロから作成しなくてもユーザーに提供できるため、テンプレートのカスタマイズは賢明な方法です。
この記事では以下の内容について学びます。
- Eclipse でプラグイン・プロジェクトのテンプレートをカスタマイズする方法
- テンプレートの持つ高度な機能 (マルチセクションの実装と制御、UI コンポーネントのカスタマイズ、検証など)
- プロジェクトのディレクトリー構造を自動的に構成するツール
前提条件
この記事は、Eclipse を理解した上でプラグインの開発に関心を持つ Java™ 技術開発者を対象としています。この記事を読むためにはプラグインと Eclipse ベースの開発ツール全般に関する基本的な事項を理解している必要があります。サンプル・プラグインを作成するためには、Eclipse (V3.4 以降) をインストールしたコンピューターと最新の JRE (Java Runtime Environment) が必要です。
ここで行う作業は、developerWorks の記事「Eclipse Plug-in Development Environment を使ってテンプレートを作成する」を基にしています。プラグイン・テンプレートを初めて扱う人は、その記事にテンプレートの作成方法が説明されていますので、まずその記事を読むことをお勧めします。ただしその記事は入門記事であるため、そこで紹介しているテンプレートにはこの記事で説明する下記のフィーチャーがありません。
- マルチセクションの実装と制御
- 一般的に、プラグイン・テンプレートのセクションはまとまりを持った関数モジュールとして定義され、ユーザー入力に基づいて作成または生成される非常に相互依存度の高いファイルを含んでいます。このセクションの下にあるファイルはすべて複製されて目的のプロジェクトとなるか、あるいはまったく何も処理されません。セクションは必須またはオプションのセクションとして、ユーザーによって定義されます。必須セクションの下にあるファイルはプラグイン・プロジェクトの中に含める必要があり、オプション・セクションの下にあるファイルは必要に応じてコピーします。これはプラグイン・テンプレートが関数のスーパーセットの場合に便利ですが、一部のプロジェクトではサブセットしか必要としません。
- UI コンポーネントのカスタマイズ
- Eclipse では、プラグイン・プロジェクトのテンプレート用にデフォルトの UI コンポーネントがいくつか提供されています。これらの基本的な UI コンポーネントは限られた機能しか提供しません。使いやすさと機能を改善するために、場合によっては複雑なコンポーネントをカスタマイズする必要があります。
- 入力検証機能
- これによってデータ検証機能を詳細に設定できるようになります。
- プラグイン・プロジェクトのディレクトリー構造の自動構成
- テンプレートを使うと、プラグイン・プロジェクトのリソースを特定のディレクトリーの中に構成することができます。この機能によって手動での作業を省くことができます。
これらの拡張フィーチャーを利用すると、プラグイン・テンプレートがよりスケーラブルに、使いやすく、そして効率的になります。以下のセクションでは、これらのフィーチャーをすべて使用するサンプル・テンプレートを説明します。
ケース・スタディー: プラグイン・テンプレートについての詳細な説明
プラグイン・プロジェクトのグループが必要だとしましょう。これらのプロジェクトはさまざまな Eclipse パースペクティブ (Java パースペクティブや Web パースペクティブなど) を作成するために使われます。1 つのパースペクティブを作成するために 1 つのプロジェクトが必要です。各パースペクティブはいくつかのビューを持つことができます。すべてのビューには関連リソースがあり (画像や自動生成された Java ソース・ファイルなど)、これらのリソースをプロジェクトの中にコピーする必要があります。1 つのパースペクティブでのビューの数と各ビューの名前は個々のパースペクティブごとに決まります。
プラグイン・テンプレートをカスタマイズすると、目的とするプロジェクトを効率よく生成することができます。
単純なテンプレートを作成する
まず、新しいプラグイン・プロジェクトを作成します (File > New > Project > Plug-in Project)。必ず、「This plug-in will make contribution to the UI (このプラグインを UI に追加)」チェックボックスを選択します。こうする理由は、この例で目的とするプロジェクトが UI を使用するパースペクティブを作成するためのものだからです。この新しいプロジェクトが作成されたら、org.eclipse.pde.ui.plugin.Content を継承するテンプレート・ウィザード拡張機能も plugin.xml に追加する必要があります。
新フィーチャー A: マルチセクションの実装と制御
上記のケースをよく見ると、テンプレートをカスタマイズする際の問題に気付きます。各パースペクティブに対するビューの数は変更される可能性があるため、その数が指定されるまで、関連リソースを生成して目的のプロジェクトの中にコピーすることができません。
この問題に対処するために、ここでは 2 つのソリューションを考えます。一般的な方法は、ビューの数が同じパースペクティブをすべて集めたパースペクティブ・カテゴリーそれぞれに対して 1 つのテンプレートを作成する方法です。もう 1 つの方法はもっと効率的で高度な方法であり、すべてのパースペクティブ・カテゴリーに対して 1 つのテンプレートのみを作成します。そしてビューとパースペクティブとのリンクをセクション・コントロールによって管理します。
パースペクティブ・セクションとビュー・セクション用に拡張機能を追加する
このサンプルでは、すべてのリソースを 2 つのセクションに分割します。パースペクティブ・セクションを使ってパースペクティブ・リソースを管理し、ビュー・セクションを使ってビュー・リソースを管理します。ビューを持たないパースペクティブが必要な場合には、対応するプロジェクトにはビュー・リソースはまったくコピーされません。同様に、9 つのビューを持つパースペクティブが必要な場合には、9 つのビューがパースペクティブに登録され、またビュー・ソースが繰り返し生成されて目的のプロジェクトにコピーされます。
この 2 つのセクションを生成するためには、プラグイン・マニフェスト・エディターの Extensions タブで拡張機能を追加する必要があります。
図 1. Extensions タブ (パースペクティブ・セクション)
図 2. Extensions タブ (ビュー・セクション)
セクションの実装
図 3 はこのテンプレート・プロジェクトの構造を示しています。この例では新しい 5 つのファイルが作成されています (SampleWizard.java、PerspectiveSection.java、ViewSection.java、$perspectiveClassName$.java、$viewClassName$.java)。これらのファイルはこのプロジェクトの中心部分を構成しています。
図 3. テンプレート・プロジェクトの構造
PerspectiveSection と ViewSection は、テンプレート・ウィザードの 1 つのセクションを表現するために使われる OptionTemplateSection のサブクラスです。この 2 つのサブクラスには 3 つの主な機能があり、テンプレートの UI の作成、UI からの入力変数の保持、そしてプラグイン・モデルの更新を行います。表 1 はこのセクション・クラスのメソッドの説明です。
表 1. セクション・クラスのメソッドの説明
| メソッド名 | 機能の説明 |
|---|
| initializeFields | 入力パラメーターを使ってウィザード・ページのオプションを初期化します。一部のオプションは、そのウィザードでの前のステップでユーザーが何を選択したかに依存します。 |
|---|
| addPages | テンプレートに関係するページをウィザードに追加します。 |
|---|
| getStringOption | オプションの名前を取得します。 |
|---|
| getSectionId | セクションの ID を返します。 |
|---|
| updateModel | 必要なエントリーをプラグイン・モデルに追加します。 |
|---|
$perspectiveClassName$.java と$viewClassName$.java はテンプレート・ファイルであり、目的とするプロジェクトの Java ソース・ファイルに自動変換されます。この例でのテンプレート・ファイルは非常に単純です。ここでは単に各ビューに対してリストを作成し、そしてこれらのビューをパースペクティブに追加すればよいだけです。
次に、ウィザードの動作の中にセクションの制御を含めます。SampleWizard クラスはプラグインのウィザードのテンプレートとして使われる NewPluginTemplateWizard のサブクラスです。指定されたセクションを、目的とするプラグイン・プロジェクトに SampleWizard クラスを使って割り当てます。performFinish メソッドはスーパー・クラスから継承され、ウィザードの中で特別な終了処理を行うために使われます (例えばテンプレートの各セクションに対してループ動作を行い、それらのセクションを連続的に実行して目的のプロジェクト用のファイルを生成する、など)。リスト 1 はウィザードにセクションを登録する方法と performFinish メソッドのメインのアクションを示しています。
リスト 1. SampleWizard.java
//register all related sections in wizard
public ITemplateSection[] createTemplateSections() {
return new ITemplateSection[] {
new PerspectiveSection(),
new ViewSection()
};
}
public boolean performFinish(final IProject project, IPluginModelBase model,
IProgressMonitor monitor) {
...
ITemplateSection[] sections = super.getTemplateSections();
//monitor finish action in this wizard
monitor.beginTask("perform finish", sections.length);
...
//get sections
for (int i = 0; i <sections.length; i++) {
if (sections[i].getClass().equals(PerspectiveSection.class)) {
perspectiveSection = (PerspectiveSection) sections[i];
} else if (sections[i].getClass().equals(ViewSection.class)) {
viewSection = (ViewSection) sections[i];
}
}
...
//set variables to sections and manage sections
...
viewSection.setViewClassName(values[j]);
viewSection.setSourcePath(sourceFolderName);
viewSection.execute(project, model, new SubProgressMonitor(monitor, 1));
perspectiveSection.setSourcePath(sourceFolderName);
perspectiveSection.setViewNames(viewNames);
perspectiveSection.execute(project, model, new SubProgressMonitor(monitor, 1));
}
|
新フィーチャー B: UI コンポーネントのカスタマイズ
先ほど触れたように、パースペクティブはユーザーが必要とするだけの任意の数のビューを持つことができ、各ビューの名前はユーザーが設定します。ここでは、あるパースペクティブのすべてのビューを収集するために、下記の入力パネルを設計します。このパネルには View Class Name フィールドと View List フィールドがあります。ユーザーがビュー・クラスの名前を入力して Add ボタンをクリックすると、そのビュー・クラスをビュー・リストに追加することができます。同様に、ユーザーは Remove ボタンを使ってビューを削除することもできます。
図 4. テンプレート・オプションをカスタマイズする
この入力パネルを作成するためには、TemplateOption を継承する ViewOption クラスをテンプレート・プロジェクトに追加します (図 3)。このクラスを使って UI コンポーネントを設定し、またユーザー入力を保存します。リスト 2 はビュー・リストと 2 つのボタンを持つ UI コンポーネントをカスタマイズする方法を示しています。
リスト 2. ViewOption.java
//add UI components in this panel
public void createControl(Composite parent, int span) {
...
//create View List
listLabel = new Label(parent, SWT.LEFT);
listLabel.setText("View List:");
listViewerField = new ListViewer(parent);
listField = (List) listViewerField.getControl();
GridData listGridData = new GridData(GridData.FILL_HORIZONTAL);
listGridData.heightHint = 100;
listField.setLayoutData(listGridData);
...
//create add button
addButton = new Button(parent, SWT.PUSH);
addButton.setText("Add");
...
addButton.setLayoutData(addBtnData);
addButton.addSelectionListener(...);
//create remove button
removeButton = new Button(parent, SWT.PUSH);
...
removeButton.addSelectionListener(...);
}
|
新フィーチャー C: 入力検証機能
入力検証機能というのは、使用前にあらゆるユーザー入力を検証するプロセスを指します。入力検証機能はアプリケーションのセキュリティーのために絶対に必要です。この記事の例では検証ルールを定義することにし、あるパースペクティブのすべてのビューにおいてビュー・クラスの名前は一意でなければならないとします。このルールに違反すると、パネルの先頭にエラー・メッセージが表示されます。
図 5. カスタマイズされたテンプレート・オプションを検証する
入力検証機能を実装するためには、対応するセクション・クラスの validateOptions メソッドを呼び出します。このメソッドはスーパー・クラスから継承され、このメソッドを上書きすることで独自の継承機能を実行することができます。リスト 3 は、この例での validateOptions メソッドを示しています。
リスト 3. ViewSection.java での validateOptions メソッド
public void validateOptions(TemplateOption source) {
this.getPage(0).setErrorMessage(null);
ViewOption viewOption = (ViewOption) source;
Text textField = viewOption.getTextField();
List listField = viewOption.getListField();
String[] items = listField.getItems();
if (items != null && items.length > 0) {
//validation rule check
for (int i = 0; i < items.length; i++) {
if (items[i].equals(textField.getText())) {
this.getPage(0).setErrorMessage("Class name '"
+ textField.getText()
+ "' already exists in View List.");
break;
}
}
}
}
|
新フィーチャー D: プラグイン・プロジェクトのディレクトリー構造の自動構成
この記事での目標の 1 つは、目的とするプラグイン・プロジェクトのディレクトリー構造をテンプレートによって自動的に構成することです。これを以下の 3 つのステップで行います。
- 目的とするプロジェクトのディレクトリー構造を、変数を使って保存します。
- Ant スクリプトを作成します。このスクリプトを使ってターゲットのディレクトリー構造を作成し、適切なディレクトリーにリソースを割り当てます。
- テンプレートのワークスペースをモニターするために
IResourceChangeListener を追加します。セクション・ファイルの生成が終了したら Ant スクリプトの実行をトリガーします。
実装
- 単純にするために、プロジェクト名と同じ名前を使う 1 つのパッケージの中にすべての Java ファイルがコピーされるものとします。例えばプロジェクト名が
com.ibm.template の場合には、すべての Java ファイルは com.ibm.template パッケージの中に入ります。この記事ではこれについての説明は省略します。詳細は「Eclipse Plug-in Development Environment を使ってテンプレートを作成する」を参照してください。
- リスト 4 は、この例で使用する Ant スクリプトを示しています。このスクリプトには 3 つの
target があります。最初の target はソースのパスとパッケージのパスに基づいてディレクトリー構造を作成します。2 番目の target はすべての Java ファイルを適切なディレクトリーにコピーします。最後の target は、このスクリプト・ファイルを新しいプラグイン・プロジェクトから削除します。
IResourceChangeListener を SampleWizard クラスの performFinish メソッドに追加します。リスト 5 はこのリスナーの実装を示しています。
リスト 4. CreatePackage.xml
<?xml version="1.0"?>
<project name="template project" default="clean" basedir=".">
<property name="package" value=".\$sourcePath$\$packagePath$"></property>
<target name="create">
<mkdir dir="$dollarMark${package}"/>
</target>
<target name="move" depends="create">
<move todir="$dollarMark${package}">
<fileset dir=".">
<include name="*.java"/>
</fileset>
</move>
</target>
<target name="clean" depends="move">
<delete dir=".">
<include name="CreatePackage.xml"/>
</delete>
</target>
</project>
|
リスト 5. SampleWizard.java (リスナー)
public boolean performFinish(final IProject project, IPluginModelBase model,
IProgressMonitor monitor) {
...
//get workspace
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
//get Ant file
String antFilePath = "CreatePackage.xml";
final IFile file = project.getFile(antFilePath);
//add Listener to monitor resource changing
IResourceChangeListener listener = new IResourceChangeListener() {
public void resourceChanged(IResourceChangeEvent event) {
try {
if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
IResourceDelta rootDelta = event.getDelta();
IPath filePath = file.getFullPath();
IResourceDelta targetDelta = rootDelta.findMember(filePath);
if (targetDelta != null) {
URI uri = file.getLocationURI();
File antFile = new File(uri);
//run Ant script
Project project = new Project();
project.fireBuildStarted();
project.init();
ProjectHelper helper = ProjectHelper.getProjectHelper();
helper.parse(project, antFile);
project.executeTarget(project.getDefaultTarget());
project.fireBuildFinished(null);
workspace.removeResourceChangeListener(this);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
workspace.addResourceChangeListener(listener);
...
}
|

 |
テンプレートを使う
新しいプラグイン・プロジェクトを作成したら、プロジェクトを更新する必要があります。このプロジェクトを右クリックし、Refresh というメニュー項目を選択します。こうする理由は、プロジェクトが生成された後で先ほどの Ant スクリプトを実行する必要があるからです。プロジェクトの更新は手動で Eclipse IDE の中で行う必要があります。リスト 6 は「ケース・スタディー: プラグイン・テンプレートについての詳細な説明」で説明したサンプルのテンプレートを使って生成されたプラグイン・プロジェクトです。
図 6. 新しいプロジェクトの構造
この新しいプロジェクトを [eclipse_home]\plugins ディレクトリーにエクスポートしたら、-clean パラメーターを付けて Eclipse を再起動する必要があります。Eclipse が起動したら、先ほど作成したパースペクティブがパースペクティブ・リストに追加されていることを確認します (リスト 7)。myplugin perspective を選択して OK をクリックします。そうすると、このパースペクティブが開かれます。
図 7. パースペクティブ・リスト
まとめ
この記事を読んだことで、Eclipse のプラグイン・テンプレートについて、より深く理解することができたはずです。この記事では、カスタマイズした入力コンポーネントを作成する方法、テンプレート・ファイルの生成を制御する方法、そしてさまざまなディレクトリー構造を持つプラグイン・プロジェクトを 1 つのテンプレートを使って生成する方法を学びました。こうしたテンプレート機能を利用すると、プラグイン・プロジェクトを容易に作成することができます。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Sample plug-in template | os-eclipse-plugin-templates.zip | 33KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | 
|  | Jie Tang は IBM China Systems and Technology Laboratories のソフトウェア・エンジニアであり、システム管理ソフトウェアを中心とした業務を行っています。現在は IBM Director Configuration Manager プロジェクトに従事しています。彼はオープンソース・プロジェクトにも関心を持っています。 |
 | 
|  | Li Li Lin は IBM Director のソフトウェア・エンジニアであり、OSGI 関連の開発を中心とした業務を行っています。彼女はプラグインの開発に熟達しており、また Web ベースのプロジェクトを幅広く経験してきています。 |
記事の評価
|