MPS 2020.1 ヘルプ

オープン API - コードからモデルにアクセスする

言語レポジトリ、プロジェクトモジュール、言語、モデルは、Open API を介してプログラム的に便利にアクセスできます。Open API を使用すると、モデルへのアクセスを制御したり、永続化などのいくつかの側面について独自の実装を提供したりすることもできます。

これら 2 つの使用箇所の種類について個別に説明します。

注意:このドキュメントは Open API の哲学の一般的な概要を説明し、API への便利なリンクを提供することを目的としています。使い方の技術的な詳細については相談してください .

Open API を使用する

API は org.jetbrains.mps.openapi パッケージにあり、いくつかのサブパッケージに分かれています。

  • event - モデルへの変更のためのイベントクラスを含みます

  • language - コンパイルされた言語にアクセスし、それらの構造を調べるための一連のインターフェースを提供します。

  • model - モデルを調べて修正する方法を提供します (AST)

  • module - モデルを論理的に整理する手段としてリポジトリとモジュールを抽象化します

  • 永続性 - モデルの永続化メカニズムを拡張およびカスタマイズするために必要なインターフェースを保持します

  • repository - リポジトリ固有のイベントのリスナーを保持します

  • util - 長期的なアクションを UI 進捗インジケータにフックするための ProgressMonitor などのユーティリティクラスが含まれています

API はこれらの論理要素を認識します。上の要素はリストの要素を含みます。

  • リポジトリ

  • 新規モジュール

  • モデル

  • ノード

  • プロパティ、参照

Open API は、上記の要素に直交するメタ構造も認識します。メタ構造は次の重要な要素で構成されています。

  • 言語

  • 概念、列挙

  • メンバー (プロパティ、リンク、列挙リテラルなど)

ノードには関連する概念があります。概念は言語に属します。言語は、言語ユーザーに言語を詳細に調査する方法を提供するために、それらが由来するソースモジュールへのポインタを保持することができます。

API を使用すると、リポジトリ全体を参照して、そのモジュール、そのモデル、それらのモデルの構築元となるノードを調査できます。さらに、API には、リポジトリ内の場所に関係なく、要素の使用箇所を検索したり、名前で要素を検索したりする機能があります。これらの要素すべてを変更したり、変更を保存したり、永続的な記憶域から再ロードしたりすることもできます。API は、メモリ内のモデルとその永続的記憶域に衝突する変更を検出します。

いくつかの API の詳細

smodel 型から Open API 型へのダウンキャストは、smodel 型の 1 つに入力された式を Open API 型に入力された変数に割り当てると自動的に行われます。

node<> n1 = ... SNode n2 = n1

逆キャストを行うと、アップキャストが行われます。
SNode n1 = ... node<> n2 = n1

メタモデルレベル

SAbstractConcept

  • SConceptSConceptInterface の両方に共通のスーパークラス

  • 概念の特性包含リンク、および参照リンクへのアクセスを提供します

  • getProperties()getContainmentLinks() および getReferenceLinks() メソッドを使用して、それぞれ概念のプロパティ、包含および参照リンクを取得します。

SPROPERTY

  • プロパティを表します

  • 概念間の包含(親子)関係を表します

  • 概念間の明示的な(参照)関係を表します

モデルレベル

スノード

  • モデル内の個々のノードを表します

SR 基準

  • ノード間の参照を表します

SNodeReference

  • 永続化してリポジトリからノードを取得するために繰り返し使用できるノードへの一意のグローバル参照

オープン API の利用パターン

プロパティを設定する

Iterable<SProperty> properties = concept/Shape/.getProperties();  list<SProperty> props = new arraylist<SProperty>(copy: properties);  currentNode/.setProperty(props.findFirst({~it => it.getName() :eq: "foo"; }), "value");

子供を追加する

Iterable<SContainmentLink> containmentLinks = concept/Shape/.getContainmentLinks();  list<SContainmentLink> containments = new arraylist<SContainmentLink>(copy: containmentLinks); currentNode/.addChild(containmentLinks.findFirst(...), childNode);

コマンドを使用する

Open API はモデルを変更する手段も提供します。変更は、処理のためにリポジトリに渡されるコマンドとして実行する必要があります。典型的なモデル変更 / 編集アクションは未完了 / 再実行可能ですが、モジュール構造に大きな変更を加えるアクションはできません。変更には 3 種類あります。

  1. モデルとノードは、元に戻すことができるアクションによって変更できます。

  2. モジュール、そのプロパティ、依存関係は、リポジトリコマンドを介して実行できます。

  3. そのような VCS の更新または完全なプロジェクトの再ロードなどのプロジェクトに根本的な変化が、外部の更新アクションを実行する必要がある - ないノードレベルの通知は、このような場合には焼成されていない、唯一のモデルは、置換またはモジュールは、通知がトリガされる変化しました

タイプに応じたコマンドには、モデルの変更を開始する前に、必要なすべての読み取りまたは書き込み権限が自動的に割り当てられます。変更通知は、ノード、モデル、モジュール、またはリポジトリレベルの登録済みリスナーに発行されます。

同時アクセス

Open API は同時アクセス用に設計されており、提供されている同期メカニズムが呼び出しコードによって正しく利用されていれば、Open API を介してモデルに同時にアクセスする複数のスレッドを正しく処理します。Open API は、不適切に同期された要求をすべて拒否し、それによってモデルの整合性を維持します。

より具体的には、操作を実行する前に読み取りまたは書き込みアクションを取得する必要があります。そうしないと、コードから例外が発生します。

リポジトリ(英語)を使用してください。getRepositoryAccess()(英語) .applyChanges() を使用して、変更内容をリポジトリリポジトリ(英語)全体に適用します。getModelAccess()(英語) .runXXXAction() で読み取り / 書き込みアクションを実行し、リポジトリ(英語)を実行します。コマンドを実行するための getModelAccess()(英語) .executeCommand()。コマンドはすべての書き込み権限を自動的に取得するため、常にリポジトリへの排他アクセス権を取得します。どちらの方法でも、EDT 内で提供されたアクションを非同期的に実行する非同期バリアントが提供されています。

モデルロックの例

リポジトリはモデルのロックを開始するのに適した場所です。EditorContext などのコンテキストオブジェクトからリポジトリ参照を取得できます。あなたのコードは ModelAccess を取得してロックを取得することができます。

(node, editorContext)->JComponent {  //get ModelAccess from the context final ModelAccess modelAccess = editorContext.getRepository().getModelAccess();    //read the model final boolean[] active = new boolean[]{false}; modelAccess.runReadAction(new Runnable() { public void run() { active[0] = node.showActive; } }); final JButton button = new JButton(active[0] ? "Show all" : "Show active"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent p0) {  //update the model in an action, that can be undone modelAccess.executeCommand(new Runnable() { public void run() { node.showActive = !node.showActive; } }); } }); return button; }  

カスタム永続化

デフォルトでは、MPS はモデルをフラットファイルとして XML またはバイナリ形式で保存します。モデルの保存方法をカスタマイズできるように、Open API にはいくつかのオプションがあります。

代替ファイル形式

フラットファイルに格納されているモデルデータの形式を変更することは、モデルの永続性をカスタマイズする最も簡単な方法です。(PersistenceFacade(英語) を通して)選んだファイル拡張子で独自の ModelFactory(英語) を単に登録すれば、そのファイル拡張子が発見されるときはいつでも MPS はあなたのカスタム SModel(英語) インプリメンテーションを具体化するためにそのファクトリを使います。SModelIdFactory(英語)SNodeIdFactory(英語) の独自の実装を提供し登録する必要もあります。

代替保管

さらに冒険的で、たとえばデータベースや他の非ファイルストレージからあなたのモデルをロードしたいなら、カスタム ModelRoot(英語) インスタンスを作成できる ModelRootFactory(英語) をさらに提供する必要があります。これらのモデルルートは、モデルをロード / 保存するために、選択したストレージのすべての詳細を処理します。通常、ユーザーがデータベースの場所、ユーザー名などのデータソースの詳細を構成できるようにするための UI をバンドルする必要もあります。

カスタム検索の使い方とナビゲーションの参加者

FindUsagesParticipant(英語) のカスタム実装を提供すると、カスタム永続化を使用してモデル内の FindUsages を最適化できます。同様に、NavigationParticipant(英語) のカスタム実装はルート / クラス / シンボルに移動アクションを最適化する機会があります。PersistenceFacade(英語) にカスタム参加者を提供することで、デフォルトで使用方法とナビゲーションの実装がすべてのモデルをメモリにロードして標準的な方法で処理するのではなく、永続ストレージに直接アクセスしてナビゲーションと同様に検索を高速化することができます。