astah*で作成されたモデルをJava APIで解析・編集する

組み込みのモデリングツールとして一般的なEnterprise Architectのファイルは、zipファイルとして解凍すると、テキストベースのXMLとして、モデルデータの各種解析や編集が可能になるのが一部で知られています。
一方で同じく組み込み一般的なAstah*の方は、zipファイルとして解凍は可能なものの、中身はバイナリファイルでEAのような解析編集が難しくなっています。ただAPIが提供されていて、その活用で柔軟な処理を行えます。今回はそのAPIの使い方について触れたいと思います。

概要

astah* APIJavaAPIです。最新版だと無料のCommunity版でもモデルの解析や編集が可能になっています。
http://astah.change-vision.com/ja/astah-api.html などに情報がまとまっています。

astah* APIライブラリの追加

astah* APIを使用する際は、Community版の場合、astah-communityとastah-apiの2つが必要です。Mac環境のIntelliJだと、ProjectSettingのLibrariesに以下を追加します。

/Applications/astah community/astah community.app/Contents/Java/astah-community.jar
/Applications/astah community/astah community.app/Contents/Java/astah-api.jar

実装

ProjectAccessorを使ってastahのファイルを操作します。細かな仕様は以下などで情報が提供されています。

http://astah.change-vision.com/ja/astah-api.html
http://members.change-vision.com/javadoc/astah-api/7_1_0/api/ja/doc/index.html

実装として、テスト設計の補助を想定して、astah*の状態遷移図のトリガイベントを網羅的にピックアップするコードを書いてみました。

//TARGET_FILE内で作成されている、TARGET_SMDの名前のステートマシン図のトリガイベントをすべて表示
import com.change_vision.jude.api.inf.model.*;
import com.change_vision.jude.api.inf.project.ProjectAccessor;
import com.change_vision.jude.api.inf.AstahAPI;

public class PrintStateTransitions {
    private static final String TARGET_FILE = "/Users/ih/Desktop/sample.asta";
    private static final String TARGET_SMD = "sampleStateMachine";

    public static void main(String[] args) {
        ProjectAccessor prjAccessor = null;
        try {
            prjAccessor = AstahAPI.getAstahAPI().getProjectAccessor();
            prjAccessor.open(TARGET_FILE, true, false, true);
            checkStateTransitions(prjAccessor.getProject());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (prjAccessor != null) {
                prjAccessor.close();
            }
        }
    }
    private static void checkStateTransitions(IPackage iPackage) {
        INamedElement[] ine = iPackage.getOwnedElements();
        for (int ip = 0; ip < ine.length; ip++) {
            INamedElement[] idg = ine[ip].getDiagrams();
            for (int id = 0; id < idg.length; id++) {
                if (idg[id] instanceof IStateMachineDiagram && idg[id].getName().equals(TARGET_SMD)) {
                    printAllStateTransitions((IStateMachineDiagram)idg[id]);
                }
            }
            if (ine[ip] instanceof IPackage) {
                // 入れ子のパッケージ構造を再帰処理
                System.out.println();
                IPackage iChildPackage = (IPackage)ine[ip];
                checkStateTransitions(iChildPackage);
            }
        }
    }

    private static void printAllStateTransitions(IStateMachineDiagram ismd) {
        ITransition[] it = ismd.getStateMachine().getTransitions();
        System.out.print(ismd.getName() + ":");
        for (int i = 0; i < it.length; i++) {
            System.out.println("  " + it[i].getName());
        }
    }
}