MPS 2020.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 およびデータソースインターフェースのインスタンスで機能します。

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

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

cp9

cp10

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

cp11
cp12

プロジェクト構造

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

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

cp4

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

cp5

永続性フォーマット

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

プラグイン ID

xmlPersistence モジュールでアイデアプラグインが有効になっていて、モジュールプロパティのアイデアプラグインタブでプラグイン ID が指定されていることに注意してください。

cp3

識別子は、xmlPersistence.ideaPlugin ソリューション内のプラグイン(xml)記述子で宣言されたプラグイン識別子と一致する必要があります。IDEA プラグイン識別子を xmlPersistence ソリューションのプロパティに追加して、ソリューションがプラグインの一部であり、プラグインのクラスを参照(または実行時にロード)できることを指定します。

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

getType()

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

cp102
モデルファクトリは独自のタイプを定義しています。
cp103
getFormatTitle() メソッドは、ここで特にメンションする価値があります。返される文字列は、将来のユーザーにストレージ形式を表すために使用されるためです。

create()

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

load()

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

save()

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

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

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

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

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

cp104
このモデルルートを選択すると、プロパティファイル(.properties 拡張子を含むファイル)を含む、ユーザーが「ソース」としてマークしたすべてのフォルダー(右側のパネル)がモデルになります。
cp105
これらのモデル(上のイメージでは「client」および「server」という名前)は、プロパティファイルのスタブモデルです。それらは読み取り専用であり、プロジェクト内の他のモデルが参照できます。MPS でプロパティファイルを記述するために使用される jetbrains.mps.samples.PropertyDefinition と呼ばれる言語も、propertyPersistence プラグインの一部です。
cp106

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

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

cp107
jetbrains.mps.samples.propertyPersistence.build ソリューションには、3 つのモジュールを MPS プラグインにパッケージ化するビルドスクリプトが含まれています。
cp108
カスタム plugin.xml 定義が使用されます。
cp109
カスタムファクトリを mps.modelRootFactory および mps.modelRootEntry として MPS の拡張として登録し、有効にすることができます。さらに、パッケージ化された言語の場所は mps.languageLibrary で指定されます。
cp110

スタブモデルの実装

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

cp111
モジュールには、Idea プラグインファセットが設定されている必要があります。
cp112
プラグイン ID を指定する必要があります。
cp113
各クラスには明確な目的があります。
  • 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) - memento からモデルルートのパスを読み取ります。これは以前に親 FileBasedModelRoot クラスによって保存されているため、メモリに存在することに依存しています。次に、パスを使用して、contentDirectory とソースルートのプロパティを設定します。注:この方法は、記念品を使用する方法を説明するものです。実際、この例では、親クラスがすでに memento を読み取り、contentDirectory とソースルートを設定しているため、これは必要ありません。

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

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

cp4

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

cp6

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

プラグインのデバッグ

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

cp13

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

cp14

最後に、構成を実行してプラグインを MPS にインストールします(MPS が再起動します)。
この手順の後、モデルにカスタム永続性プロバイダーを使用して、期待どおりに動作するかどうかをテストできるようになります。

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

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

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

cp7

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

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

IDEA プラグインは、MPS ベースのプロジェクションエディターで XML ドキュメントを編集し、プレーンな xml ファイルに永続化することもできます。.xml ファイルは IDEA の XML エディターに関連付けられているため、XML ファイルをクリックすると、デフォルトの IDEA のエディターが開きます。

cp20

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

cp21

次に、プロジェクションエディターで編集し、変更を元の xml ファイルに保持します。

cp22