リソースと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があります。
OpenCookieCloseCookiePrintCookieEditorCookie
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」の皆さま、ありがとうございました。

