L'API Java Use-API du langage de modèle HTML (HTML Template Language) permet à un fichier HTML d'accéder aux méthodes d'assistance dans une classe Java personnalisée par data-sly-use
. Cela permet à l’ensemble de la logique métier complexe d’être encapsulée dans le code Java, tandis que le code HTL traite uniquement la production directe des balises.
Un objet Java Use-API peut être un POJO simple, instancié par une implémentation particulière via le constructeur par défaut du POJO.
Les POJO Use-API peuvent également exposer une méthode publique, appelée init, avec la signature suivante :
/**
* Initializes the Use bean.
*
* @param bindings All bindings available to the HTL scripts.
**/
public void init(javax.script.Bindings bindings);
La carte bindings
peut contenir des objets qui fournissent un contexte au script HTML actuellement exécuté que l’objet Use-API peut utiliser pour son traitement.
Nous allons commencer avec un composant HTL qui n’a pas de classe d’utilisation. Il se compose d’un seul fichier, /apps/my-example/components/info.html
/apps/my-example/component/info/info.html
<div>
<h1>${properties.title}</h1>
<p>${properties.description}</p>
</div>
Nous avons également ajouté du contenu pour que le rendu de ce composant s’effectue à l’adresse /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."
}
Lorsque ce contenu est consulté, le fichier HTL est exécuté. Dans le code HTML, nous utilisons l'objet contextuel properties
pour accéder aux ressources title
et description
actuelles et les afficher. Le code HTML de sortie sera :
view-source:http://<host>:<port>/content/my-example.html
<div>
<h1>My Example</h1>
<p>This Is Some Example Content.</p>
</div>
Le composant info en tant que tel n’a pas besoin d’une classe d’utilisation pour remplir sa fonction (très simple). Cependant, dans certains cas, vous devez effectuer des opérations qui ne peuvent pas être effectuées dans HTL, et vous avez donc besoin d’une classe d’utilisation. Cependant, gardez à l’esprit les considérations suivantes :
Une classe d’utilisation doit être utilisée uniquement lorsqu’une opération ne peut pas être effectuée uniquement dans HTL.
Par exemple, supposons que vous souhaitiez que le composant info
affiche les propriétés title
et description
de la ressource, mais entièrement en minuscules. Comme HTL ne possède pas de méthode pour passer des chaînes en minuscules, vous aurez besoin d’une classe d’utilisation. Nous pouvons effectuer cela en ajoutant une classe d’utilisation Java et en modifiant le fichier info.html
comme suit :
/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;
}
}
Dans les sections suivantes, nous examinons les différentes parties du code.
La classe d’utilisation Java peut être installée de deux manières : en local ou groupée. Cet exemple utilise une installation locale.
Dans le cas d’une installation locale, le fichier source Java est placé à côté du fichier HTL, dans le même dossier de référentiel. Sur demande, la source est automatiquement compilée. Aucune étape de compilation ou d’assemblage distincte n’est requise.
Dans le cas d’une installation groupée, la classe Java doit être compilée et déployée au sein d’un groupe OSGi par le biais du mécanisme de déploiement groupé standard d’AEM (voir Classe Java groupée).
Une classe d’utilisation Java locale est recommandée quand la classe d’utilisation est spécifique au composant en question.
Une classe d’utilisation Java groupée est recommandée quand le code Java met en œuvre un service qui est utilisé par plusieurs composants HTL.
Lorsque vous utilisez une installation locale, le nom du package de la classe d’utilisation doit correspondre à l’emplacement du dossier de référentiel, avec tous les tirets dans le chemin remplacés par des traits de soulignement dans le nom du package.
Dans ce cas, Info.java
se trouve à l’adresse /apps/my-example/components/info
. Par conséquent, le package est 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 {
...
}
Il est recommandé d’utiliser des tirets dans les noms des éléments du référentiel lors du développement AEM. Toutefois, les tirets sont des caractères interdits dans les noms de package Java. C’est pourquoi tous les tirets dans le chemin d’accès au référentiel doivent être convertis en traits de soulignement dans le nom du package.
WCMUsePojo
Même s’il existe plusieurs façons d’incorporer une classe Java avec HTL (voir les alternatives à WCMUsePojo
), le plus simple est d’étendre la classe 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
...
}
Lorsque la classe d'utilisation est étendue à partir de WCMUsePojo
, l'initialisation est effectuée en remplaçant la méthode activate
:
...
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();
}
...
}
En règle générale, la méthode activate est utilisé pour précalculer et stocker (dans les variables de membres) les valeurs nécessaires dans votre code HTL, en fonction du contexte actif (la requête et la ressource actives, par exemple).
La classe WCMUsePojo
permet d’accéder au même ensemble d’objets de contexte qui est disponible dans un fichier HTL (voir Objets globaux).
Dans une classe qui étend WCMUsePojo
, les objets de contexte peuvent être consultés par nom en utilisant
<T> T get(String name, Class<T> type)
Vous pouvez également accéder directement aux objets de contexte fréquemment utilisés par la méthode pratique appropriée :
Une fois que la classe d’utilisation est initialisée, le fichier HTL est exécuté. Au cours de cette étape, HTL récupère généralement l’état de plusieurs variables de membres de la classe de l’utilisation et les restitue pour la présentation.
Pour permettre l’accès à ces valeurs à partir du fichier HTL, vous devez définir des méthodes getter personnalisées dans la classe d’utilisation, en respectant la convention de dénomination suivante :
getXyz
exposera une propriété d’objet appelée xyz
dans le fichier HTL.Dans l’exemple suivant, les méthodes getTitle
et getDescription
ont pour effet que les propriétés d’objet title
et description
deviennent accessibles dans le contexte du fichier HTL :
/apps/my-example/component/info/Info.java
...
public class Info extends WCMUsePojo {
...
public String getLowerCaseTitle() {
return lowerCaseTitle;
}
public String getLowerCaseDescription() {
return lowerCaseDescription;
}
}
L’attribut data-sly-use
est utilisé pour initialiser la classe d’utilisation dans votre code HTL. Dans notre exemple, l’attribut data-sly-use
indique que nous voulons utiliser la classe Info
. Nous pouvons utiliser seulement le nom local de la classe, parce que nous utilisons une installation locale (le fichier source Java ayant été placé dans le même dossier que le fichier HTL). Si nous utilisions une installation groupée, nous devrions spécifier le nom de classe complet.
/apps/my-example/component/info/info.html
<div data-sly-use.info="Info">
<h1>${info.lowerCaseTitle}</h1>
<p>${info.lowerCaseDescription}</p>
</div>
L'identifiant info
(après le point dans data-sly-use.info
) est utilisé dans le fichier HTL pour identifier la classe. La portée de cet identificateur est globale dans le fichier, une fois qu’il a été déclaré. Elle ne se limite pas à l’élément qui contient l’instruction 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>
L’identificateur info
est alors utilisé pour accéder aux propriétés de l’objet title
et description
, qui ont été exposées par les méthodes getter Info.getTitle
et Info.getDescription
.
/apps/my-example/component/info/info.html
<div data-sly-use.info="Info">
<h1>${info.lowerCaseTitle}</h1>
<p>${info.lowerCaseDescription}</p>
</div>
Désormais, lorsque nous accédons à /content/my-example.html
, elle renvoie le code HTML suivant :
view-source:http://<host>:<port>/content/my-example.html
<div>
<h1>my example</h1>
<p>this is some example content.</p>
</div>
Dans cette section, nous présenterons d'autres fonctionnalités qui vont au-delà de l'exemple simple ci-dessus :
WCMUsePojo
Les paramètres peuvent être transmis à un chemin de classe d’utilisation lors de l’initialisation. Par exemple, nous pouvons effectuer ce qui suit :
/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>
Dans ce cas, nous transmettons un paramètre appelé text
. La classe d’utilisation met la chaîne que nous récupérons en majuscules et affiche le résultat avec info.upperCaseText
. Voici la classe d’utilisation ajustée :
/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;
}
...
}
Le paramètre est accessible via la méthode WCMUsePojo
<T> T get(String paramName, Class<T> type)
Dans notre cas, l’instruction:
get("text", String.class)
La chaîne est alors inversée et exposée par le biais de la méthode:
getReverseText()
Bien que l’exemple ci-dessus soit techniquement correct, il n’est pas très judicieux de transmettre une valeur depuis HTL pour initialiser une classe d’utilisation, lorsque la valeur en question est disponible dans le contexte d’exécution du code HTL (ou, trivialement, la valeur est statique, comme ci-dessus).
C’est parce que la classe d’utilisation aura toujours accès au même contexte d’exécution que le code HTL. Cela entraîne une ’importation recommandée :
La transmission d’un paramètre à une classe d’utilisation ne doit être effectuée que lorsque cette dernière est utilisée dans un fichier data-sly-template
, qui est lui-même appelé à partir d’un autre fichier HTL avec les paramètres qui doivent être transmis.
Par exemple, créons un fichier data-sly-template
distinct avec notre exemple existant. Nous appellerons le nouveau fichier extra.html
. Il contient un bloc data-sly-template
appelé 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>
Le modèle extra
prend un seul paramètre, text
. Il initialise ensuite la classe d’utilisation Java ExtraHelper
extraHelper
avec le nom local et lui transmet la valeur du paramètre de modèle text
en tant que paramètre de classe d’utilisation text
.
Le corps du modèle récupère la propriété extraHelper.reversedText
(qui, de son côté, appelle en fait ExtraHelper.getReversedText()
) et affiche cette valeur.
Nous adaptons également notre fichier info.html
existant pour utiliser ce nouveau modèle :
/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>
Le fichier info.html
contient désormais deux instructions data-sly-use
, celle d’origine qui importe la classe d’utilisation Java Info
, et une nouvelle qui importe le fichier de modèle sous le nom local extra
.
Notez que nous aurions pu placer le bloc de modèle à l’intérieur du fichier info.html
pour éviter le deuxième data-sly-use
, mais un fichier de modèle distinct est plus courant et plus facile à réutiliser.
La classe Info
est utilisée comme avant, en appelant ses méthodes getter getLowerCaseTitle()
et getLowerCaseDescription()
via leurs propriétés HTL correspondantes info.lowerCaseTitle
et info.lowerCaseDescription
.
Nous effectuons ensuite un data-sly-call
sur le modèle extra
et lui transmettons la valeur properties.description
en tant que paramètre text
.
La classe d’utilisation Java Info.java
est modifiée pour gérer le nouveau paramètre de texte :
/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;
}
}
Le paramètre text
est récupéré avec get("text", String.class)
, et la valeur est inversée et rendue disponible en tant qu’objet HTL reversedText
par le getter getReversedText()
.
Avec une classe d’utilisation groupée, la classe doit être compilée, mise en package et déployée dans AEM à l’aide du mécanisme de déploiement standard de regroupement OSGi. Contrairement à installation locale, la classe d’utilisation de déclaration du package doit être appelé normalement :
/apps/my-example/component/info/Info.java
package org.example.app.components;
import com.adobe.cq.sightly.WCMUsePojo;
public class Info extends WCMUsePojo {
...
}
et l’instruction data-sly-use
doit référencer le nom de classe entièrement qualifié, et non pas simplement le nom de classe local :
/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
La méthode la plus fréquente pour créer une classe d’utilisation Java consiste à étendre WCMUsePojo
. Cependant, il existe un certain nombre d’options supplémentaires. Pour comprendre ces variantes, il est utile de comprendre comment l’instruction HTL data-sly-use
s’exécute en arrière-plan.
Supposons que vous ayez l’instruction data-sly-use
suivante :
<div data-sly-use.
localName
="
UseClass
">
Le système traite l’instruction comme suit :
(1)
UseClass.java
existe dans le même répertoire que le fichier HTL, essayez de compiler et de charger cette classe. En cas de réussite, accédez à la partie (2).UseClass
comme nom de classe entièrement qualifié et essayez de le charger à partir de l’environnement OSGi. En cas de réussite, accédez à la partie (2).UseClass
en tant que chemin d’accès vers un fichier HTL ou JavaScript et chargez ce fichier. En cas de réussite, accédez à la partie (4).(2)
Resource
actuel à UseClass
. En cas de réussite, passez à (3).Request
active à UseClass
. En cas de réussite, accédez à la partie (3).UseClass
avec un constructeur sans argument. En cas de réussite, accédez à la partie (3).(3)
localName
.UseClass
implémente io.sightly.java.api.Use
, appelez la méthode init
, en transmettant le contexte d'exécution actuel (sous la forme d'un objet javax.scripting.Bindings
).(4)
UseClass
est un chemin d’accès à un fichier HTL contenant un data-sly-template
, préparez le modèle.UseClass
est un chemin d’accès à une classe d’utilisation JavaScript, préparez la classe d’utilisation (voir Use-API JavaScript).Voici quelques points importants à propos de la description ci-dessus :
Resource
ou de Request
, ou qui dispose d’un constructeur sans argument peut être une classe d’utilisation. La classe ne doit pas nécessairement étendre WCMUsePojo
ni même mettre en œuvre Use
.Use
, sa méthode init
est automatiquement appelée avec le contexte actif, ce qui vous permet d’y placer le code d’initialisation qui dépend de ce contexte.WCMUsePojo
est seulement un cas spécial de mise en œuvre de Use
. Elle fournit les méthodes de contexte pratiques et sa méthode activate
est appelée automatiquement à partir de Use.init
.Bien que la méthode la plus simple pour créer une classe d’utilisation consiste à étendre WCMUsePojo
, il est également possible de mettre en œuvre directement l’interface io.sightly.java.api.Use
elle même.
L’interfaceUse
ne définit qu’une seule méthode :
public void init(javax.script.Bindings bindings)
La méthode init
sera appelée lors de l’initialisation de la classe avec un objet Bindings
qui contient tous les objets de contexte et tous les paramètres transmis dans la classe d’utilisation.
Toutes les fonctionnalités supplémentaires (telles que l’équivalent de WCMUsePojo.getProperties()
) doivent être implémentées explicitement à l’aide de l’objet javax.script.Bindings
. Par exemple :
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");
}
...
}
La principale raison pour laquelle vous devriez mettre en œuvre l’interface Use
par vous-même au lieu d’étendre WCMUsePojo
est si vous souhaitez utiliser une sous-classe d’une classe existante en tant que classe d’utilisation.
Une autre option consiste à utiliser une classe d’assistance qui est adaptable à partir de org.apache.sling.api.resource.Resource
.
Supposons que vous ayez besoin d’écrire un script HTL qui affiche le mimetype d’une ressource DAM. Dans ce cas, vous savez que quand votre script HTL est appelé, ce sera dans le contexte d’une Resource
qui enveloppe un Node
JCR de type dam:Asset
.
Vous savez qu’un nœud dam:Asset
possède le type de structure suivant :
{
"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": {
...
}
}
}
}
}
}
}
}
Nous montrons ici la ressource (une image JPEG) qui est fournie avec une installation par défaut d’AEM en tant qu’exemple de projet geometrixx. La ressource est appelée jane_doe.jpg
et son mimetype est image/jpeg
.
Pour accéder à la ressource à partir de HTL, vous pouvez déclarer com.day.cq.dam.api.Asset
comme classe dans l'instruction data-sly-use
, puis utiliser une méthode get de Asset
pour récupérer les informations souhaitées. Par exemple :
mimetype.html
<div data-sly-use.asset="com.day.cq.dam.api.Asset">
<p>${asset.mimeType}</p>
</div>
L’instruction data-sly-use
demande à HTL d’adapter la Resource
active à un Asset
et de lui donner le nom local asset
. Il appelle ensuite la méthode getMimeType
de Asset
à l’aide du raccourci getter HTL : asset.mimeType
.
Il est également possible d'utiliser comme classe d'utilisation toute classe adaptable à partir de org.apache.sling.api.SlingHttpServletRequest
Comme pour le cas ci-dessus d'une variable adaptable use-class de Resource
, une variable use-class adaptable de SlingHttpServletRequest
peut être spécifiée dans l'instruction data-sly-use
. Lors de l’exécution, la requête active sera adaptée à la classe donnée et l’objet produit sera rendu disponible dans HTL.