EMF を使ったメタモデリング: 具体的で再利用可能な Java スニペットを生成する

Eclipse Ecore メタモデルを拡張する方法

再利用可能な Java™ スニペットをモデル化するために、EMF (Eclipse Modeling Framework) Ecore メタモデルに要素と属性を追加して拡張する方法を学んでください。この記事では、JET による動的テンプレートを使って拡張モデル要素の実装コードを生成する方法についてもステップバイステップで説明します。

Ken McNeill, Consulting Solution Architect, IBM

Ken McNeill は、ソリューション・アーキテクト兼エンジニア、さらにオープンソース活動家として Java ベースの MDA および SOA 駆動型ソフトウェアに携わっています。彼の拠点はフランスです。



2010年 7月 20日 (初版 2008年 4月 08日)

EMF は Eclipse プラットフォームに不可欠な部分であると同時に、Eclipse Visual Editor、SDO、XSD、そして UML といった関連技術およびフレームワーク (その多くは、Rational® Application Developer や WebSphere® Business Modeler などの IBM® プラットフォームに統合されています) の基礎でもあります。現在、EMF は列挙型、アノテーション、Generics をはじめとする Java 技術の機能を包含するまでに進化しました。EMF に馴染みのない方は、「参考文献」に記載されている入門者用の記事を参照してください。

EMF に関するほとんどのマニュアルやチュートリアルでは、振る舞いをモデル化するためにではなく、データとインターフェース (EMF リリース・ドキュメントでの Library と Books など) をモデル化するために EMF を使用しています。もちろんデータ・オブジェクトを対象に生成されたデフォルト・メソッド実装もありますが、これらの実装が扱っているのはモデル要素間の関係です。その上、Eclipse Foundation の記事「Modeling Rule-Based Systems with EMF」(「参考文献」を参照) は例外としても、「メタ・メタモデル」としての EMF の使用例はほとんど文書化されておらず、Ecore メタモデルの拡張方法を説明する例に至っては 1 つもありません。

また、EMF JET テンプレートを使用および拡張するプロセスも十分には文書化されていません。さらに、最近になって JET エディター・プロジェクトは別の Eclipse プロジェクト (M2T) に移行されました。そこで、この記事ではこうした内容について説明し、読者の皆さんが動的テンプレートを EMF との関連で一層活用できるようにしたいと思います。

Ecore メタモデルを拡張する理由

そもそも Ecore とは何なのか

EMF (Eclipse Modeling Framework) は、Eclipse 用のモデリング・フレームワークです。Eclipse Foundation によると、コアとなる EMF のフレームワークにはモデルとそのモデルのランタイム・サポートを記述するためのメタモデル (Ecore) が組み込まれています。このメタモデルには、変更通知、デフォルト XMI によるシリアライズを使った永続化サポート、そして EMF オブジェクトを一般的に操作するためのリフレクティブ API が含まれます。言い換えると、Ecore はコア・モデルの構造を定義し、さらにそのコア・モデルが、開発者がアプリケーション・データを管理するために使用するモデルの構造を定義するということです。

Ecore メタモデルは、モデル駆動型アーキテクチャー (MDA) を設計する際の強力なツールで、ソフトウェア開発の出発点として使用することができます。一般に Ecore メタモデルで定義するのは、アプリケーションの領域でのオブジェクト (EClass 型)、オブジェクトの属性、そしてオブジェクト間の関係です。また、これらのオブジェクトに属する特定の操作も EOperation モデル要素を使って定義します。EMF はデフォルトで、これらの操作の「スケルトン」、つまりメソッド・シグニチャーを生成しますが、操作を実装するには Ecore メタモデルにまで戻る必要があり、同じようなロジックのコードを何度も作成することも珍しくありません。

一方、ある種の自由な実装の振る舞いをモデルに直に指定するという場合を考えてみてください。それには、テキスト・ベースのアノテーション (EAnnotation 型) をモデル・オブジェクトに追加し、コードの生成中にこれらのアノテーションをテンプレートで解釈するという方法があります。その好例は、Eclipse Foundation の記事「Implementing Model Integrity in EMF with MDT OCL」(「参考文献」を参照) に記載されています。しかし、その記事に記載されているようなモデル要素の妥当性の検証は、この記事で目的とするところではなく、この記事で目的とするのは、あらゆる具象モデルでメタモデル要素を再利用するために、実装自体をモデル化することです。この目的のためには、Ecore メタモデルを拡張する必要があります。


拡張メタモデル

この記事で取り上げるのは、Ecore を拡張したモデルで、プログラムによる非常に単純化されたモデルです。このモデルは完全な、あるいは首尾一貫したメタモデルでもフレームワークでもなく、厳密には EMF によるコード実装のメタモデリングの可能性を示すことを目的としたプロトタイプ的な一連の要素でしかありません。図 1 に、この記事で使用する EcoreX というサンプル拡張メタモデルのスナップショットを記載します。この図に続いて、それぞれの要素を簡単に説明します。

図 1. EcoreX モデル
EcoreX モデル

EcoreX の要素

EPackage を拡張する EPackageX
この要素は、Ecore 要素である EPackage の単純な「マーカー」拡張で、追加の属性はありません。この要素が必要となる理由は、デフォルトでは EPackage 要素に対応した EMF エディター・プラグインで EClass のサブクラスを子要素として追加することができないためです (この後の EClassX を参照)。EPackage を拡張するモデル要素を提供すると、EPackageXEClassX 子要素を追加することのできるコードが自動的に生成されることになります。
EClass を拡張するEClassX
同じくこの要素も Ecore 要素である EClass の単純な「マーカー」拡張で、追加の属性はありません。この要素が必要となるのは、上記の要素と同じく、EClass のエディター・プラグインではこの記事が目的とする EOperation のサブクラスをデフォルトでは追加することができないためです。
EOperation を拡張する EOperationImpl
これは基本エンティティーであり、具体的なメタ機能を Ecore モデルに追加するためのエントリー・ポイントとなります。この要素は、Ecore の基本 EOperation 要素には存在しない属性で参照されます。以下に説明するすべての要素はこの EOperationImpl に属し、プログラムによる実装を構成するために使用されます。例えば、EOperationImpl には変数とステートメントがあり、参照または値を返すことが可能です。
ETypedElement を拡張する LocalVariable
LocalVariable はローカル・スコープを持つ変数です。変数には名前と Java の型 (StringIntegerObject など) があります。これらの属性は変数のスーパー・スーパークラスである EParameter にすでに存在するため、LocalVariable に必要な追加属性はありません。
EClass を拡張する Statement
この単純化されたサンプル・ロジック・モデルでは、EOperationImpl に含まれる多数の statement は、一定の順序で評価されます。Statement は抽象スーパークラスです。
Statement を拡張する LiteralAssignment
変数を参照する LiteralAssignment には、String 属性があります。ユーザーはこの属性に、解析されて変数に割り当てられる値を入力することができます (例えば、「hello」、「4.5」をそれぞれ Stringfloat に割り当てることができます)。
Statement を拡張する Access
Access は、Java フィールドまたは操作を参照する動作表します。
Access を拡張する FieldReferenceAssignment
フィールドにアクセスして値を割り当てます (例えば、var1 = var2.name)。
Access を拡張する Invoke
操作 (Java メソッド) を呼び出します。呼び出し (Invoke) の結果は、変数に割り当てることができます (例えば、myVar = obj.toString())。

図 2 に、UML 風の表現で EcoreX メタモデルを図解します。

図 2. EcoreX モデル図
EcoreX モデル図

開始手順

この記事のステップは、大まかに以下の 2 つに分けられます。

  1. メタモデルの構築
  2. 具象モデルの構築

上記で説明したメタモデルは、作成することも、インポートすることもできます。いずれの場合にしても、まずは既存の Java プロジェクトから手順を開始しなければなりません。既存の Java プロジェクトがなければ、新しく作成してください。この記事では、EMFX という名前の Java プロジェクトを使用します。プロジェクトには model という名前のフォルダーが必要です。EcoreX.ecore モデル (「参考文献」を参照) を model ディレクトリーにコピーして「Editor Metamodel プラグインをビルドして起動する」のセクションまでスキップするか、または以下のステップに従ってメタモデルを一から作成しなおしてください。

Ecore メタモデルを拡張する - 一から始める場合

プロジェクトを右クリックし、コンテキスト・メニューから New > Other > Example EMF Model Creation Wizards > Ecore Model (Eclipse V3.5 以降 (Galileo、Helios) では、New > Other > Eclipse Modeling Framework > Ecore Model) を選択します。フォルダーには model フォルダーを選択し、名前には EcoreX.ecore と入力してください。

デフォルトのモデル・パッケージの名前は ecorex です。モデル・ウィンドウで右クリックして Load Resource > Browse Registered Packages の順に選択します。名前空間が http://www.eclipse.org/emf/2002/Ecore となっている Ecore モデルを選択します。

Ecore メタモデルのインポートが完了したら早速、モデルの拡張に取り掛かれます。まず、ecorex.ecore モデルを再作成するために、パッケージ要素 ecorex を右クリックして New Child > EClass を選択してください。この要素は EPackageX という名前にします (上記のモデル要素の説明を参照してください)。次に必要な作業は、基本要素 EPackage をこの新しい EpackageX 要素の ESuper Type として追加することです。

同じ手順に従って、EClass を今度は ESuperType として指定して新規要素 EClassX を作成します。引き続き必要に応じて Ecore オブジェクトをサブクラス化し、EcoreX モデルに他の EClass を定義します。どの属性でどの EClass を作成するかについて確認するには、図 1 と EcoreX.ecore ファイルを参照してください。

Editor メタモデル・プラグインをビルドして起動する

ビルド・ステップでは、genmodel メタモデルを作成し、モデルとエディター・プロジェクトをビルドします。まず、EcoreX モデルを右クリックして New > Other > Eclipse Modeling Framework > EMF Model (Eclipse V3.5 以降 (Galileo、Helios) では、New > Other > Eclipse Modeling Framework > EMF Generator Model) の順に選択してください。モデル名は自分で指定するのでも、デフォルト名の EcoreX.genmodel をそのまま使用するのでも構いません。genmodel の基本モデルには、EcoreX モデルが事前に選択されているはずです。Load をクリックして EcoreX.ecore メタモデルの妥当性を検証します。

図 3. 新規 EMF モデル
新規 EMF モデル

生成するパッケージと他のジェネレーター・モデルから参照させるパッケージを指定するように求められたら、Root packages では EcoreX パッケージ、Referenced generator models では Ecore を選択します。

この時点で、ウィザードはメタモデルの genmodel を作成します。これで、genmodel の最上位レベルの要素を強調表示してからコンテキスト・メニューで Generate All を選択することによって、関連するコードを自動生成できるようになります。生成されるのは、genmodel に構成された振る舞いに応じた 4 つの Eclipse プロジェクトです。この記事では .test プロジェクトについては取り上げないので、このプラグインに関しては生成しなくても構いません。

ここからは、起動ステップに移ります。ほとんどの Eclipse チュートリアルでは、開発したプラグインを別の Eclipse プロセスで起動するように指示していますが、このセクションではそれとは異なる方法を取ります。ここでは、プラグインを現行の Eclipse およびワークスペース内で有効にします。こうすることによって、次のセクションで、事前に構築されたメタモデルと具象モデル開発を統合しやすくなるからです。以下のステップに従って、プラグインを有効にしてください。

  1. EMFX plugin.xml をダブルクリックしてプラグイン構成エディターを開きます。
  2. Exporting タブで Export Wizard をクリックします。
  3. 基本モデリング・プラグインと 2 つのエディター・プラグインを選択します。
  4. Destination タブで Eclipse のインストール・ディレクトリーを選択します。
図 4. Export ウィザード
Export ウィザード

: -console オプションを指定して Eclipse を起動すると、Eclipse を再起動したり、別のインスタンスを起動することなく、OSGi コマンド・コンソールを使ってプラグイン (バンドル) の起動、停止、更新、リフレッシュを動的に行うことができます。

Finish をクリックすると、自動的に生成済みプラグインの JAR がビルドされて plugins ディレクトリーにコピーされます。この時点で、Eclipse を再起動して新規プラグインを有効にしてください。プラグインが有効になったら、具象モデル (ここでの名前は Test2) を保持するための新規プロジェクトを作成するとエディター・プラグインが起動されるようになります。

この新規プロジェクト内で New > Other > Example EMF Model Creation Wizards > Ecorex Model にナビゲートし、モデル名を指定します。EPackageX 要素を選択すると、空の具象モデルが作成されます。


具象テスト・モデルのモデリング

このセクションでは、具象 Java クラス (EClassX のインスタンス) をモデル化し、このクラスが持つ 2 つの具象メソッドの実装をモデル化します。最初のサンプル・メソッドは String パラメーター・メッセージを取り、このメッセージをタイムスタンプ付きで出力します (こうすると、例えばメッセージをデバッグする際に役立ちます)。目的とする出力結果は以下のとおりです。

リスト 1. printTimestampMessage
void printTimestampMessage(String message) {
	
	System.out.print(message);
	System.out.print("; Timestamp= ");
	System.out.println(System.currentTimeMillis());
}

2 つ目のサンプル・メソッドは日付に基づく 3 つのパラメーターを取り、その日付の曜日を表す 1 つの数値を返します。

リスト 2. getDayOfWeek
int getDayOfWeek(int year, int month, int date) {
	
	int result;
	Calendar calendar = Calendar.getInstance();
	calendar.set(year, month, date);
	result = calendar.get(Calendar.DAY_OF_WEEK);
	return result;
}

最初のステップは、前のセクションの最後のステップで作成した新規 EPackageX 要素で 3 つの必須属性を入力することです。モデリング・ウィンドウの下に Properties タブが表示されていない場合は、コンテキスト・メニューから Show Properties View を選択してください。このサンプルでのパッケージ名は、mypackage とします。

図 5. EPackageX プロパティー
EPackageX プロパティー

次に、新規 EClassX を mypackage に追加します。それには、mypackage が強調表示された状態でコンテキスト・メニューを使用します。name 属性を入力してクラスに名前 (例えば、MyClass) を指定し、この新規クラスに 2 つの EOperationImpl 要素を追加して上記の printTimeStampMessagegetDayofWeek というメソッド名を指定します。続いて、操作ごとに Ecore パラメーターを追加します。

図 6. EOperationImpl getDayOfWeek()
EOperationImpl getDayOfWeek()
図 7. getDayOfWeek() プロパティー
getDayOfWeek() プロパティー

上記の printTimestampMessage() 操作では EString 型のパラメーターを 1 つ取り、getDayOfWeek() 操作では EInt 型のパラメーターを 3 つ取ります。さらに getDayOfWeek 操作は、EType プロパティー属性で構成された EInt を返します (図 7 を参照)。

EOperationImpl の構成内容

これまでは継承された Ecore 要素と属性のみを扱っていましたが、ここからは拡張したメタモデル要素を使って Java 実装をビルドします。

LocalVariable
図 8 を見るとわかるように、printTimestampMessage() に必要な 2 つの LocalVariable 要素の型は、EStringELong です。
図 8. printTimestampMessage()
printTimestampMessage()
図 9. LiteralAssignment
LiteralAssignment

図 9 の Value 属性のストリングは LiteralAssignment にインライン化されています。別のメタモデルでは、リテラル値 (定数) がそれぞれ個別の要素としてモデル化される場合も当然あります。

次に LiteralAssignment 型の要素を挿入します。この要素によって、LocalVariable を選択してそれに値を割り当てることが可能になります。この例では String 変数を選択し、上記のプロトタイプ・メソッドからのテキスト値を提供します (テキストを囲む引用符を忘れずに含めてください)。

DataType
上記の図をもう一度見て、SystemType という Ecore DataType があることに注目してください。これは java.lang.System のラッパーです。これを mypackage パッケージに含める必要があるのは、その後に続く Invoke 要素がこのラッパーを参照するためです。
Statement
この操作に追加する最初の Statement は、上記で定義した SystemType での静的メソッド、currentTimeMillis() の呼び出し (Invoke) です。
図 10. currentTimeMillis() プロパティーの呼び出し
currentTimeMillis() プロパティーの呼び出し

このメタモデルでは (次のセクションでコード・テンプレートを提供した上で)、上記の Invoketimestamp = java.lang.System.currentTimeMillis(); という Java ステートメントに変換されることになります。

次に追加する Invoke は前のものとは微妙に違います。まず第一に、Assignment がありません。第二に、message パラメーターを Args というプロパティーの引数として参照します。

図 11. out.print プロパティーの呼び出し
out.print プロパティーの呼び出し

Access Name プロパティーの値が out.print となっていることにも注目してください。実は、ここでは Java System から out フィールドを逆参照してから print メソッドを呼び出しています。FieldReferenceAssignmentPrintStream 型の LocalVariable と併せて使用する代わりに、今のところはこのショートカットを使用します。

この操作に追加する 3 つ目かつ最後の Invoke は、LocalVariable timestamp を唯一の引数として使用する println() です。これで、printTimestampMessage() 操作の具象モデルが完成します。

次に、2 つ目の EOperationImpl getDayOfWeek() の完全なモデルを見てみましょう。

図 12. getDayOfWeek()
getDayOfWeek()
DataTypes
このモデルの一番下には、この操作に必要な追加 DataType として作成した CalendarType があります。
LocalVariable
この操作モデルに含まれる 3 つの LocalVariable のうち、特に重要なのは result です。操作の最後のステートメントの後に返される値は、このローカル変数が保持するためです。EOperationImpl プロパティーの 1 つとして Return Ref というプロパティーがあります。実装では、このプロパティーとしてプルダウン・メニューを使って LocalVariableresult を選択します。
Statement
図 12 を見るとわかるように、3 つの LocalVariable の後には 3 つの Statement が続いています。最初の InvokeCalendarType 要素の getInstance() を使用し、それによって値を calendar 変数に割り当てます。これは図 10 での実行内容と似ています。

その次にあるのは calendar 変数の set() メソッドの Invoke で、EOperationImpl パラメーターに対応する year、month、date という 3 つの Arg を渡します。

図 13. パラメーターを使用した set()
パラメーターを使用した set()
図 14. FieldReferenceAssignment
FieldReferenceAssignment

メタモデルでは、この要素は DAY = Calendar.DAY_OF_WEEK; のような Java コードになります。

図 15 では、EOperationImpl の最後の InvokeDAY 変数が使用されています。get() の戻り値が、result 変数 (この実装の Return Ref) に割り当てられます。

図 15. Return Ref
Return Ref

動的テンプレートの実装

これまでのところで、拡張メタモデルを設計し、それを使って My.ecorex という具象モデルを記述しました。今度はいよいよ、JET を使ってコード実装を生成する番です。JET テンプレート構文の特徴を調べるためには、JET エディター・プラグインをインストールする必要があります (「参考文献」および「Jet エディターの制約事項」を参照)。

デフォルトでは、EMF はモデルのコードを生成する際に動的テンプレートを使用しません。EMF が使用するのは事前ビルドされた Java クラスです。JET テンプレートのカスタマイズに取り掛かるには、プラグイン JAR の org.eclipse.emf.codegen.ecore_2.3.0.XYZ.jar (ここで、XYZ は Eclipse plugins フォルダーに含まれる EMF ビルドのタイムスタンプ) からコピーしなければならないファイルがいくつかあります。この記事で使用するのは org.eclipse.emf.codegen.ecore_2.3.0.v200706262000.jar です。ファイルをコピーするには、ZIP ユーティリティーで JAR ファイルを開き、以下の手順に従ってください。

  1. この JAR の templates ディレクトリーを具象モデル用の Java プロジェクトに解凍します。
  2. templates/model に Class という名前のディレクトリーを作成します。
  3. model フォルダーに、implementedGenOperation.TODO.override.javajetinc という名前の空のファイルを新規に作成するか、このファイルを「参考文献」からコピーします。

その名前からわかるように、ステップ 3 の新規ファイルは JET テンプレートです。これからこのテンプレートに、モデル・オブジェクト EOperationImpl のコード生成ロジックを配置します。このファイルはデフォルトでは存在しません。EMF は各 EOperation に対して単に空のメソッド・シグニチャーを提供するだけだからです。動的テンプレート機能を有効にすると、この新規ファイルは EOperationImpl の定義に従って自動的に Java メソッドの本文として組み込まれます。

implementedGenOperation.TODO.override.javajetinc の完全なコードは以下のとおりです。

リスト 3. implementedGenOperation

リスティングを見るにはここをクリック

リスト 3. implementedGenOperation

// created by implementedGenOperation.TODO.override.javajetinc
<%if ( ! (genOperation.getEcoreOperation() instanceof EOperationImpl) ) { %>
	// TODO: implement this method
	// Ensure that you remove @generated or mark it @generated NOT
thrownew UnsupportedOperationException();
<% } else { %>
	// ** EOperationX implementation **
<% EOperationImpl opx = (EOperationImpl)genOperation.getEcoreOperation();
Statement stm = null;
Iterator iterator = null;

EList<LocalVariable> pList = opx.getLocalVariables();
LocalVariable lvar = null;

String iname = null;
StringBuffer paramsString = null;
StringBuffer varString = null;
	
for (int i = 0;i < pList.size(); i++) {
	lvar = pList.get(i);
	iname = lvar.getEType().getInstanceClassName();%><%=iname%><%=lvar.getName()%><%if (iname.startsWith("java")) { %> = null<% } %>;
<% }

iterator = opx.getStatements().iterator();

while (iterator.hasNext()) {

	paramsString = new StringBuffer();
	varString = new StringBuffer();
	iname = null;
	
	stm = (Statement)iterator.next();
if (stm instanceof LiteralAssignment) {%><%= stm.getAssignment().getName()%> = <%=\
((LiteralAssignment)stm).getValue()%>;	
<%} else 
	// 
if (stm instanceof FieldReferenceAssignment) {
		Access ax = (Access)stm;	
if (stm.getAssignment() != null) {
		varString.append(stm.getAssignment().getName());
		varString.append(" = ");
		}
if ( ax.getStaticType() != null) {
			// STATIC
			iname = ax.getStaticType().getInstanceClassName();
			} else {
			// NON STATIC
			iname = ax.getTarget().getName();
			} %><%=varString.toString()%><%=iname%>.<%=ax.getAccessName()%>;
<% } elseif (stm instanceof Invoke) {
		// INVOKE
		Invoke iv = ((Invoke)stm);
		
if (stm.getAssignment() != null) {
			varString.append(stm.getAssignment().getName());
			varString.append(" = ");
		}
		
for (int p = 0; p < iv.getArgs().size(); p++) {\
paramsString.append(iv.getArgs().get(p).getName());			
if ( p + 1 < iv.getArgs().size() ) {
			paramsString.append(" , ");
			}
		}
if (iv.getStaticType() != null) {
				// STATIC
				iname = iv.getStaticType().getInstanceClassName();
				} else {
			// NON STATIC
				iname = iv.getTarget().getName();
				} %><%=varString.toString()%><%=iname%>.<%=iv.getAccessName()\
%>(<%=paramsString.toString()%>);
<% }
	
} // STATEMENTS
if (opx.getReturnRef() != null) { %>return<%=opx.getReturnRef().getName()%>;
<% }	

} // EOPERATIONIMPL %>

JET の詳細については、この記事では説明しませんが、JET テンプレートがこのプロセスに重要であることは明らかなので、擬似コードという点からこのテンプレートの中身を調べることにします。最初の変数、genOperation は、テンプレートが処理される前に Ecore/JET によってあらかじめ初期化されることを念頭に置いておいてください。

リスト 4. Ecore/JET によって事前に初期化される genOperation
Is this GenOperation is an EOperationImpl?If false, emit default UnsupportedOperationException
	STOP;

Else, cast it to EOperationImpl;
	continue;

Find and declare all elements of type LocalVariable, initializing Java Objects to null;

Iterate through all Statements;
	Emit Java code according to the subtype;

Does the implementation return something?
If yes, emit the return statement;

There are a few actions to perform before building the concrete model. First, at the top of templates/model/Class.javajet, we must add to the list of imports (the first two marked in bold):

<%@jetpackage="org.eclipse.emf.codegen.ecore.templates.model"
imports="ecorex.*  org.eclipse.emf.common.util.* \
java.util.* org.eclipse.emf.codegen.ecore.genmodel.*"…

具象モデルを構築する前に、いくつか行っておかなければならない作業があります。まず、templates/model/Class.javajet の先頭にインポートするファイルのリストを追加してください (最初の 2 つを太字で示しています)。

上記の EcoreX パッケージはもちろん、拡張したメタモデルです。次に、具象モデル (My.ecorex) の EMF (GenModel) を作成して構成します。それには、モデルを右クリックして New > Other > Eclipse Modeling Framework > EMF Model (Eclipse V3.5 以降 (Galileo、Helios) では、New > Other > Eclipse Modeling Framework > EMF Generator Model) の順に選択します。EMF モデルが作成されたら、Templates & Merge プロパティー・グループにある 3 つのプロパティーを以下のように構成してください。

図 16. GenModel - Templates & Merge
GenModel - Templates & Merge
  1. Dynamic Templates は true に設定します。
  2. Template Directory を指定します。
  3. Template Plugin Variables に EMFX (拡張メタモデル・プラグイン ID) を追加します。

これで、具象モデルを構築する準備ができました。GenModel を右クリックして Generate Model Code を選択してください。すべてが上手くいくと、具象 Test プロジェクト (この例では Test2) のソース・フォルダー (src) に、生成された Java ソース・パッケージとクラスが表示されます。そのなかに含まれる mypackage.impl.MyClassImpl.java ファイルを開くと、2 つのメソッドが生成されているはずです。

リスト 5. MyClassImpl.java
publicvoid printTimestampMessage(String message) {
	// created by implementedGenOperation.TODO.override.javajetinc
	// ** EOperationX implementation **
	java.lang.String timestampStr = null;
long timestamp;
	timestampStr = "; Timestamp = ";
	
	timestamp = java.lang.System.currentTimeMillis();
	
	java.lang.System.out.print(message);
	
	java.lang.System.out.print(timestampStr);
	
	java.lang.System.out.println(timestamp);
	
	}
publicint getDayOfWeek(int year, int month, int date) {
	// created by implementedGenOperation.TODO.override.javajetinc
	// ** EOperationX implementation **
int result;
int DAY;
	java.util.Calendar calendar = null;
	calendar = java.util.Calendar.getInstance();
	
	calendar.set(year , month , date);
	
	DAY = java.util.Calendar.DAY_OF_WEEK;
		
	result = calendar.get(DAY);
	
return result;
	
	}

このクラスをテストするには、main メソッドを追加してください。


注意点とトラブルシューティング

JET エディターの制約事項

JET テンプレートの構文を色分けして強調表示するには、Eclipse JET エディターがインストールされている必要があります (JET エディター・プラグインは最近、EMF から M2T に移行しました)。

ただし、この記事を執筆している時点では、最新バージョンの JET エディターは、ネストされた JET インクルード (.javajetinc ファイルなど) での Java コンテンツ・アシストやオンザフライでのコンパイルを正しく処理しません。さらに、インポートを指定できるのは親ファイル (上記の Class.javajet など) のみで、インクルード・ファイルで指定するとビルドが成功しません。

追加の構成を行うことによって (プロジェクトのコンテキスト・メニューを使用)、EMF 動的テンプレート・プロジェクト (この例では Test2) を JET プロジェクトに変換することは可能です。しかし実際には、上記の制約事項と併せ、EMF と M2T/JET が統合されていないことから、このような変換は現時点では非現実なものとなっています。

したがって、インクルードされたテンプレート・ファイルでエラーをキャッチして修正するのは困難な場合があります。JET テンプレートは最終コードが発行される前に、まず中間 Java ファイル (デフォルトでは JETEmitter という隠し Java プロジェクトに配置) にコンパイルされるため、Eclipse の Package Explorer ビューでのフィルター設定をしないことでコンパイル・エラーを確認することができます。エラーがテンプレート・ファイル内での純粋なフォーマットのエラーであれば、ビルド中に Eclipse のポップアップ・ウィンドウが表示されるはずです。JET の今後のリリースでは、より進化した機能を期待できると思います。

モデルの妥当性の検証の欠如

この記事の例では、EMF Validation Framework も OCL 機能も使用していません。そのため、モデル内に矛盾があるとモデルの構築は失敗します。例えば、EOperationImpl は特定の戻り型を宣言しているのに、Return Ref プロパティーが別の型を参照していたり、ヌルであったりするような場合、このようなエラーはモデルの構築中にはキャッチされないため、生成されたコードはコンパイルされません。進化したメタモデルでは、OCL (「参考文献」を参照) を使用して整合性および制約を強化することになるはずです。


まとめ

この記事では、Ecore メタモデルを拡張して統合的な Java メソッド内での単純なプログラムによる振る舞いを概念化する方法について検討してきました。まずは Ecore 自体をインポートするという方法で、いくつもの Ecore モデル要素 (特に EOperation) を拡張し、それからメタモデルを構築しました。次にエディターを使用して、EOperationImpl という形でモデル化した 2 つの Java メソッドが含まれる具象テスト・モデルを設計しました。そして最後に、EOperationImpl のコードを生成するための JET テンプレートを構成してビルドしました。


ダウンロード

内容ファイル名サイズ
Sample templatesos-eclipse-emfmetamodel.zip2KB

参考文献

学ぶために

  • Eclipse Foundation の記事「Using EMF」で、Eclipse Modelling Framework について紹介しています。
  • Eclipse Foundation の記事「Modeling Rule-Based Systems with EMF」では、ルール・ベース・システムのモデリングを対象とした ECore のメタモデルを定義しています。
  • Eclipse Foundation の記事「Implementing Model Integrity in EMF with MDT OCL」では、後からカスタム・コードを生成する必要のない Ecore 仕様によるモデルの生成方法を紹介しています。
  • Eclipse Modeling Framework (EMF) には、あらゆる EMF 関連の資料とダウンロードが揃っています。
  • Eclipse Foundation の Model To Text (M2T) は、JET を含め、モデルからテキスト成果物を生成することに重点を置いたプロジェクトです。
  • developerWorks の記事「動的 EMF を使ってメタモデルを構築する」を読んで、Java 実装クラスを生成することなく、オンデマンドで動的な Ecore ベースのモデルを作成する方法を学んでください。
  • Eclipse オススメ情報リスト」を読んでください。
  • developerWorks ですべての Eclipse 関連記事を調べてください。
  • Eclipse の初心者は、developerWorks の記事「Eclipse Platform 入門」を読んでください。Eclipse の起源とアーキテクチャー、そしてプラグインで Eclipse を拡張する方法を学べます。
  • IBM developerWorks の Eclipse project resources を調べて、Eclipse のスキルを磨いてください。
  • ソフトウェア開発者を対象とした興味深いインタービューや討論については、developerWorks ポッドキャストをチェックしてください。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • 無料の developerWorks On demand demos で、IBM およびオープンン・ソースの技術と製品機能を調べて試してみてください。
  • 世界中で近日中に予定されている IBM オープンソース開発者を対象とした会議、見本市、ウェブ放送やその他のイベントをチェックしてください。
  • オープンソース技術を使用して開発し、IBM の製品と併用するときに役立つ広範囲のハウツー情報、ツール、およびプロジェクト・アップデートについては、developerWorks Open source ゾーンを参照してください。

製品や技術を入手するために

議論するために

  • Eclipse に関する質問を投じる最初の場所として、Eclipse Platform newsgroups があります (このリンクをクリックすると、デフォルト Usenet ニュース・リーダー・アプリケーションが起動され、eclipse.platform が開きます)。
  • Eclipse newsgroups には Eclipse を利用し、拡張することに関心を持つ人達のために、さまざまなリソースが用意されています。
  • developerWorks blogs から developerWorks コミュニティーに加わってください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=307852
ArticleTitle=EMF を使ったメタモデリング: 具体的で再利用可能な Java スニペットを生成する
publish-date=07202010