DSL Designerで構築したDSL Editorで描いたモデル内容へのアクセス方法

Visula Studio 2005 SDKをVisual Studio 2005(Professional Edition以上)にインストールすると、DSL Toolkitという、独自のモデル(DSL:Domain Specific Language)向けモデルエディタを構築するためのツールが使えるようになります。
※DSL ToolkitはVisual Studio 2008ベータ版でも使えます。

独自のモデルエディタの構築方法は、https://www.microsoft.com/japan/msdn/architecture/dsl/default.aspxの最後の方で紹介されている、3つのホワイトペーパー

  1. DSL Toolsのライフサイクル全体の作業に関するホワイトペーパー
  2. DSL Toolsで作成したグラフィカルデザイナのカスタマイズ方法について
  3. DSL Toolsで表現できるグラフィカル表現とモデルの関係について

を参考にしてください。では、構築したモデルエディタを使って描いたモデルから、モデルの定義情報を取り出して、様々な別の成果物に変換する方法を紹介していきましょう。

モデルエディタは、モデルの意味を定義する“メタモデル”とモデルの見栄えを定義する“グラフィカル要素”の二つを定義することによって構築することができます。DSL Toolkitでメタモデルを定義すると、モデルにアクセスするためのライブラリが自動的に生成されます。このライブラリを利用することにより、モデルエディタを使って描いたモデルの記述内容を全てプログラマブルに参照することができます。
モデルの内容を参照するライブラリは、メタモデルの定義のときに指定した、名前空間で定義されます。その中に、メタモデルのルートモデルのドメインクラスの名前を持つクラスが用意されています。モデルエディタを使って描いた各モデル図の内容は、このルートモデルを通じて参照することが可能です。
また、メタモデル上に定義されたドメインクラスは、それぞれメタモデル上で定義されているドメインクラス名と同じ名前のクラスが、自動的に同じ名前空間で生成されています。
加えて、メタモデル上で定義されたDomain RelationshipのRole名と同じ名前のプロパティがそのRole名が付いている側のドメインクラスから生成されたクラスに用意されています。
例えば、前述のホワイトペーパー1で説明されている例の場合では、名前空間がFabrikam.DSL、ルートモデルがWizardUIPModelという名前になっています。このクラスには、メタモデル上で定義されている、WizardUIPModelとWizardPageElement間のEmbedding RelationshipのWizardUIPModel側に記載された”Elements”というロールに対応した、”Elements”というプロパティがあり、WizardUIPModelのオブジェクトのElementsプロパティをコールすると、WizardUIPModelオブジェクト内で定義されているWizardPageElementオブジェクトのリストを取り出すことができます。
これらメタモデル定義から生成されるクラス群は、DSL DesignerでSolutionを作成した際にそのSolution内に用意されるDslプロジェクトのGeneratedCodeフォルダー内に、密かに生成されているDomainClasses.csで定義されています。

では、以上を踏まえ、WizardUIPのモデルエディタで作成されたモデルファイルを読み込み、モデルの記述内容を取り出すサンプルコードを紹介しましょう。モデルファイルの名前を、ModelFile.uipと仮定します。

StringBuffer buf = new StringBuffer();using (Store store = new Store()){    store.LoadDomainModels(        typeof(CoreDesignSurfaceDomainModel),        typeof(WizardUIP)));    using (Transaction t = store.TransactionManager.BeginTransaction("LoadModel"))    {        WizardUIPModel root = WizardUIPSerializationHelper.Instance.LoadModel(store,"ModelFile.uip",null,null);        buf.AppendLine("**** WizardUIP Model Contents ****");        foreach ( WizardPageElement wpe in root.Elements )        {            if (wpe is WizardPage)            {                WizardPage wp = wpe as WizardPage;                buf.AppendLine("WizardPage[name:" + wp.Name + "]");                foreach ( Field field in wp.Fields )                {                    buf.AppendLine("    Field[name:" + field.Name + "]");                }            }            else if (wpe is Condition)            {                Condition c = wpe as Condition;                buf.AppendLine("Condition[name:" + c.Name + "]");                foreach (WizardPageElement nextWPE in c.Next)                {                    Transition transition = Transition.GetLink(c, nextWPE);                    buf.AppendLine("    - Next[guard:" + transition.Guard + "] -> WizardPageElement[name" + nextWPE.Name +"]");                }            }        }    }}

サンプルコードの、Store、及び、Transactionは、Microsoft.VisualStudio.Modelingの名前空間で用意されている、モデルの内容にアクセスするためのクラスです。Storeはモデルの格納機能を提供し、Transactionは、一つのモデルに同時に複数の読み書きを行うときのトランザクション機能を提供します。モデルに変更を加えた場合には、Transaction.Commitメソッドをコールすることによって変更が確定します。また、Transaction.Rollbackメソッドをコールすることにより、モデルへの変更をキャンセルすることも可能です。
また、Domain Relationshipへの参照を取得するには、Domain Relationshipをもとに生成された同名のクラスのGetLinkメソッドを使います。(他にもっとスマートな方法は?)
上のサンプルコードを前述のホワイトペーパー1のPage75に記載の図3.2.3-1に出てくるサンプルのダイアグラムで実行すると、bufの中身は、以下のようなテキストになります。
※順番はモデルを描いた時の手順に依存

**** WizardUIP Model Contents ****WizardPage[name:SearchForRooms]    Field[name:StartDate]    Field[name:EndDate]    Field[name:People]WizardPage[name:NotFound]Condition[name:Room found?]    - Next[guard:true] -> WizardPageElement[name:FoundRoom]・・・・ 以下省略

以上、DSLエディタで描いたモデルの内容をアクセスする方法を説明してきました。上のサンプルコードでは、bufをファイルに保存すれば、テキストファイルが出来上がります。このようなプログラムを書くことにより、モデルの内容をテキストファイルに変換することができます。非常に自然なことですが、テキストに変換する過程で、様々な文字列の付加や、モデル定義の内容の変換が可能なので、プログラムをはじめとする様々なテキストに変換できることがお分かりでしょう。
しかし、サンプルコードから、bufに格納されるようなテキストに変換される事が直観的には分かり難いことにもお気づきでしょう。モデルからテキストを生成する、より直観的な方法は、T4 Templateを使うことです。
サンプルコードで紹介したプログラミングによる変換は、CodeDOMを利用したコードツリーへの変換や、XML Processorを用いたXML DOMツリーへの変換、他のDSL Modelへの変換向きです。

T4 TemplateによるDSLモデルからテキストへの変換方法は別のページで紹介します。

 以上、説明した内容は、Windows XP Embeddedや、Windows XP、Vistaを特定の組込みシステム専用で使う場合のアプリケーション開発で実際に活用可能です。