Show Menu
トピック×

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 内で使用可能になります。