EMF Transactionについて
EMFのデータモデルをトランザクションを用いて、複数スレッドからのアクセスコントロールやデータの整合性(atomic)を守る仕組み。 EditingDomainを用いてやり取りを行います。
簡単な説明はざっくり飛ばします。参考サイトを読んでください。
予備知識:EditingDomain
editingDomainは相関のあるEMFモデルを含んでいるのとコマンドを管理するものです。モデルはリソースセットの形式で保持されていています。
コマンドとモデルの編集はドメインを経由して、コマンドスタックを使って行います。
EditingDomainの補足機能として、基本的なコマンドのオーバーライドが使えます(OverrideableCommand. を参照)
ドメインはgetParent,getChildrenメソッドの結果でモデルへ階層的に役割を課す。
これはネストしたオブジェクトの削除などに使うRemoveCommandなどの実装に便利である。
また、ネストしたコピーなどに使うCopyCommandも便利である。
クラス図的にはこんな感じ
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());
- }
コマンドオプション
コマンド実行に対して、色々オプションを付けて実行が行える。
* 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 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;
- }
- }
参考サイト