XPJS Components Proposal

警告: この記事の内容は古くなっている可能性があります。 これはシステムに対する実装済みの提案ですが、実際の実装とは異なる可能性があります。この提案の状況に関する最新情報は ステータスドキュメント をご参照ください。

Draft 1.0

XPJS コンポーネントとは何ですか?

XPJS コンポーネントとは、JavaScript で書かれた XPCOM コンポーネントをサポートするシステムの (安っぽい) 名前です。さて、あなたはこうお尋ねになるかもしれません。「それは XPConnect がすることではないのですか?」そして、私の答はこうです。「そのタスクに対して、XPConnect は必要ではあっても十分ではありません。」 XPConnect は、ネイティブな XPCOM コンポーネントと JS XPCOM コンポーネントの間の通信の仕組みを提供します。ただし、ブラウザウィンドウの外において、JS コンポーネントの登録とインスタンス化の基盤をすべて提供するわけではありません。 XPJS は、そのための基盤を提供するのです。

では、これによって、何をしようとしているのですか?

XPJS コンポーネントシステムは、JavaScript による XPCOM サービス、ファクトリー、コンポーネントの実装を支援します。また、サービスとファクトリーの登録をサポートします。これらのコンポーネントは、ウェブのコンテンツとブラウザーウィンドウから独立しています。ユーザーディスクからロードされ、ネイティブなコンポーネントのように動作します。

どのように動作するのですか?

今までの原則はオーバーライドされ、(XPJS コンポーネントは)できるだけネイティブなコンポーネントのように動作させることが原則になります。 XPJS コンポーネントは .js ファイルの中に「存在」します。ちょうど、ネイティブなコンポーネントのモジュールと同じように、これらの .js ファイルには、以下の関数があるはずです。

  • <tt>NSRegisterSelf</tt>
  • <tt>NSGetFactory</tt>
  • <tt>NSUnregisterSelf</tt> (任意)
  • <tt>NSCanUnload</tt> (任意)

それぞれの .js ファイルには、一つ以上のコンポーネントの実装があるかもしれません。

XPJSManager と呼ばれるネイティブなモジュールが一つあります。これは、このシステムをまとめる役割を果たします。 XPJSManager は、これらの .js ファイルを受け持ち、それら自身の登録を支援します。そして XPCOM コンポーネントマネージャと JS コードの間を仲介します。

XPJS コンポーネントは、ブラウザウィンドウ上では動作しません。それぞれの .js ファイル (モジュールと呼ぶことにしましょう) は、比較的「そのままの形」で JS グローバルオブジェクトのコンテキスト上で、起動して動作します。標準的な (非 DOM の) JS クラスが利用できます。XPConnect コンポーネントオブジェクトが利用できます。そして、追加のコンポーネントがいくつか利用できるようになるかもしれません。XPConnect コンポーネントオブジェクトにより、ネイティブなコンポーネントと JS XPCOM コンポーネントの全リポジトリーにアクセスできるようになります。そのため、最初に感じられるほど、孤立した環境ではありません。

「load」または「import」関数も提供されており、JS コード が他の .js ファイルをライブラリとしてインポートすることができます。これは「静的な」ライブラリの使用に似ています。 XPCOM/XPConnect 経由で他のコンポーネント/サービスにアクセスするのは「動的な」ライブラリの使用に似ています。

XPJS コンポーネントモジュールが最初にインストールされた時、あるいは自動登録時に、XPJSManager は、.js ファイルを新しい JS 環境にロードします。そして、トップレベルのスクリプトを実行し、適切な初期化が行われます。そして、モジュールの NSRegisterSelf 関数を呼び出します (この時 .js ファイルの filespec が渡されます)。この時、モジュールは、コンポーネントオブジェクト上の (新しい) メソッドを使って、1 つ以上の classsid または progid に対応するファクトリーモジュールとして、自分自身をコンポーネントマネージャに登録します。

この時、JS コードが呼び出す登録関数 (例えば、Components.RegisterComponentSpec) は、 XPJSManager によって提供されます。 XPJSManager は、JS コードからこの呼び出しを受けます。そして、自分自身で後から使うために、 clsid から .js filespec へのマッピングをレジストリに保存します。そして、実際のコンポーネントマネージャを呼び出して登録を行います。しかしながら、XPJSManager は、それ自身の filespec をコンポーネントマネージャに渡します。

そのため、その後で、あるコードがコンポーネントマネージャにある clsid (または progid) に対応するオブジェクトインスタンスの生成を依頼したとすると、コンポーネントマネージャは、 XPJSManager のモジュールをロードし、見つかったネイティブな NSGetFactory を呼び出します。ネイティブな NSGetFactory 関数は、レジストリにある情報をチェックして、ある clsid に対応する JS ファクトリーがどこの .js ファイルにあるかを見つけます。そして、(まだロードされていなければ) .js ファイルをロードし、その NSGetFactory 関数を呼び出します。

XPConnect は、JS モジュールの NSGetFactory 関数から返ってきた JS オブジェクトを XPCOM オブジェクトに変換します。コンポーネントマネージャ (およびそのファクトリーへの参照を持っている他のもの) は、ファクトリーの CreateInstance メソッドを自由に呼び出すことができます。

JS モジュールは、ファクトリーやコンポーネントやサービスを自由に実装することができます。これらは、ファクトリーがコマンドに応じて構築します。コードがどこにあろうとも、あるいはどの言語で実装されようとも、これらに対し、コンポーネントマネージャとサービスマネージャ経由でアクセスすることができます。

XPJSManager は、ある程度、それぞれの XPJS モジュールの生存期間の管理を担当しています。 JavaScript は、ガベージコレクトされ、オブジェクトの削除やコンパイルされたコードをメモリから消去するのを強制することはできません (JSRuntime を削除する、つまり JS 全体を削除するのを除いて)。 C++ において、もし、あるモジュールがオブジェクトを作成した後、そのオブジェクトへの参照が残っているにもかかわらず、そのモジュールをメモリから消去すると、すぐにクラッシュする可能性が高いです。 JS では、この問題がありません。もし、(どんな手段によっても) XPJSManager がそれ自身を削除するように依頼された場合、それぞれのモジュールの NSCanUnload メソッドがもしあれば、それを呼び出すでしょう。もし、モジュールがそれに OK すると、XPJSManager は、モジュールのグローバルオブジェクトのルートを解放します。そして、そのモジュールが保持していたオブジェクトを解放します。それ以降、コンポーネントマネージャから来る要求に対しては、 モジュールへの NSGetFactory の呼び出しを行います。そして、 XPJSManager に .js から新しいインスタンスをロードするように強制し、やり直しを行います。このように、これらの XPJS コンポーネントモジュールは、安全にメモリから除去することができますが、(ネイティブなモジュールのように) どのようなメモリ除去の試みも拒否することはできます。

では、いつ使えるようになるのですか?

これは、すぐに実現するだろうと考えていました。そんなに難しくないことだと思います。

コメントと提案を歓迎します!

原文書の情報

ドキュメントのタグと貢献者

 このページの貢献者: kohei.yoshino
 最終更新者: kohei.yoshino,