astah*で作成されたモデルをJavaのプログラムで解析・編集する

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