MPS 2024.1 ヘルプ

カスタム持続クックブック

このドキュメントでは、MPS にバンドルされている xmlPersistence サンプルを使用して、独自の永続化形式を定義、デプロイ、使用する方法を説明します。

カスタム永続性とは何ですか?

MPS は通常、モデルを独自の XML ベースの形式で保存します。ただし、モデルファイルを独自の形式でロードまたは保存したい場合があります。

スタブモデル

これらは読み取り専用モデルであり、通常はライブラリコードを表します。たとえば、MPS を利用して既存の言語の 1 つを記述したいとします。たとえば、BaseLanguage は Java の優れた説明です。このような場合、その元の言語用に作成されたライブラリには、MPS 内からアクセスできる必要があります。このようなライブラリのスタブモデルを作成するのに役立つのは、言語のスタブの側面です。スタブモデルは、MPS の外部のコードを参照する必要がある参照のターゲットとして使用されます。

独自のカスタム形式での言語の永続性

場合によっては、モデルのデフォルトの MPS 永続化形式が重すぎる場合や、MPS 以外のツールで永続化されたモデルを使用したい場合など、永続化形式をカスタマイズする必要があります。もう 1 つの便利な例: MPS で必要なのが、MPS エディターを使用して独自の DSL のファイルを編集することだけである場合、モデルをテキスト形式で保存して、任意のテキストエディターで編集できるようにすると便利です。

独自のカスタム形式での MPS モデルの一般的な永続性

MPS によってすぐに使用できる 3 つの形式よりも何らかの点で優れた汎用的な永続性を実装する場合。

これらの各ケースでは、わずかに異なる処理が必要です。

拡張アプローチ

一般に、カスタム永続性に取り組む方法は 2 つあります。

  • データソースが与えられたときに独自のモデルを作成するカスタム ModelFactory を提供します。

  • データソースを管理し、オンデマンドでこれらのデータソースの周囲にモデルを作成するカスタム ModelRoot を提供します。

用語

SModel および EditableSModel (org.jetbrains.mps.openapi.model)

MPS 内のモデルまたは編集可能なモデルを表すことができるインターフェース。永続ストレージからロードできます。編集可能なモデルは永続ストレージに保存できます。

注目すべき実装:

  • SModelBase- デフォルトの SModel 実装

  • EditableSModelBase- デフォルトの EditableSModel 実装

  • RegularModelDescriptor- スタブモデルのから拡張する必要があります

  • EditableModelDescriptor- カスタム永続性のためにから拡張する必要があります

SModelData (jetbrains.mps.extapi.model)

メモリ内のモデルの内容を表すインターフェース。それはそのルートとノードを保持し、操作することができます。

注目すべき実装:

  • jetbrains.mps.smodel.SModel- デフォルトの万能実装

  • jetbrains.mps.smodel.DefaultSModel- 「ヘッダー」を使用して読み取りを最適化できる実装。

データソース (org.jetbrains.mps.openapi.persistence)

モデルを表す永続化されたデータの場所を表します。ファイル、インターネットコンテンツ、データベースコンテンツは、考えられるデータソースの例です。FileDataSource と StreamDataSource は、カスタム永続性で最も頻繁に使用される実装です。

DataSourceType (org.jetbrains.mps.openapi.persistence.datasource)

データソースの種類を一意に識別します。FileExtensionDataSourceType 実装クラスは、ファイルに添付されたデータソースを表すために使用されます。

ModelRoot (org.jetbrains.mps.openapi.persistence)

ファイルやディレクトリなど、関連する物理的なオリジンに由来する論理的に接続されたモデルのグループを表します。これらのモデルを管理します。モデルを作成、ロード、保存します。

注目すべき実装:

  • ModelRootBase

  • FileBasedModelRoot

メメント

セッション間で情報を保持する階層構成情報ストレージの一般的な抽象化。Mementos は、本質的に、階層的に編成されたハッシュマップに似ています。

SourceRootKind

モデルルートにはいくつかの種類があります。通常はソース、テスト、除外です。このインターフェースは、必要な / サポートされている種類のルートを通信するために使用されます。SourceTootKinds 列挙には、いくつかの事前定義された種類が含まれています。

ModelFactory (org.jetbrains.mps.openapi.persistence)

データソースのロード / 保存 / アップグレード戦略を表します。その load()create()、および save() メソッドは、SModel および DataSource インターフェースのインスタンスで機能します。

ModelRootFactory

モデルルートのファクトリ。有効にするには、plugin.xml ファイルに登録する必要があります。

ModelRootEntry

新しいモデルルートが指定されているときにユーザーと対話する UI 要素。

ModelRootEntryFactory

ModelRootEntries のファクトリ。有効にするには、plugin.xml ファイルに登録する必要があります。

ModelLoadResult (jetbrains.mps.smodel)

モデルのロードの結果を表します。ロードされた ModelData とロードされたモデルデータの状態を保持します (jetbrains.mps.smodel.loading.ModelLoadingState)

モデル ID

モデルを一意に識別します。他のモデルは、ID を使用して参照モデルを表します。

2 つのオプションがあります:

  • モデルは、データソースの場所など、再現可能な事実から ID を導出できます。

  • モデルは任意の ID を持ち、それをデータソース(通常はファイルの先頭)に格納できます。モデルは、ロードされるたびに ID を再構築する必要があります。

PersistenceFacade.createModelId() を使用して、説明文字列から ID を作成できます。文字列は、特別な形式 'factoryDesignator:text'(たとえば、'path:a/b/c.xml')である必要があります。ここ

  • factoryDesignator は、ID の構築に使用する ID ファクトリの「識別」です。これらのファクトリは、PersistenceFacade.setModelIdFactory() メソッドを介して登録されている必要があります。

    すでに利用可能ないくつかのファクトリがあります:

    • 'i'(IntegerSModelId)- モデルに整数値('text' から 16 進数として解析される)を与える IntegerSModelId を作成します。モデルは、ID 自体を保持する必要があります。

    • 'path'(RelativePathSModelId)-'text' で指定された相対パスでモデルを識別する RelativePathSModelId を作成します。 ID は、モデルのデータソースパスから再構築できます。

    • 'r' (RegularSModelId)-'text' から解析された UUID を使用します。モデルは ide の格納を処理する必要があります。

    • 'f' (ForeignSModelId)-'text' に直接格納されている文字列を使用します。モデルは、ide の格納を処理する必要があります。

  • text-ID を構築するためのシード情報としてファクトリに渡すテキスト。

SModelName (org.jetbrains.mps.openapi.model)

モデルの名前(たとえば、jetbrains.mps.samples.xmlPersistence @ generator)を表します。これは通常、いくつかの部分で構成されます。

  • 名前空間 (jetbrains.mps.samples)

  • 簡単な名前 (xmlPersistence)

  • ステレオタイプ (@generator)

モデルリファレンス

含まれているモジュール内のモデルを表します。これらは内部 API の一部であり、最終的にはパブリック API から削除する必要があります。

PersistenceFacade

モデルとモデルルートファクトリのレジストリを表すシングルトンクラス。また、文字列を model.module 参照およびノード ID との間で変換するためのヘルパーメソッドも提供します。

ModelSaveException

モデルが永続性フォーマットに適合しない場合にスローされます。

ModelLoadException

永続性フォーマットに、目的のモデルを構築するために必要なすべてのデータが含まれていない場合にスローされます。

ModelReadException

モデルのロード時にエラーを報告するために使用されます。

問題 (org.jetbrains.mps.openapi.model.SModel)

永続性の問題を表します。これは通常、例外を通じて報告され、MPS は最終的にユーザーに問題を視覚化します。問題の場所とノードへの参照を保持します。

注目すべき実装:

  • jetbrains.mps.extapi.model.PersistenceProblem

サンプルの xml モデルファクトリプロジェクトを見回す

このプロジェクトがビルドされ、生成されたプラグインが MPS にデプロイされると、MPS は、モデルが作成されるときに、モデルに新しいタイプの永続性を提供します。この新しい永続性により、jetbrains.mps.xml.core 言語のみがモデルで使用され、モデルが単一の XML ドキュメントに永続化されます。

MPS でカスタム永続プラグインを使用する

生成されたプラグインを MPS にインストールした後、新しいモデルを作成するときに、それらの XML ファイル永続性プロバイダーを指定できます。

cp8.png

XmlPersistenceModelDescriptor.importedLanguageIds() メソッドで指定するのと同じように、新しいモデルには、使用言語として jetbrains.mps.core.xml 言語が追加され、空のルートノードが追加されます。

cp9.png
cp10.png

ルートノードに入力したものはすべて、対応する xml ファイルにすぐに保持されます。基になる xml ファイルへの変更は、エディターで開くとモデルに反映されます。

cp11.png
cp12.png

プロジェクト構造

xmlPersistence サンプルプロジェクトを開くと、3 つのソリューションが表示され、それぞれがパズルで別々のロールを果たします。

cp1.png

xmlPersistence モジュールは実際の永続性ロジックを定義し、xmlPersistence.build にはビルドスクリプトが含まれ、xmlPersistence.ideaPlugin にはカスタマイズされたプラグイン記述子が含まれます。ビルドスクリプトは通常、適切なプラグイン記述子を独自に提供しますが、今回は記述子をカスタマイズする必要があるため、プロジェクトに明示的に含めます。

cp4.png

プラグイン記述子は、標準のプラグイン情報を提供するだけでなく、jetbrains.mps.persistence.XmlModelPersistence クラスを mps.ModelFactoryProvider として登録します。これは、明示的なプラグイン記述子を提供する必要がある追加のビットです。

cp5.png

永続性フォーマット

xmlPersistence モジュールは、永続性ロジックを実装します。MPS の永続性タイプはモデルごとのレベルに設定されています。単純化したケースでは、サンプルは、jetbrains.mps.core.xml 言語の単一の XMLFile ルート要素に制限されているモデルをプレーンな XML ドキュメントに格納できます。実際の XML 解析ロジックは XmlConverter クラスにあり、XmlModelPersistence クラスは MPS の内部動作にフックするための基本的なインターフェースを実装しています。

XmlPersistenceModelDescriptor

このクラスは EditableModelDescriptor を拡張し、MPS のモデルを表します。

これらは注目すべき点です:

  • importedLanguageIds() メソッドは、このモデルのインスタンスに jetbrains.mps.core.xml 言語がインポートされていることを確認します。

  • save() メソッドは、モデル内の単一のルートを想定しており、モデルファイルに永続化されます。また、StreamDataSource を想定しています。jetbrains.mps.core.xml 言語のモデルを xml テキストに変換するヘルパー RegularTextUnit クラスを利用します。

  • createModel() メソッドは、モデルファイルが存在するかどうかを確認します。

    • そうでない場合は、新しい空のメモリ内モデル(SModel インスタンス)が返されます。

    • ファイルが存在する場合は、読み取り、解析され、単一のルート XmlFile を含む SModel インスタンスに変換されます。

XmlModelPersistence

このクラスは ModelFactory を拡張し、XmlPersistenceModelDescriptor インスタンスの作成と永続化のライフサイクルを処理します。

supports()

supports() メソッドは、データソースのタイプをチェックします。FileSystemBasedDataSourceStreamDataSource のみを同時に受け入れます。ClassCastExceptions がこれらのメソッド内から発生しないようにするには、永続性に関連するすべてのメソッドからメソッドを手動で呼び出す必要があります。

getPreferredDataSourceTypes()

このメソッドは、この ModelFactory が処理する DataSourceTypes のコレクションを返します。この実装は、ファイル拡張子に基づくタイプである独自の XML_TYPE を返します。

cp101.png

getType()

このメソッドは、モデルファクトリを記述する ModelFactoryType のインスタンスを返します。MPS には 3 つの組み込み型があり、すべて PreinstalledModelFactoryTypes 列挙型で定義されています。

cp102.png

モデルファクトリは独自のタイプを定義しています。

cp103.png

getFormatTitle() メソッドは、返される文字列が将来のユーザーにストレージ形式を表すために使用されるため、ここで特にメンションする価値があります。

create()

このメソッドは、XmlPersistenceModelDescriptor の新しいインスタンスを作成し、パスベースの ID で初期化します。次に、モデルの名前と同じ名前の新しいルートノードを追加して、空のモデルを表します。

load()

このメソッドは、XmlPersistenceModelDescriptor の新しいインスタンスを作成し、パスベースの ID で初期化します。この時点では、モデル自体はロードされていません。

save()

このメソッドは、モデルの save() メソッドに委譲します。

サンプルスタブプロジェクトを見回す

propertyPersistence サンプルプロジェクトは、モデルルートを使用してプロパティファイルのスタブモデルを実装する方法を示しています。ディスク上のフォルダーはモデルになり、その中のプロパティファイルはこれらのモデルのルートノードになります。

カスタムスタブ永続性の使用

プラグインが MPS にデプロイされると、ユーザーはソリューションに新しいタイプのモデルルート(プロパティファイル)を設定できるようになります。

cp104.png

このモデルルートを選択すると、プロパティファイル(.properties 拡張子を含むファイル)を含む、ユーザーが「ソース」としてマークしたすべてのフォルダー(右側のパネル)がモデルになります。

cp105.png

これらのモデル(上のイメージでは「client」および「server」という名前)は、プロパティファイルのスタブモデルです。それらは読み取り専用であり、プロジェクト内の他のモデルが参照できます。jetbrains.mps.samples.PropertyDefinition と呼ばれる MPS でプロパティファイルを記述するために使用される言語も、propertyPersistence プラグインの一部です。

cp106.png

プラグインプロジェクトの構造

プロジェクトには、jetbrains.mps.samples.PropertyDefinition 言語と、単純なプロパティ定義で言語をテストするためのサンドボックスソリューションが含まれています。

cp107.png

jetbrains.mps.samples.propertyPersistence.build ソリューションには、3 つのモジュールを MPS プラグインにパッケージ化するビルドスクリプトが含まれています。

cp108.png

カスタム plugin.xml 定義が使用されます。

cp109.png

カスタムファクトリを mps.modelRootFactory として登録し、mps.modelRootEntry を MPS の拡張機能として登録して、有効にします。さらに、パッケージ化された言語の場所は mps.languageLibrary で指定されます。

cp110.png

スタブモデルの実装

必要なすべてのクラスの実際の実装は、jetbrains.mps.samples.propertyPersistenceDef ソリューションにあります。

cp111.png

各クラスには明確な目的があります。

  • PropertyFilesDataSource - 唯一の指定は、現在のフォルダーから .properties 拡張子を持つファイルは、データソースに含まれるべきであるということを FolderDataSource 拡張

  • PropertyFilesStubModelRootEntryFactory - MPS から要求されたときに PropertyFilesStubModelRootEntry のインスタンスを作成するファクトリ。

  • PropertyFilesStubModelRootEntry - ユーザーがモジュールの UI でこの種のモデルルートを指定および構成できるようにします。モデルルートはファイルとフォルダーを使用するため、このクラスは FileBasedModelRootEntry にのみ委譲します。

  • PropertyFilesStubModelDescriptor - RegularModelDescriptor を拡張するモデルの実装。プロパティファイルを解析し、ルートノードを作成して、新しく作成したモデルに入力します。xmlPersistence と同様に、モデル記述子クラスも、作成時に適切な言語(jetbrains.mps.samples.PropertyDefinition)がモデルにインポートされることを保証します。スタブモデルは読み取り専用であるため、モードを保存する必要はありません。

  • PropertyFilesStubModelRootFactory - MPS から要求されたときに PropertyFilesStubModelRoots のインスタンスを作成するファクトリ。

  • PropertyFilesStubModelRoot - モデルルートの実際の実装。FileBasedModelRoot を拡張します

PropertyFilesStubModelRoot

このクラスの詳細:

  • loadModels()- このメソッドは、ユーザーによって SOURCE としてマークされたすべてのディレクトリを取得し、ディレクトリごとに PropertyFilesStubModelDescriptor インスタンスを再帰的に作成します。

  • getType()- このメソッドは、ルートタイプの文字列識別子を返します。識別子は、関連するファクトリを識別するために plugin.xml で使用されます。

  • getSupportedFileKinds1() - モジュール設定ダイアログでモデルルートを設定するときに、ユーザーがファイルとディレクトリをマークするために選択できる、サポートされているすべてのファイルの種類(SOURCES、TESTS、EXCLUDED など)を返します。

  • load(Memento) - メメントからモデルルートのパスを読み取ります。以前は親の FileBasedModelRoot クラスによって保存されているため、メモリに存在することに依存しています。次に、パスを使用して、contentDirectory とソースルートのプロパティを設定します。注: この方法は、mementos での作業の例として役立ちます。実際、この例では、親クラスがすでに memento を読み取り、contentDirectory とソースルートを設定しているため、これは必要ありません。

MPS プラグインをビルドする

xmlPersistencePlugin プロジェクトと propertyPersistencePlugin プロジェクトの両方に、必須モジュールを IDEA/MPS プラグインに圧縮する標準のビルドスクリプトが含まれています。

cp4.png

ビルドスクリプトを再構築すると、ビルドスクリプトを実行して、プラグインを生成できるようになります。

cp6.png

これによりプラグインが作成され、ユーザーに配布できます。

プラグインのデバッグ

MPS は、MPS で直接、新しい永続性の実装をすぐにテストしたい場合にも役立ちます。プラグインのデプロイテンプレートから実行構成を作成します。

cp13.png

次に、(プロジェクトを再構築してビルドスクリプトを再実行した後)プラグインを実行構成でデプロイするように指定します。

cp14.png

最後に、構成を実行してプラグインを MPS にインストールします(MPS が再起動します)。

この手順を実行すると、モデルにカスタム永続性プロバイダーを使用して、期待どおりに動作するかどうかをテストできるようになります。

プラグインは、Windows の場合はホームフォルダーの .MPSxxx サブディレクトリに、Mac の場合は $HOME/Library/Application Support/MPSxxx にインストールされます。プラグインマネージャー UI を使用するか、プラグインフォルダーを手動で削除することにより、プラグインをアンインストールまたは無効にすることができます。

IntelliJ IDEA プラグインをビルドする

IntelliJ IDEA プラグインの構築は、MPS プラグインの構築とそれほど違いはありません。あなただけのビルドスクリプトで mpsPluginMPS からの依存関係を変更し、MPS の IDEA プラグインがデプロイされてきたどこにアーティファクトの場所を設定する必要があります。

cp7.png

プロジェクトをリビルドしてビルドスクリプトを実行した後、IDEA にデプロイするプラグインを取得します。

IntelliJ IDEA でカスタム XML 永続性プラグインを使用する

IDEA プラグインを使用すると、XML ドキュメントを MPS ベースの射影エディターで編集し、プレーン XML ファイルに保存することもできます。.xml ファイルは IDEA の XML エディターに関連付けられているため、XML ファイルをクリックすると、デフォルトの IDEA エディターが開きます。

cp20.png

ただし、sample.xml ファイルは構成された MPS モデルのルートにあるため、MPS はカスタム永続プラグインを呼び出して、そこからモデルを構築します。Alt+Insert を押して名前でクラスを開くと、サンプルモデルを開くオプションが表示されます。

cp21.png

次に、射影エディターで編集し、変更を元の xml ファイルに保持します。

cp22.png