2010年3月31日水曜日

EMF Transactionについてまとめてみました

EMFTransaction
EMF Transactionについて

EMFのデータモデルをトランザクションを用いて、複数スレッドからのアクセスコントロールやデータの整合性(atomic)を守る仕組み。 EditingDomainを用いてやり取りを行います。

簡単な説明はざっくり飛ばします。参考サイトを読んでください。


予備知識:EditingDomain

editingDomainは相関のあるEMFモデルを含んでいるのとコマンドを管理するものです。モデルはリソースセットの形式で保持されていています。
コマンドとモデルの編集はドメインを経由して、コマンドスタックを使って行います。
EditingDomainの補足機能として、基本的なコマンドのオーバーライドが使えます(OverrideableCommand. を参照)
ドメインはgetParent,getChildrenメソッドの結果でモデルへ階層的に役割を課す。
これはネストしたオブジェクトの削除などに使うRemoveCommandなどの実装に便利である。
また、ネストしたコピーなどに使うCopyCommandも便利である。

クラス図的にはこんな感じ

Transactional Commands API




Transactional Commands API


EditingDomain取得方法

EMFTransactionはEditingDomainを利用して、データのやり取りを行うため、EditingDomainを取得する必要があります。取得方法としてはTransactionUtilのユーティリティクラスのgetEditingDomainメソッドを利用します。
引数はEObject,Resource,ResourceSetのいずれかを入れてやれば取得が行えます。

データアクセス方法
データ取得

データの取得に関してはデータの変更が行われないため、取得方法はどのようにしても構いません。リソースからモデルを取得して任意のデータを取得することが可能です。

データ更新

コマンドを用いてデータ更新は行います。リソースから直接取得してデータ更新を行うとExceptionが投げられます。


public void setModuleDet(String moduleName, boolean detInfo) {
EObject owner = null;
EAttribute feature = null;


try{
Command cmd = editingDomain.createCommand(
SetCommand.class,
new CommandParameter(
owner,
feature,
detInfo
));

editingDomain.getCommandStack().execute(cmd);
} catch (Exception e) {
logger.warn(e.getMessage());
}
}



ロールバック

トランザクション環境で、データ整合性が失われた場合ロールバックするために、R/Wのトランザクションが発生する。しかし、基本的なコマンドスタックAPIはコマンドを失敗することはないので、
ロールバックしたときのフィードバックはない。
もし、トランザクションが始まっていなく、トランザクションがロールバックや、割り込み例外が発生したとき、トランザクションコマンドスタックはロールバック例外を投げることができる。


Library richmond = getLibrary("Richmond Branch"); // this would use a read-only transaction
TransactionalEditingDomain domain = getEditingDomain();

TransactionalCommandStack tstack = (TransactionalCommandStack) domain.getCommandStack();

Command cmd = domain.createCommand(
SetCommand.class,
new CommandParameter(richmond, EXTLibraryPackage.Literals.LIBRARY__ADDRESS, "5600 Perth St."));

try {
tstack.execute(cmd, Collections.EMPTY_MAP);
} catch (InterruptedException e) {
MessageDialog.openError(shell, "Command Failed",
"Interrupted while waiting for a read/write transaction.");
} catch (RollbackException e) {
ErrorDialog.openError(shell, "Command Failed", "Transaction rolled back",
e.getStatus());
}



コマンドオプション

コマンド実行に対して、色々オプションを付けて実行が行える。

Transaction Options




* OPTION_NO_NOTIFICATIONS:  リスナに変更通知を送らない。
* OPTION_NO_TRIGGERS: トリガーを使わない。
* OPTION_NO_VALIDATION: 変更に整合性チェックを行わない。
* OPTION_NO_UNDO: UNDO/REDOやロールバックのための変更記録を行わない。
* OPTION_UNPROTECTED: OPTION_NO_UNDO, OPTION_NO_VALIDATION, and OPTION_NO_TRIGGERSの複合ケース



TransactionalCommandStack stack;
Library library;

// don't tell the UI that we are changing the library name
stack.execute(
SetCommand.create(domain, library,
EXTLibraryPackage.Literals.LIBRARY__NAME, "Secret Name"),
Collections.singletonMap(
Transaction.OPTION_NO_NOTIFICATIONS, Boolean.TRUE));



トリガー
トリガーの実装も可能である。
Trigger API






// trigger ensuring that all libraries have names
class MyListener extends ResourceSetListenerImpl {
MyListener() { // only interested in changes to Library objects
super(NotificationFilter.createNotifierTypeFilter(
EXTLibraryPackage.Literals.LIBRARY));
}

public Command transactionAboutToCommit(ResourceSetChangeEvent event)
throws RollbackException {

List commands = new ArrayList();
Iterator iter = event.getNotifications().iterator();

while (iter.hasNext()) {
Notification next = (Notification) iter.next();
Library library = (Library) next.getNotifier();
if (library.getName() == null)
commands.add(SetCommand.create(
event.getEditingDomain(), library,
EXTLibraryPackage.Literals.LIBRARY__NAME, "A library"));
}

return commands.isEmpty()? null : new CompoundCommand(commands);
}
}



class MyTriggerListener extends TriggerListener {
MyListener() { // only interested in changes to Library objects
super(NotificationFilter.createNotifierTypeFilter(
EXTLibraryPackage.Literals.LIBRARY));
}

protected Command trigger(TransactionalEditingDomain domain,
Notification notification) throws RollbackException {

Library library = (Library) next.getNotifier();
if (library.getName() == null) {
return SetCommand.create(domain, library,
EXTLibraryPackage.Literals.LIBRARY__NAME, "A library");
}

return null;
}

}



参考サイト

2010年3月29日月曜日

WindowTester Pro 5.0リリース

WindowTester Pro 5.0のリリースだそうなので色々調べてみました。

InfoQにWindowTester Pro 5.0がリリースというニュースを見たので、
ちょっと気になったため調べてみました。
GUI作成ツールを調査しているときにRCP DeveloperやWindowBuilderが
引っかかりWindowTesterも知っていました。
WindowTesterのデモを見るとわかるとは思いますが、SWTBotの動作を
より実運用的にしたイメージです。
・http://www.instantiations.com/flash/wt_demo/record_playback_eclipse_test.html
・http://www.instantiations.com/flash/wt_demo/record_playback_rcp_test.html

SWTBotのレコード機能とgroovyをうまく使いこなせばある程度近いものは作れないかなぁ?
とは思ってみたりするんだけど、そんな時間がない。。。。。
SWTBotのレコード機能をちょっと調査してみたいです。


http://www.instantiations.com/mktg/windowtester-demo.html

2010年3月21日日曜日

eclipse 3.6(Helios)をインストールしてみた

eclipseのHelios(Modeling Tools)をインストールしてみました。
現在2010/03/20のバージョンはM6(03/12/2010)でAPI Freeze状態です。
GW前にはFeature Freezeになるそうです。

・GalileoとはCompatibilityがある。
・InternationalizationはLatin-1,DBCSロケールデフォルトサポート。ドイツ語、日本語は現在テスト中のこと。
・EMF QueryがM5で入っていないというMLで流れていたが、すでにM6では入っている。QVTは問題なく使えそう。OCLも入っている。
・subcripseも普通にインストールできた。
・GMFはデフォルトで入っていないため、インストールが必要(しかし更新サイトからのインストールが固まる)

とりあえず以下のパッケージがデフォルトで入っているようです。

org.eclipse.amalgam.discovery
org.eclipse.cvs 1.1.0
org.eclipse.emf.cdo.epp
org.eclipse.emf.compare.sdk
org.eclipse.emf.mint.sdk
org.eclipse.emf.query.sdk
org.eclipse.emf.sdk
org.eclipse.emf.transaction.sdk
org.eclipse.emf.validation.sdk
org.eclipse.epp.usagedata.feature
org.eclipse.equinox.p2.user.ui 1.1.0
org.eclipse.gef.sdk
org.eclipse.help 1.1.0
org.eclipse.jdt 3.6.0
org.eclipse.mylyn.bugzilla_feature
org.eclipse.mylyn.context_feature
org.eclipse.mylyn.ide_feature
org.eclipse.mylyn.java_feature
org.eclipse.mylyn.pde_feature
org.eclipse.mylyn.wikitext_feature
org.eclipse.mylyn_feature
org.eclipse.ocl.all.sdk
org.eclipse.pde 3.6.0
org.eclipse.rcp 3.6.0
org.eclipse.sdk 3.6.0
org.eclipse.uml2.sdk
org.eclipse.xsd.sdk

2010年3月16日火曜日

EMF Transaction

またまた新しい知識を得なければならなくなりました。
その名もEMF Transaction。

http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclipse.emf.doc/references/overview/EMF.html

概要を説明すると、EditingDomainをマルチスレッドアクセスでも整合性を保つようにDBのような
トランザクションの仕組みをEMFに取り込んだものである。
基本的にはトランザクションはコマンドをトランザクションとして処理を行う。



ざっくりな和訳


The transaction framework provides the capability of managing access to an editing domain
by multiple reading and writing threads. It also provides a facility to register and
share an editing domain amongst different clients and listeners. Resource set listeners
are defined in the transaction layer and are provided with notifications in batches.
The resource set listener has the option to append changes before the transaction is
committed (pre-commit) or receive only the notifications of transactions that were
validated and not rolled-back (post-commit). The following are the main extension
points and classes to be used with the transaction framework:


トランザクションフレームワークはマルチスレッドによるEditingDomainのR/Wのアクセス管理を可能にする。
異なるクライアント間でeditingDomainとリスナの共有と登録で実現できている。
リソースセットリスナはトランザクション層で定義されていて、
バッチの通知で提供されている。
リソースセットリスナは変更を追加するオプションを持っている。
トランザクションがコミットされる前やvalidateされたトランザクションや
ロールバックされていないトランザクションの通知を受け取る前に
次の拡張ポイントとクラスでトランザクションフレームワークが利用されている。