HTL Java Use-API

HTML Template Language(HTL)Java Use-APIを使用すると、HTLファイルは、data-sly-useを介してカスタムJavaクラス内のヘルパーメソッドにアクセスできます。 これにより、複雑なビジネスロジックをすべて 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マップには、現在実行されているHTLスクリプトにコンテキストを提供するオブジェクトを含めることができます。このHTLスクリプトは、Use-APIオブジェクトが処理に使用できます。

簡単な例

まず、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 ファイルが実行されます。HTLコード内では、コンテキストオブジェクトpropertiesを使用して現在のリソースのtitledescriptionにアクセスし、それらを表示します。 出力される 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 コンポーネントで、リソースの titledescription プロパティを、すべて小文字で表示するとします。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;
    }
}

以降の節では、コードの様々な部分について順を追って説明します。

ローカルとバンドルのJavaクラス

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

    ...
}

クラスの初期化

use-classをWCMUsePojoから拡張すると、初期化はactivateメソッドをオーバーライドして実行されます。

/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 を拡張するクラスでは、名前を基準として、以下のコードを使用してコンテキストオブジェクトにアクセスできます。

<T> T get(String name, Class<T> type)

また、以下のような適切で​便利なメソッド​によって、よく使用されるコンテキストオブジェクトに直接アクセスできます。

PageManager getPageManager()
ページ getCurrentPage()
ページ getResourcePage()
ValueMap getPageProperties()
ValueMap getProperties()
デザイナー getDesigner()
デザイン getCurrentDesign()
スタイル getCurrentStyle()
コンポーネント getComponent()
ValueMap getInheritedProperties()
Resource getResource()
ResourceResolver getResourceResolver()
SlingHttpServletRequest getRequest()
SlingHttpServletResponse getResponse()
SlingScriptHelper getSlingScriptHelper()

ゲッターメソッド

use クラスが初期化されると、HTL ファイルが実行されます。この段階で、HTL は通常、use クラスの様々なメンバー変数の状態を引っ張ってきて、プレゼンテーション用にレンダリングします。

HTL ファイル内からこれらの値へアクセスできるようにするには、以下の命名規則に従って、use クラスでカスタムのゲッターメソッドを定義する必要があります。

  • getXyz という形式のメソッドを使用すると、HTL ファイル内で xyz という名前のオブジェクトプロパティがアクセス可能になります。

次の例では、メソッドgetTitlegetDescriptionによって、オブジェクトのプロパティtitledescriptionがHTLファイルのコンテキスト内でアクセス可能になります。

/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>

ローカル識別子

識別子infodata-sly-use.infoのドットの後)は、HTLファイル内でクラスを識別するために使用されます。 宣言された識別子は、ファイル内でグローバルスコープとして認識されます。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)に進みます。
  • それ以外の場合は、UseClassを完全修飾クラス名として解釈し、OSGi環境から読み込もうとします。 成功した場合は(2)に進みます。
  • 成功しなかった場合は、UseClass を HTL ファイルまたは JavaScript ファイルへのパスとして解釈し、そのファイルを読み込みます。成功した場合は(4)に進みます。

(2)

  • 現在のResourceUseClassに適応させてみます。成功した場合は、(3)に移動します。
  • 成功しなかった場合は、現在の RequestUseClass に適応させてみます。成功した場合は(3)に進みます。
  • 成功しなかった場合は、引数ゼロのコンストラクターで UseClass をインスタンス化してみます。成功した場合は(3)に進みます。

(3)

  • HTL 内で、新しく適応または作成したオブジェクトを、名前 localName にバインドします。
  • UseClassio.sightly.java.api.Useを実装している場合は、initメソッドを呼び出し、現在の実行コンテキストを(javax.scripting.Bindingsオブジェクトの形式で)渡します。

(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 つのメソッドのみです。

public void init(javax.script.Bindings bindings)

init メソッドは、クラスの初期化時に、すべてのコンテキストオブジェクトおよび use クラスに渡されるすべてのパラメーターを保持する Bindings オブジェクトで呼び出されます。

すべての追加機能(WCMUsePojo.getProperties()と同等の機能)は、javax.script.Bindingsオブジェクトを使用して明示的に実装する必要があります。 次に例を示します。

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 です。

HTL内からアセットにアクセスするには、com.day.cq.dam.api.Assetdata-sly-useステートメントのクラスとして宣言し、Assetのgetメソッドを使用して必要な情報を取得します。 次に例を示します。

mimetype.html

<div data-sly-use.asset="com.day.cq.dam.api.Asset">
  <p>${asset.mimeType}</p>
</div>

data-sly-use ステートメントは、現在の ResourceAsset に適応し、asset というローカル名を付けるように、HTL に指示します。次に、HTL ゲッターの短縮形の getMimeType を使用して、Assetasset.mimeType メソッドを呼び出します。

リクエストから適応可能

また、org.apache.sling.api.SlingHttpServletRequestから適応可能なクラスはどれでも、use-classとして使用できます

上記のResourceから適応可能な使用クラスの場合と同様に、SlingHttpServletRequestから適応可能な使用クラスをdata-sly-use文に指定することができる。 実行時に、現在のリクエストが与えられたクラスに適応され、結果のオブジェクトが HTL 内で使用可能になります。

このページ

Adobe Summit Banner

A virtual event April 27-28.

Expand your skills and get inspired.

Register for free
Adobe Summit Banner

A virtual event April 27-28.

Expand your skills and get inspired.

Register for free