リソースとWindow(エディターやIDEのメニュー)の連携について
リソースがどのように管理されているかは、EclipseとNetBeansで大きく違うポイントです。この部分を良く理解できれば、NetBeansにおける開発をかなりハイスピードで行うことができます。
NetBeansでのファイルリソースの扱い
Eclipseでは、IResource
というインターフェイスをベースに、IFile
、IFolder
、IProject
というインターフェイスが派生していて、リソースとビュー(表示機能)は独立しているシンプルな構成でした。
NetBeansの場合は、下図のようになっています。
下の方のオブジェクトから説明していくと、File
は、java.io.File
に相当する単なるJavaのオブジェクトです。
FileObject
は、このjava.io.File
をラップしたNetBeans用のFile
アクセス用の標準ライブラリだと理解してください。FileObject
では、単純にラップするほかに、FileObject
への変更をNetBeansの本体に通知する仕組みを実装しています。
DataObject
は、NetBeansのリソース管理において中心的な存在です。なぜならば、DataObject
が非常に沢山の情報を持っているからです。DataObject
は、そのファイルに対して、現在どのような処理が可能かを管理したり、その処理を実際に行うオブジェクト(Cookie
)を管理しています。また、Node
オブジェクトのファクトリーとしての機能も持っています。
Node
は、プロジェクトのディレクトリツリーに表示されるときのアイコンやテキストなどのGUI表示に関する機能をサポートするほか、右クリックのした際に表示されるメニューのActionの管理や、ファイルのプロパティの項目のサポートをしています。
NetBeansでプロジェクトを開くと、各ファイルにさまざまなアイコンがついていますが、これは、各Node
オブジェクトがサポートしている機能です。
ファイルが認識されるまでの流れについて
NetBeansのPluginモジュールの開発をする際、プロジェクトを開いたときに、内部でどのようにしてNetBeansがファイルを認識していくかを知ることは非常に重要です。
まず最初にNetBeansがプロジェクトに相当するフォルダを開くと、NetBeansはそのフォルダの中にあるファイルやフォルダを認識します。このときに、その認識されたファイルやフォルダに相当するFileObject
が作られます。
次に、NetBeans本体は、そのファイルオブジェクトの拡張子(XMLファイルの場合は、トップ階層のタグ名)から、どのDataLoader
を使うか判断します。このとき、どの拡張子に対してどのDataLoader
を使うかという情報は、システム・ファイルシステムの中から取得します。ですので、新しいタイプのデータタイプを作成するときには、どの拡張子に対してどのDataLoader
クラスを使うかという情報を「layer.xml」に記述しなくてはなりません。
次に、先ほど選択されたDataLoader
からDataObject
が作成されます。DataObject
が作成された時点では、まだ表示されていません。そのファイルをビューの中に表示するには、表示に関してサポートするNode
オブジェクトを作成する必要があります。
そして、最後に、DataLoader
がNode
オブジェクトを作成します。これをプロジェクトの中身を表示するNetBeansのビュー(ウィンドウ)に渡すことによって、プロジェクトツリーの中にそのオブジェクトが表示されます。
DataObjectとCookieパターン
DataObjectとCookieパターンについて知っておくことも、NetBeansでPluginモジュールを作成する上で必要です。
DataObject
は、そのファイルに対して現在どのような処理を行えるかを知っていると書きましたが、それをコードにすると次のようになります。
Cookie cookie = this.dataObject.getCookie(SaveCookie.class); // もしも、cookieがnullだった場合にはその処理ができないことを示す if(cookie != null){ SaveCookie saveCookie = (SaveCookie)cookie; // SaveCookie独自(保存処理)の処理を行う saveCookie.save(); }
このコードでは、そのDataObject
を保存できるかどうかを聞いて、もし、DataObject
がエディタで変更されて保存が必要ならば保存し、変更がなく保存の必要がない場合には、何もしません。
この、getCookie()
メソッドから特定の処理用のCookie
を取得し、取得したCookie
がnullでないかnullかで、その処理ができるかできないかを判断するのは、NetBeansでは標準的な方法です。
この方法が使われている例として、エディタでJavaのソースコードを更新した際に、左上の保存ボタンが有効になったり、保存した直後には無効になったりする仕組みが挙げられます。
今回は、ドキュメントの保存処理に関するSaveCookie
を紹介しましたが、そのほかに次のようなCookie
があります。
OpenCookie
CloseCookie
PrintCookie
EditorCookie
Lookupパターン
Lookupパターンは、NetBeansのPlugin開発を勉強する際に、かなり使い方がつかみにくいパターンです。なぜ、つかみにくいかと言うと、それは、仕様用途が広範囲にわたるため、DocumentでLookup
オブジェクトのところを見ても「何かを探す仕組み」としか書いていないからです。
確かにそうなのですが、例がないと分かりにくいと思いますので、今回はLookupパターンの使用例を一つ挙げてみます。
今回、Lookupパターンは、DataObject
とNode
、もしくはその他のDataObject
に関連付けられた部品間で情報を共有するための仕組みに用いられています。
基本的にNode
がメインでLookup
オブジェクトを管理していますが、DataObject
からNode
にアクセスしてLookup
を取得することも可能です。
Cookieパターンの復習も兼ねて、次のソースコードを見てください。
ここでは、DbFuncDataObjectという名前のDataObject
にDbFuncFileCookieSupportという名前のCookie
をセットしています。DataObject
に対して、OpenCookie
インターフェイスの実装クラスをセットしているので、このファイルに対してOpen処理を行うことがこれで可能になります。
public class DbFuncDataObject extends MultiDataObject { public DbFuncDataObject(FileObject pf, DbFuncDataLoader loader) throws DataObjectExistsException, IOException { super(pf, loader); CookieSet cookies = getCookieSet(); cookies.add((Node.Cookie) DbFuncFileCookieSupport .create(this, getPrimaryEntry(), cookies)); } protected Node createNodeDelegate() { return new DbFuncDataNode(this); } }
実際のOpen処理の内容は次のソースコードのようになります。ここで、そのファイルをOpenするためのエディタを指定しています。つまりNetBeansの場合は、Open処理に関連付けられるエディタがOpenCookie
の実装で決まることになります。
public class EasyDbFuncEditorCookie extends DataEditorSupport implements OpenCookie{ public void open() { Lookup lookUp = dataObject.getNodeDelegate().getLookup(); //NodeLookup
オブジェクトからいろいろと取得 // まずは、DataObject
オブジェクトを取得 HyperDbFileDataObject dataObj = (HyperDbFileDataObject) lookUp.lookup(HyperDbFileDataObject.class); // つぎは、DataNode
オブジェクトを取得 HyperDbFileDataNode nodeObj = (HyperDbFileDataNode) lookUp.lookup(HyperDbFileDataNode.class); // さらにCookieも取得できます EasyEditorCookie cookie = (EasyEditorCookie)lookUp.lookup(EasyEditorCookie.class); DbFuncTopComponent topComp = DbFuncTopComponent.getInstance(lookUp, dataObject); topComp.open(); topComp.requestActive(); } }
今回は、Node
オブジェクトからLookup
を取得していますが、このLookup
オブジェクトの実際のクラスは、NodeLookup
クラスです。Lookup
クラスからは、いろいろなものが取得できるようになっています。
Lookup
の使い方が分からないときは、デバッガで見てしまうのが一番です。
引用と謝辞
本稿の画像は、NetBeans.org 『Recognizing a File Type Tutorial』を基に、描きおこさせていただきました。
引用の許可などについて協力していただいた「NetBeans, Japanese Speaking Community」の皆さま、ありがとうございました。