Show Menu
TOPICS×

HTL Java Use-API

The HTML Template Language (HTL) Java Use-API enables an HTL file to access helper methods in a custom Java class through
data-sly-use
. これにより、複雑なビジネスロジックをすべて Java コードでカプセル化し、HTL コードではマークアップの直接作成処理のみを行うことができます。
Java Use-APIオブジェクトは、単純なPOJOで、POJOのデフォルトのコンストラクタを通じて特定の実装によってインスタンス化されます。
Use-API POJOは、次の署名を持つinitと呼ばれるパブリックメソッドも公開できます。
/** * Initializes the Use bean. * * @param bindings All bindings available to the HTL scripts. **/ public void init(javax.script.Bindings bindings);
この
bindings
マップには、Use-APIオブジェクトが処理に使用できる、現在実行されているHTLスクリプトにコンテキストを提供するオブジェクトを含めることができます。

簡単な例

まず、use クラスを持たない HTL コンポーネントから始めます。これは単一のファイル、
/apps/my-example/components/info.html
で構成されています。

/apps/my-example/component/info/info.html

<div> <h1>${properties.title}</h1> <p>${properties.description}</p> </div>
また、このコンポーネントが
/content/my-example/
でレンダリングするコンテンツもいくつか追加します。

http://<host>:<port>/content/my-example.json

{ "sling:resourceType": "my-example/component/info", "title": "My Example", "description": "This Is Some Example Content." }
このコンテンツにアクセスがあると、HTL ファイルが実行されます。Within the HTL code we use the context object
properties
to access the current resource's
title
and
description
and display them. 出力される HTML は以下のとおりです。

view-source:http://<host>:<port>/content/my-example.html

<div> <h1>My Example</h1> <p>This Is Some Example Content.</p> </div>

use クラスの追加

info
コンポーネントは、現状では、use クラスがなくとも、その(非常に単純な)機能を実行できます。ただし、場合によっては、HTL ではできないことを実行する必要があるので、use クラスは必要です。ただし、以下のことに留意してください。
use クラスは、HTL だけでは実行できない場合にのみ使用してください。
例えば、
info
コンポーネントで、リソースの
title
description
プロパティを、すべて小文字で表示するとします。HTL には文字列を小文字にするためのメソッドがないので、use クラスが必要になります。これを行うには、以下のように、Java use クラスを追加して
info.html
を変更します。

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info"> <h1>${info.lowerCaseTitle}</h1> <p>${info.lowerCaseDescription}</p> </div>

/apps/my-example/component/info/Info.java

package apps.my_example.components.info; import com.adobe.cq.sightly.WCMUsePojo; public class Info extends WCMUsePojo { private String lowerCaseTitle; private String lowerCaseDescription; @Override public void activate() throws Exception { lowerCaseTitle = getProperties().get("title", "").toLowerCase(); lowerCaseDescription = getProperties().get("description", "").toLowerCase(); } public String getLowerCaseTitle() { return lowerCaseTitle; } public String getLowerCaseDescription() { return lowerCaseDescription; } }
以降の節では、コードの様々な部分について順を追って説明します。

Local vs. Bundle Java Class

Java use クラスは、
ローカル
​または​
バンドル
​の 2 つの方法でインストールできます。この例ではローカルインストールを使用します。
ローカルインストールでは、Java ソースファイルは HTL ファイルと並んで、同じリポジトリフォルダーに配置されます。ソースは、オンデマンドで自動でコンパイルされます。コンパイルやパッケージを別途行う必要はありません。
バンドルインストールでは、Java クラスは、標準の AEM バンドルデプロイメントメカニズムを使用してコンパイルし、OSGi バンドル内にデプロイする必要があります( バンドルされた Java クラス を参照)。
ローカル Java use クラス
​は、use クラスが対象コンポーネントに特有の場合にお勧めします。
バンドル Java use クラス
​は、複数の HTL コンポーネントからアクセスがあるサービスを Java コードで実装する場合にお勧めします。

Java パッケージはリポジトリパス

ローカルインストールを使用するとき、use クラスのパッケージ名は、リポジトリフォルダーの場所と一致する必要があります。ただし、パス内のハイフンは、パッケージ名ではアンダースコアに置き換えられます。
ここでは、
Info.java
/apps/my-example/components/info
に配置されているので、パッケージは
apps.my_example.components.info
です。

/apps/my-example/component/info/Info.java

package apps.my_example.components.info; import com.adobe.cq.sightly.WCMUsePojo; public class Info extends WCMUsePojo { ... }
AEM開発では、リポジトリ項目の名前にハイフンを使用することをお勧めします。 ただし、ハイフンは Java パッケージ名では不正です。この理由から、
リポジトリパス内のハイフンはすべて、パッケージ名ではアンダースコアに変換する必要があります

拡張
WCMUsePojo

Java クラスを HTL に組み込むには多数の方法がありますが(「
WCMUsePojo
の代替策」を参照)、最も簡単な方法は
WCMUsePojo
クラスを拡張することです。

/apps/my-example/component/info/Info.java

package apps.my_example.components.info; import com.adobe.cq.sightly.WCMUsePojo; public class Info extends WCMUsePojo ... }

クラスの初期化

When the use-class is extended from
WCMUsePojo
, initialization is performed by overriding the
activate
method:

/apps/my-example/component/info/Info.java

... public class Info extends WCMUsePojo { private String lowerCaseTitle; private String lowerCaseDescription; @Override public void activate() throws Exception { lowerCaseTitle = getProperties().get("title", "").toLowerCase(); lowerCaseDescription = getProperties().get("description", "").toLowerCase(); } ... }

コンテキスト

Activate メソッドの通常の用途は、現在のコンテキスト(現在の要求やリソースなど)に基づいて HTL コードに必要な値を事前に計算し、(メンバー変数に)格納することです。
WCMUsePojo
クラスを使用すると、HTL ファイル内で使用可能なものと同じコンテキストオブジェクトにアクセスできます( グローバルオブジェクト を参照)。
WCMUsePojo
を拡張するクラスでは、名前を基準として、以下のコードを使用してコンテキストオブジェクトにアクセスできます。
また、以下のような適切で​
便利なメソッド
​によって、よく使用されるコンテキストオブジェクトに直接アクセスできます。

ゲッターメソッド

use クラスが初期化されると、HTL ファイルが実行されます。この段階で、HTL は通常、use クラスの様々なメンバー変数の状態を引っ張ってきて、プレゼンテーション用にレンダリングします。
HTL ファイル内からこれらの値へアクセスできるようにするには、以下の命名規則に従って、use クラスでカスタムのゲッターメソッドを定義する必要があります。
  • getXyz
    という形式のメソッドを使用すると、HTL ファイル内で
    xyz
    という名前のオブジェクトプロパティがアクセス可能になります。
In the following example, the methods
getTitle
and
getDescription
result in the object properties
title
and
description
becoming accessible within the context of the HTL file:

/apps/my-example/component/info/Info.java

... public class Info extends WCMUsePojo { ... public String getLowerCaseTitle() { return lowerCaseTitle; } public String getLowerCaseDescription() { return lowerCaseDescription; } }

data-sly-use 属性

data-sly-use
属性は、HTL コード内で use クラスを初期化する際に使用します。ここに示す例では、
data-sly-use
属性によって、
Info
クラスを使用することを宣言しています。ここではローカルインストールを使用している(Java ソースファイルを HTL ファイルと同じフォルダーに配置している)ので、クラスのローカル名だけを使用できます。バンドルを使用する場合は、完全修飾クラス名を指定する必要があります。

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info"> <h1>${info.lowerCaseTitle}</h1> <p>${info.lowerCaseDescription}</p> </div>

ローカル識別子

The identifier
info
(after the dot in
data-sly-use.info
) is used within the HTL file to identify the class. 宣言された識別子は、ファイル内でグローバルスコープとして認識されます。
data-sly-use
ステートメントを含む要素のみに制限されるわけではありません。

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info"> <h1>${info.lowerCaseTitle}</h1> <p>${info.lowerCaseDescription}</p> </div>

プロパティの取得

識別子
info
はその後、ゲッターメソッド
title
および
description
によってアクセス可能になったオブジェクトプロパティ
Info.getTitle
および
Info.getDescription
へのアクセスに使用されます。

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info"> <h1>${info.lowerCaseTitle}</h1> <p>${info.lowerCaseDescription}</p> </div>

出力

ここで、
/content/my-example.html
にアクセスすると、以下の HTML が返されます。

view-source:http://<host>:<port>/content/my-example.html

<div> <h1>my example</h1> <p>this is some example content.</p> </div>

応用

この節では、上記の単純な例を超える機能をいくつか紹介します。
  • use クラスにパラメーターを渡す
  • バンドルされた Java use クラス
  • WCMUsePojo
    の代替策

パラメーターを渡す

初期化時に、use クラスにパラメーターを渡すことができます。例えば、次のようなことが可能です。

/content/my-example/component/info/info.html

<div data-sly-use.info="${'Info' @ text='Some text'}"> <h1>${info.lowerCaseTitle}</h1> <p>${info.lowerCaseDescription}</p> <p>${info.upperCaseText}</p> </div>
ここでは、
text
というパラメーターを渡しています。その後、use クラスでは、取得した文字列を
info.upperCaseText
で大文字に変換して結果を表示します。適用された use クラスは次のとおりです。

/apps/my-example/component/info/Info.java

package apps.my_example.components.info; import com.adobe.cq.sightly.WCMUsePojo; public class Info extends WCMUsePojo { ... private String reverseText; @Override public void activate() throws Exception { ... String text = get("text", String.class); reverseText = new StringBuffer(text).reverse().toString(); } public String getReverseText() { return reverseText; } ... }
パラメーターへのアクセスには
WCMUsePojo
メソッドを使用します。
<T> T get(String paramName, Class<T> type)
我々の場合、
get("text", String.class)
次に、文字列が逆順になり、メソッドを使用して公開されます。
getReverseText()

data-sly-template からのみパラメーターを渡す

上記の例は、技術的には正しいものの、問題の値が HTL コードの実行コンテキストで使用可能な場合(または上記のように値が静的である場合)に HTL から値を渡して use クラスを初期化する意味は、実際にはあまりありません。
理由は、use クラスが HTL コードと同じ実行コンテキストに常にアクセスできるからです。これにより、ベストプラクティスの読み込みポイントが提示されます。
use クラスにパラメーターを渡すのは、その use クラスが
data-sly-template
ファイルで使用されており、かつ渡す必要のあるパラメーターを含む別の HTL ファイルからその data-sly-template ファイルが呼び出されている場合のみにしてください。
例として、既存の例に加えて、別の
data-sly-template
ファイルを作成します。新しいファイルの名前は
extra.html
とします。これには、
data-sly-template
という名前の
extra
ブロックが含まれています。

/apps/my-example/component/info/extra.html

<template data-sly-template.extra="${@ text}" data-sly-use.extraHelper="${'ExtraHelper' @ text=text}"> <p>${extraHelper.reversedText}</p> </template>
テンプレート
extra
は、単一のパラメーター
text
を取ります。その後、Java use クラス
ExtraHelper
をローカル名
extraHelper
で初期化し、それに対して、テンプレートパラメーター
text
の値を use クラスパラメーター
text
として渡します。
テンプレートの本文は、プロパティ
extraHelper.reversedText
(内部で実際に
ExtraHelper.getReversedText()
を呼び出すプロパティ)を取得して、その値を表示します。
既存の
info.html
も、この新しいテンプレートを使用するように適応させます。

/apps/my-example/component/info/info.html

<div data-sly-use.info="Info" data-sly-use.extra="extra.html"> <h1>${info.lowerCaseTitle}</h1> <p>${info.lowerCaseDescription}</p> <div data-sly-call="${extra.extra @ text=properties.description}"></div> </div>
info.html
ファイルには、この時点で
data-sly-use
ステートメントが 2 つ含まれます。元からある、
Info
Java use クラスを読み込むステートメントと、ローカル名
extra
でテンプレートファイルを読み込む新しいステートメントです。
テンプレートブロックを
info.html
ファイル内に配置すれば、
data-sly-use
が 2 つになるのを防ぐことができますが、テンプレートファイルは別にしたほうが一般的であり、再利用もしやすくなります。
Info
クラスの採用方法は前と同じで、ゲッターメソッド
getLowerCaseTitle()
および
getLowerCaseDescription()
を、対応する HTL プロパティである
info.lowerCaseTitle
および
info.lowerCaseDescription
を使用して呼び出します。
次に、
data-sly-call
をテンプレート
extra
に対して実行し、
properties.description
の値を
text
パラメーターとして渡します。
Java use クラス
Info.java
は、新しいテキストパラメーターを処理するように変更されます。

/apps/my-example/component/info/ExtraHelper.java

package apps.my_example.components.info; import com.adobe.cq.sightly.WCMUsePojo; public class ExtraHelper extends WCMUsePojo { private String reversedText; ... @Override public void activate() throws Exception { String text = get("text", String.class); reversedText = new StringBuilder(text).reverse().toString(); ... } public String getReversedText() { return reversedText; } }
text
パラメーターは
get("text", String.class)
で取得され、値が反転されて、ゲッター
reversedText
を使用することにより、HTL オブジェクト
getReversedText()
として使用可能になります。

バンドルされた Java クラス

バンドル use クラスの場合、クラスは、AEM で、標準の OSGi バンドルデプロイメントメカニズムを使用してコンパイル、パッケージ、デプロイを行う必要があります。ローカルインストールとは異なり、use クラスの​
パッケージ宣言
​には、通常どおりに名前を付けます。

/apps/my-example/component/info/Info.java

package org.example.app.components; import com.adobe.cq.sightly.WCMUsePojo; public class Info extends WCMUsePojo { ... }
また、
data-sly-use
ステートメントは、ローカルクラス名のみではなく、完全修飾クラス名を参照する必要があります。

/apps/my-example/component/info/info.html

<div data-sly-use.info="org.example.app.components.info.Info"> <h1>${info.title}</h1> <p>${info.description}</p> </div>

WCMUsePojo
の代替策

Java use クラスを作成する最も一般的な方法は、
WCMUsePojo
を拡張することです。ただし、これ以外にもいくつかのオプションがあります。他の方法について理解するには、HTL の
data-sly-use
ステートメントが内部でどのように機能するかを理解することが役立ちます。
次の
data-sly-use
ステートメントがあるとします。
<div data-sly-use.
localName
="
UseClass
">
このステートメントは以下のように処理されます。
(1)
  • ローカルファイル
    UseClass.java
    が、HTL ファイルと同じディレクトリにある場合は、そのクラスをコンパイルして読み込んでみます。成功した場合は(2)に進みます。
  • Otherwise, interpret
    UseClass
    as a fully qualified class name and try to load it from the OSGi environment. 成功した場合は(2)に進みます。
  • 成功しなかった場合は、
    UseClass
    を HTL ファイルまたは JavaScript ファイルへのパスとして解釈し、そのファイルを読み込みます。成功した場合は(4)に進みます。
(2)
  • Try to adapt the current
    Resource
    to
    UseClass
    . If successful, go to (3).
  • 成功しなかった場合は、現在の
    Request
    UseClass
    に適応させてみます。成功した場合は(3)に進みます。
  • 成功しなかった場合は、引数ゼロのコンストラクターで
    UseClass
    をインスタンス化してみます。成功した場合は(3)に進みます。
(3)
  • HTL 内で、新しく適応または作成したオブジェクトを、名前
    localName
    にバインドします。
  • If
    UseClass
    implements
    io.sightly.java.api.Use
    then call the
    init
    method, passing the current execution context (in the form of a
    javax.scripting.Bindings
    object).
(4)
  • UseClass
    が、
    data-sly-template
    を含む HTL ファイルへのパスである場合は、テンプレートを用意します。
  • UseClass
    が JavaScript use クラスへのパスである場合は、use クラスを用意します( JavaScript Use-API を参照)。
上記の説明に関する重要な点を以下に示します。
  • Resource
    から適応可能なクラス、
    Request
    から適応可能なクラス、引数ゼロのコンストラクターを持つクラスはどれも use クラスになることができます。
    WCMUsePojo
    を拡張することも、
    Use
    を実装することも、必須ではありません。
  • ただし、use クラスが実際に
    ​実装する
    Use
    場合は、その
    init
    メソッドが現在のコンテキストで自動的に呼び出され、そのコンテキストに依存する初期化コードを配置できます。
  • WCMUsePojo
    を拡張する use クラスは、
    Use
    実装の特殊ケースです。これは便利なコンテキストメソッドを提供し、
    activate
    メソッドは
    Use.init
    から自動的に呼び出されます。

Use インターフェイスの直接実装

use クラスの最も一般的な作成方法は
WCMUsePojo
を拡張することですが、
io.sightly.java.api.Use
Use
インターフェイスで定義されるのは次の 1 つのメソッドのみです。
init
メソッドは、クラスの初期化時に、すべてのコンテキストオブジェクトおよび use クラスに渡されるすべてのパラメーターを保持する
Bindings
オブジェクトで呼び出されます。
All additional functionality (such as the equivalent of
WCMUsePojo.getProperties()
) must be implemented explicitly using the
javax.script.Bindings
object. 次に例を示します。

Info.java

import io.sightly.java.api.Use; public class MyComponent implements Use { ... @Override public void init(Bindings bindings) { // All standard objects/binding are available Resource resource = (Resource)bindings.get("resource"); ValueMap properties = (ValueMap)bindings.get("properties"); ... // Parameters passed to the use-class are also available String param1 = (String) bindings.get("param1"); } ... }
Use
を拡張するのではなく
WCMUsePojo
インターフェイスを自分で実装する主なケースは、既に存在するクラスのサブクラスを use クラスとして使用する場合です。

リソースから適応可能

もう 1 つのオプションは、
org.apache.sling.api.resource.Resource
から適応可能なヘルパークラスを使用することです。
DAM アセットの MIME タイプを表示する HTL スクリプトを作成する必要があるとします。この場合、HTL スクリプトが呼び出されるのは、JCR
Resource
をノードタイプ
Node
でラップする
dam:Asset
のコンテキスト内です。
dam:Asset
ノードは次のような構造になっています。

リポジトリ構造

{ "content": { "dam": { "geometrixx": { "portraits": { "jane_doe.jpg": { ... "jcr:content": { ... "metadata": { ... }, "renditions": { ... "original": { ... "jcr:content": { "jcr:primaryType": "nt:resource", "jcr:lastModifiedBy": "admin", "jcr:mimeType": "image/jpeg", "jcr:lastModified": "Fri Jun 13 2014 15:27:39 GMT+0200", "jcr:data": ..., "jcr:uuid": "22e3c598-4fa8-4c5d-8b47-8aecfb5de399" } }, "cq5dam.thumbnail.319.319.png": { ... }, "cq5dam.thumbnail.48.48.png": { ... }, "cq5dam.thumbnail.140.100.png": { ... } } } } } } } }
ここでは、サンプルプロジェクト geometrixx の一部として AEM のデフォルトインストールに含まれているアセット(JPEG 画像)を表示します。このアセットの名前は
jane_doe.jpg
で、MIME タイプは
image/jpeg
です。
To access the asset from within HTL, you can declare
com.day.cq.dam.api.Asset
as the class in the
data-sly-use
statement and then use a get method of
Asset
to retrieve the desired information. 次に例を示します。

mimetype.html

<div data-sly-use.asset="com.day.cq.dam.api.Asset"> <p>${asset.mimeType}</p> </div>
data-sly-use
ステートメントは、現在の
Resource
Asset
に適応し、
asset
というローカル名を付けるように、HTL に指示します。次に、HTL ゲッターの短縮形の
getMimeType
を使用して、
Asset
asset.mimeType
メソッドを呼び出します。

リクエストから適応可能

It is also possible to employ as a use-class any class that is adaptable from
org.apache.sling.api.SlingHttpServletRequest
As with the above case of a use-class adaptable from
Resource
, a use-class adaptable from
SlingHttpServletRequest
can be specified in the
data-sly-use
statement. 実行時に、現在のリクエストが与えられたクラスに適応され、結果のオブジェクトが HTL 内で使用可能になります。