エクステンダー実装のご紹介 - Japan

null エクステンダー実装のご紹介
by Yasuyuki Takeo

エクステンダー実装のご紹介

画像

こんにちは。
日本ライフレイ、サポータビリティエンジニアの竹生(たけお)です。

今回はLiferayの拡張(エクステンダー)実装について、少し詳しくなれる記事を紹介します。

以下の知識レベルの方たち、ユースケースが対象です。ご参照ください。


  

  • 上級レベル*
  • Liferay DXP開発に必須の知識

*レベルの定義については、こちらのブログの冒頭で紹介しています。


※本記事はLiferay Community Blogに投稿されている”Meet The Extenders”を翻訳したものです。配信元または著者の許可を得て配信しています。
※オリジナルの英記事著者:David H Nebinger サウスカロライナ州のサマーヴィルに住むLiferay, Inc.のSoftware Architect/リードコンサルタント。Liferay Communityサイトにて、多くの技術情報を投稿するなど精力的に活動しています。

はじめに


 本ブログではLiferayの拡張(エクステンダー)実装について、どのように活用するべきかご紹介します。

Liferayのソースコードを掘り下げると、常に新しいことを学ぶ機会があります。

先日はLiferayエクステンダーのソースコードで、いくつか発見をしたため、共有したいと思います。

  

拡張パターン


そもそもエクステンダーパターンとは何でしょうか。 LiferayのWABエクステンダー、Springエクステンダー、またはXyzエクステンダーなどに関連して、単語自体は聞いたことあるかもしれません。ですが、実際何であるか、どう機能するものなのかしっかりと理解している人は少ないのではないかと思います。

実際、エクステンダパターンは公式OSGiパターンです。私が見つけた、最も簡単で、完璧な定義は次のとおりです。

エクステンダーパターンは、バンドルコンテンツに基づいて実行時に追加機能を提供するために、一般的に使用されます。この目的のために、エクステンダバンドルはライフサイクルの特定の時点で、新しいバンドルをスキャンし、そのスキャンに基づいて追加のアクションを実行するかどうかを決定します。追加のアクションには、追加リソースの作成、コンポーネントのインスタンス化、サービスの外部への公開などがあります。 OSGiサービスプラットフォームエンタープライズ仕様の機能の大部分は、エクステンダーバンドル、特にブループリント、JPA、およびWABのサポートを通じてサポートされています。

パターンについてもっと深く知りたい場合、OSGi エクステンダーモデルについての説明はだいぶ長くなってしまいます。

なので端的に説明すると、エクステンダーは開始されているバンドル内のファイルを検査し、いくつかの機能を自動化することができます。たとえばDSの場合は、@ Componentアノテーションで装飾されたクラスを処理できます。エクステンダーは、開発者がコンポーネントインスタンスを登録して起動するために、繰り返し書くような作業を代行してくれます。

Liferayには実際いくつかのエクステンダーがあります。それらをチェックしてみましょう。


com.liferay.portal.remote.http.tunnel.extender.internal.HttpTunnelExtender

このエクステンダーは、バンドル用のHttpTunnelサーブレットを接続します。バンドルにHttp-Tunnelというヘッダーがある場合は、トンネルサーブレットがそれに接続され、実際に多くの補助的なサービス登録を作成します。

  • 認証検証用のAuthVerifierFilter(AuthVerifyパイプラインによる検証。BasicAuthおよびLiferayセッション認証を含む)
  • バンドルのサーブレットコンテキストのServletContextHelper
  • Tunnelサーブレット自体のサーブレット。知らない人のために:Tunnelサーブレットは保護されたTunnelサーブレットを介して、リモートLiferayインスタンスにコマンドを送信することを可能にし、リモートステージングが機能するにあたっての中核部分です。

com.liferay.frontend.theme.contributor.extender.internal.ThemeContributorExtender

テーマのコントリビューターは、エクステンダーパターンを使って実装されています。

このエクステンダーは、バンドルからLiferay-Theme-Contributor-Typeヘッダーを(bnd.bndファイルを介して)検索するか、package.jsonファイルがある場合はthemeContributorTypeを探します。また、リソースがバンドルに含まれていることも確認します。

次に、ThemeContributorExtenderはバンドル用に2つのサービスを登録します。1つ目はバンドルリソースをポータルWebリソースとして公開するためのThemeContributorPortalWebResourcesインスタンス、もう1つは実際にバンドルリソースを公開して返すためのBundleWebResourcesのインスタンスです。


com.liferay.portal.configuration.extender.internal.ConfiguratorExtender

コンフィギュレータエクステンダーは、あまり実例を目にすることのないものの1つです。

基本的にバンドルヘッダーLiferay-Configuration-Pathがある場合、コンフィギュレータエクステンダは基本的にこのパスのプロパティファイルを使用してConfiguration Adminで設定を行います。バンドルのデプロイを介して設定を強制したい場合、つまりElasticSearch設定を部分的に変更するために、バンドルをプッシュしたい場合は、役に立つかもしれません。


com.liferay.portal.language.extender.internal.LanguageExtender

言語拡張機能は、バンドルのリソースバンドル処理を処理します。バンドルにliferay.resource.bundleケーパビリティがある場合、ケーパビリティ文字列(一般的にベース名、集合コンテキストなどを含む)を解析する方法を知っている拡張を作成し、特別な集約Resource Bundle LoaderをOSGiに登録します。


com.liferay.portal.spring.extender.internal.context.ModuleApplicationContextExtender

これは、ServiceBuilderをLiferay 7 CEおよびLiferay 7 DXPで機能させるために便利なエクステンダーです。言葉で説明するには、少し長くなります。

このエクステンダーはLiferay-Spring-Contextヘッダを持つすべてのバンドルに対して機能します(もちろんbnd.bndから参照されます)。

最初に、ModuleApplicationContextExtenderは、モジュールBeanの作成元または作成元となるSpringコンテキストとなるバンドルのModuleApplicationContextRegistratorインスタンスを作成します。 Liferay-ServiceおよびLiferay-Spring-Contextバンドルヘッダーを使用してSpringコンテキストxmlファイルを識別し、ModuleApplicationContextを使用してすべてのインスタンスを作成します。

次にバンドル用のBeanLocatorを作成します(Liferay 6の頃を覚えていますか?テンプレートおよびスクリプトコントロールパネルで要求されたとき、ポータルがサービスを見つけることができる方法です)。

その後、ModuleApplicationContextRegistratorはサービスを初期化し、最後にバンドル内の各Spring BeanをOSGiコンポーネントとして登録します(SB実装クラスで@Componentsとして宣言することなく、SBサービスを@Referenceできます)。

ModuleApplicationContextExtenderはまだ行われていません。 Springの初期化は、OSGiが新しいSpringコンテキストの管理(ライフサイクル)を引き継ぐように、OSGi Dependency Managerによって管理される動的に作成されたコンポーネントを準備することでした。

バンドルにLiferay-Require-SchemaVersionヘッダーがある場合、ModuleApplicationContextExtenderはコンポーネントの依存関係としてリストされているバージョンの要件を追加します。これが、x.y.zバージョンのサービス実装がx.y.zバージョンのAPIモジュールに特別にバインドされる方法です。 Liferay-Require-SchemaVersionヘッダーがAPIモジュールに刻印されたバージョンと同期していることを確認することが重要である理由と、実際にモジュールのバージョン番号をぶつけることを忘れないようにすることも重要です。エンティティまたはサービスクラスのservice.xmlファイルやメソッドシグネチャを変更します。

ModuleApplicationContextExtenderは最終的な責任、SBテーブル、インデックス、およびシーケンスの初期作成を行います。通常、アップグレードを扱う場合は、UpgradeStepRegistratorコンポーネントを手動で作成し、バージョンが変更されたときに呼び出されるアップグレード手順を、それらに登録する必要があります。しかし、は、ServiceBuilderの0.0.0からx.y.zへのアップグレード手順は手動で書く必要はありません。 ModuleApplicationContextExtenderは自動的にアップグレード手順を登録し、基本的にスクリプトを適用してテーブル、インデックス、およびシーケンスを作成します。

お察しの通り、ここではたくさんの処理が行われています。サービスモジュールがLiferay、Spring、OSGiにどのように公開されるのか、今ならお分かりいただけると思います。


com.liferay.portal.osgi.web.wab.extender.internal.WabFactory

このエクステンダーは、個人的な意見ですが、名前が良くないと思います。 WabFactoryという名前は、それがWAB専用であることを(私には)暗示しているように思えるのですが、実際は一般的なサーブレットもカバーします。

Liferayはすべてのサーブレット、フィルタなどを公開するためにOSGi HTTP Whiteboardサービスを使用します。RESTサービスはなんでしょうか? HTTPホワイトボードですね。JSPポートレットは?HTTPホワイトボードです。テーマ投稿者も同様です。シンプルサーブレットも、LiferayによってWABに変換される「従来の」ポートレットWARも、HTTPホワイトボードを介して公開されています。

これは長所でもあります。OSGi宣言サービスのダイナミズムにより、さまざまな実装をコンテナーに影響を与えることなく追加、削除、および再始動できるからです。

しかし、ご存じないかもしれませんが、HTTPホワイトボードは、実装の詳細にはまったく関係ありません。たとえば、JSPの処理についてはまったく触れていません。また、REST処理、MIMEタイプなどもありません。これはHTTPホワイトボードが正しいサービス実装に入ってくる要求を委譲することができるよう、サービスがどのように登録されるかを表しています。

そのため、HTTPホワイトボード登録のための一般的な一連の手順があります。登録するには最初にHttpサービスの参照が必要です。バンドルのServletContextHandlerを作成し(バンドルリソースをサーブレットコンテキストとして公開する)、次にそれを使用して、サーブレット、フィルタ、およびバンドル(または他の場所)からのリスナを登録する必要があります。これはOSGiとのやり取りを扱うための定型コードです。サーブレット開発者であれば、これらすべてのOSGiの側面を習得する必要はありません。

扱うべきJSP、RESTサービスなどがまだあり、他にもたくさんのことをする必要があります。

でも、WabFactoryをつかうとその必要はありません。

たとえば、WabFactoryは、Web-ContextPathおよびWeb-ContextNameバンドルヘッダーを処理するので、すべてのサーブレットをHTTP Whiteboardプロパティで装飾する必要はありません。バンドルのServletContextHelperインスタンスを登録し、サーブレット、フィルタ、およびリスナのすべてをサーブレットコンテキストにバインドします。バンドル内のJSPファイルをコンパイルして使用できるようにJspServletを登録します(LiferayがバンドルJSPをコンパイルしているのではなく、アプリケーションコンテナではないことに気付いたでしょう)。

ここには他にもたくさんの機能があります。portal-osgi-web-wab-extenderモジュールにおいて、そのすべての処理がどのように起こっているかをより理解したいのであれば、さらに掘り下げてみることをお勧めします。


com.liferay.frontend.js.top.head.extender.internal.TopHeadExtender(7.1)

これは7.1で導入された新しいエクステンダーです。

このエクステンダーは、実際には2つの異なるバンドルヘッダー、Liferay-JS-Resources-Top-HeadLiferay-JS-Resources-Top-Head-Authenticatedを使用して、ページの上部にJSリソースを含めることを処理します。認証セッションとゲストセッションで異なるリソースを使用している可能性があります。

この新しいエクステンダーは、基本的にportal-ext.propertiesの古いjavascript.barebone.filesおよびjavascript.everything.filesプロパティを廃止し、モジュールが独自のスクリプトを動的に提供してHTMLページの領域に含めることを可能にします。

実際にこれが新しいfrontend-js-webモジュールのbnd.bndファイルで使われているのを見ることができます。カスタムモジュールとLiferay-Top-Head-Weightバンドルヘッダーを使用してより高いサービスランクを定義することで上書きできます。


まとめ


私たちはOSGi Extenderパターンの基本的な定義から始めました。それから、現在Liferayで使用されている具体的な実装をもとに努力しました。

特に開発の観点からは、これらのエクステンダーが実際にLiferay 7 CEおよびLiferay 7 DXPの重要な部分であることを理解できると思います。

拡張機能がない場合は、開発者として多くの定型コードを生成する必要があります。 ModuleApplicationContextExtenderと、それがServiceBuilderの実装に対して行っていることへ、リソースを割いているとしたら、一度止めて、それらすべて自分自身で結び付けなければならない場合の生産性を考えてみてください。どれだけのバグを作り込んでしまう可能性があるでしょうか。 Liferay エクステンダーに関する本レビューが、プロジェクトのボイラープレートコードをどのように排除することができるか、ヒントになると幸いです。


 

本記事は以上です。
いかがでしたでしょうか?

記事に関するご意見、ご感想などございましたら、お気軽にyasuyuki.takeo@liferay.comまでご連絡ください。

 


 

■ これまで発信してきた日本語による技術コンテンツを、Qiitaでお読みいただけます。よろしければそちらの記事も合わせてご役立てください。
https://qiita.com/yasuflatland-lf

Doorkeeperのライフレイコミュニティメンバー大歓迎!
コーポレートブログの技術コンテンツ更新情報など定期的におとどけしています。
https://liferay.doorkeeper.jp/

 

 

業界最高の評価

Gartner

Gartnerレポート:『リーダー』に位置づけ
ライフレイは9年連続で、Gartner社によるデジタルエクスペリエンスプラットフォーム(DXP )分野のマジック・クアドラントにおいて、リーダーに選出されました。

レポートの詳細、ダウンロード