開発環境の内部で。 ベースモデル

しばらく前に、たまたまNetbeansとJDeveloperの開発環境のコンポーネントを開発しました。 うーん、実はかなり前のことで、すべてを忘れて、クラウドが完全に世界をキャプチャするまで、このことについて記事を書かなければなりません。 そのため、私たちが毎日使用する製品の内部を見ることができたのは幸運でした。この記事では、開発環境の設計のいくつかの側面と、Java IDE内で使用されるモデルの設計の原則について説明します。 例としてNetbeansを使用しますが、他の環境でもほぼ同じです。同じ問題が同様のソリューションを生み出すからです。



IDEは、プロジェクトの一部であるドキュメント(主にソーステキストファイル)を編集するためのツールを提供します。 同時に、通常は単純なテキストエディターで行われるように、文字セットを使用するだけでなく、ドキュメントの内容の意味、および同じプロジェクト、依存関係プロジェクト、および依存関係ライブラリの他のドキュメントを考慮します。



開発環境を設計するとき、 MVCアーキテクチャテンプレートが積極的に使用されます。 レイヤーV(ビュー)は、画面上で観察するもの、ユーザーが操作するものです:テキストエディターとグラフィックエディター、あらゆる種類のナビゲーター(プロジェクトごと、プロジェクトファイルツリーごと、ファイル構造ごと)、ダイアログボックスなど目に見えないレイヤーM(モデル)はこのレイヤーの下に隠されています-これらは、開発環境が動作するデータを表す非常に開発されたオブジェクト構造です。 さまざまな抽象化レベルのドキュメント。 また、C(コントローラー)の順序についても言及します。これは最もわかりにくいレイヤーです。コントローラーによってデータを変更するように設計されたコンポーネントを意味しますが、コントローラーを独立した本格的なコンポーネントとして分離することは不可能な場合が多く、多くの場合これは単なる役割です。 たとえば、テキストエディタは明らかにドキュメントビューですが、同時に、それを使用してコンテンツに変更が加えられます。 それは一種のコントローラーであると同時にコントローラーでもあります。



ディスク上のファイル、仮想ファイルシステム



開発環境はファイルを操作します。つまり、これらのファイルを表すオブジェクト、またはディスク上のこれらのファイルの場所が必要です。 歴史的な瞬間があります。Javaには長い間、ファイルシステムの変更に関するイベントを追跡できるAPIがありませんでした。 ファイルシステムイベントに関心があり、誰もこれらのイベントを送信しない場合はどうすればよいですか? 標準的なソリューションがあります:中間層-仮想ファイルシステム(VFS)を導入します。 さらに、IDEコンポーネントは、VFSメソッドを介してファイルシステムと排他的に動作します。たとえば、突然新しいファイルを作成する必要がある場合、java.io.Fileを使用せずに、仮想ファイルシステムにファイルを作成するように依頼し、同じJavaを使用してファイルを作成します。 io.Fileは、新しいファイルが表示されたときにイベントを発行します。 ファイル発生イベントの監視に関心のある開発環境のすべてのコンポーネントは、VFSイベントにサブスクライブし、新しいファイルが作成されたという通知を受け取ります。







ただし、1つの問題が残っています。プロジェクト内のファイルは、サードパーティのプログラム(ヘッドライト、メモ帳、git cliなど)によって変更される可能性があります。 私はたまたまこのソリューションを観察しました:サードパーティのプログラムでファイルを変更するには、ファイルに切り替える必要があります。つまり、開発環境ウィンドウが入力フォーカスを失うため、プロジェクトの再スキャンを起動すると、フォーカスが開発環境に戻ったときに、ほぼすべてのサードパーティの変更をキャッチします もちろん、すべてのIDEは、可能な限りオペレーティングシステムのイベントをリッスンしようとしています。



Netbeansでは、ディスク上のファイルはFileObjectクラスを使用して表されます。



コンピューターのメモリ内のファイル



何らかのエディターでファイルを表示するには、メモリーにロードする必要があります。 そのため、メモリにロードされたファイルを表すオブジェクトが必要です。 多くの場合、このレイヤーではファイルの内容が考慮され始めます。 結局のところ、ファイルはデータを保存し、データはJavaコードである場合と、別の場合-3番目のJSONのXMLで異なります。 XMLデータも異なる場合があり、MavenプロジェクトまたはJPA設定ファイルの場合があります。 ファイルの中身を見て、その拡張子を見て、どのクラスを使用してこのコンテンツを持つファイルを表現するかを決めることができます。 Netbean環境では、メモリ内のファイルはDataObjectクラスを使用して表されます。



開発環境はこれらのオブジェクトをキャッシュし、毎回同じ物理ファイルに対して同じインスタンスを返します。 つまり これらのオブジェクトは、コンストラクタを使用してユーザーが作成するのではなく、プラットフォームから要求されます。たとえば、次のようになります。



DataObject myDataObject = DataObject.find(myFileObject);
      
      





このレイヤーのオブジェクトは、開発者に物理ファイルのコンテンツへのアクセスを提供します。これがまだ行われていない場合、コンテンツは開発環境によってコンピューターのメモリに透過的にロードされます。 例:



 BaseDocument myDocument = (BaseDocument) myDataObject.getCookie(EditorCookie.class).openDocument();
      
      





テキストコンテンツ



したがって、テキストファイルの内容を表す最下位レベルのモデルにアクセスできました。 Netbeansで使用されるBaseDocumentは、古き良きドキュメントスイングインターフェイスを実装します。





テキストバッファまたは文字バッファ、ドキュメントという名前を使用することもありますが、本質は同じです。可変長の文字の配列にすぎません。



競争力のあるアクセスと通知



モデルとは、いくつかのデータをオブジェクトのコレクションとして表現したものです。 これらのオブジェクトのメソッドを呼び出すことにより、モデルを変更できます。 変更時に、モデルは通知を送信します。実際、オブザーバーとして登録されたオブジェクトのメソッドを呼び出します。


開発環境はマルチスレッドです。 まず、キーストロークのイベント、マウスイベントが処理され、UIコンポーネント-GUIイベントディスパッチャースレッド(EDT)が展開およびレンダリングされるスレッドがあります。 エディターでテキストを入力すると、このスレッドのテキストバッファーが変更されます。 そして、たとえば、このスレッドで複雑な操作を実行するウィザードは、進行状況インジケーターをオンにし、バックグラウンドスレッドでモデルに変更を加えます。 一般に、バックグラウンドスレッドで任意の長さの時間を要する操作を実行して、ユーザーインターフェイスのブロックと速度低下を回避することは理にかなっています。 したがって、開発環境で使用されるモデルは通常、スレッドセーフです。


テストバッファは、関連するロックを使用して競合する変更から保護されます。 NetbeansおよびJDeveloperでは、これは読み取り/書き込みロックであり、日食では通常のモニターです。



変更を行うには、ロックを明示的または暗黙的にキャプチャする(書き込みロック)必要があり、モデルの変更と変更に関するイベントが送信されます。 ここでは、もちろん、オプションが可能ですが、通常、イベントは変更が行われたのと同じストリームで送信され、ロックの解除前に特定の危険が生じますが、ユーザーにより多くの自由が与えられます。 (ニュアンス:書き込みロックを所有するスレッドで実行されるイベントハンドラーのコードは、このモデルを変更しようとする場合があり、この動作を禁止することを好む場合があります)これは、読み取り/書き込みロックを使用した明示的なブロックのケースを探す方法です:







プラットフォーム ディスク上のファイル表現 メモリ内のファイルの表現 テキストバッファ ロックアクセス
Netbeans ファイルオブジェクト データオブジェクト 文書化 ドキュメントのreadLockwriteLock
JSR-198 java.net.URIおよびVirtualFileSystemクラスの静的メソッド javax.ide.model.Document 文書化 javax.ide.model.Transaction
日食 IPathIFileStore IFileBufferITextFileBuffer IDocument ISynchronizable
JSR 198(統合開発環境用の標準拡張API)は、APIおよびSPI開発環境を標準化する試みです。 この試みは失敗であり、JDeveloperでのみ実装されており、誰も使用していません。 しかし、このことには認知的価値があります-理想的なAPIと概念の一種の簡単な絞り込みです。


コンテキスト



開発環境のコンポーネントのコンテキストでは、編集済みファイル(オプション)、現在のプロジェクト(ファイルが開いているプロジェクト)、現在の選択(選択)が理解されます。 したがって、プロジェクトモデルと割り当てがあり、ファイルモデルについては既に説明しました。



エディターを開く(または他のコンポーネントを作成する)と、開発環境プラットフォームは現在のコンテキストを通知します。 「レポート」とは、次のことを意味します。editor.setContext(コンテキスト)メソッドまたはその類似物がエディターで呼び出され、コンテキストはファイル、プロジェクト、選択の3つのフィールドを持つオブジェクトにすぎません。



したがって、コンテキストは、編集者が他のファイルの情報を使用して「オートコンプリート」、「検証」などのツールの作業に必要なすべての情報を取得できる開始点です。 この情報は、高レベルモデルの形式で提示されます。その設計については、次の記事で説明します。



All Articles