La API de uso de Java de HTL

La API de uso de Java de HTL permite que un archivo HTL acceda a los métodos de ayuda en una clase Java personalizada.

Caso práctico

La API de uso de Java de HTL permite que un archivo HTL acceda a los métodos de ayuda en una clase Java personalizada mediante data-sly-use. Esto permite encapsular toda la lógica empresarial compleja en el código Java, mientras que el código HTL solo trata la producción de marcado directo.

Un objeto de la API de uso de Java puede ser un POJO simple, creado por una implementación particular a través del constructor predeterminado del POJO.

Los POJO de la API de uso también pueden exponer un método público, denominado init, con la siguiente firma:

    /**
     * Initializes the Use bean.
     *
     * @param bindings All bindings available to the HTL scripts.
     **/
    public void init(javax.script.Bindings bindings);

El mapa bindings puede contener objetos que proporcionan contexto al script HTL que el objeto de la API de uso puede utilizar para su procesamiento.

Un ejemplo sencillo

Este ejemplo ilustra el empleo de la API de uso.

NOTA

Está simplificado para ilustrar simplemente su utilización. En un entorno de producción, se recomienda emplear los Modelos de Sling.

Empezaremos con un componente HTL, llamado info, que no tiene una clase de uso. Consiste en un solo archivo, /apps/my-example/components/info.html

<div>
    <h1>${properties.title}</h1>
    <p>${properties.description}</p>
</div>

También agregamos contenido para este componente para renderizarlo en /content/my-example/:

{
    "sling:resourceType": "my-example/component/info",
    "title": "My Example",
    "description": "This Is Some Example Content."
}

Cuando se accede a este contenido, se ejecuta el archivo HTL. Dentro del código HTL, utilizamos el objeto de contexto properties para acceder al title y description del recurso actual y mostrarlos. El archivo de salida /content/my-example.html será el siguiente:

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

Añadir una clase de uso

El componente info tal como está, no necesita una clase de uso para realizar su función simple. Sin embargo, hay casos en los que necesita hacer cosas que no se pueden hacer en HTL y por lo tanto necesita una clase de uso. Pero tenga en cuenta lo siguiente:

NOTA

Una clase de uso solo debe usarse cuando algo no se pueda hacer solo en HTL.

Por ejemplo, supongamos que desea que el componente info muestre las propiedades title y description del recurso, pero todo en minúsculas. Como HTL no tiene un método para cadenas en minúsculas, necesitará una clase use. Podemos hacerlo añadiendo una clase de uso de Java y cambiando /apps/my-example/component/info/info.html de la siguiente manera:

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

Además, creamos /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;
    }
}

Consulte Javadocs de com.adobe.cq.sightly.WCMUsePojo para obtener más información.

Ahora recorremos las diferentes partes del código.

Clase Java local frente a un paquete

La clase de uso de Java puede instalarse de dos maneras:

  • Local: en una instalación local, el archivo de origen Java se coloca junto al archivo HTL, en la misma carpeta de repositorio. La fuente se compila automáticamente bajo demanda. No es necesario compilar ni empaquetar por separado.
  • Paquete: en una instalación de paquete, la clase Java debe compilarse e implementarse dentro de un paquete OSGi usando el mecanismo de implementación de paquete de AEM estándar (consulte la sección Clase Java en paquete).

Para saber qué método utilizar, tenga en cuenta estos dos puntos:

  • Se recomienda una clase de uso local de Java cuando la clase de uso es específica del componente en cuestión.
  • Se recomienda una clase de uso en paquete de Java cuando el código Java implementa un servicio al que se accede desde varios componentes HTL.

Este ejemplo utiliza una instalación local.

El paquete Java es la ruta del repositorio

Cuando se utiliza una instalación local, el nombre del paquete de la clase use debe coincidir con el de la ubicación de la carpeta del repositorio, con los guiones de la ruta reemplazados por guiones bajos en el nombre del paquete.

En este caso, Info.java se encuentra en /apps/my-example/components/info, por lo que el paquete es apps.my_example.components.info:

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo {

   ...

}
NOTA

El uso de guiones en los nombres de los elementos del repositorio es una práctica recomendada en el desarrollo de AEM. Sin embargo, los guiones no se admiten en los nombres de paquetes Java. Por este motivo, todos los guiones de la ruta del repositorio deben convertirse en guiones bajos en el nombre del paquete.

Ampliación de WCMUsePojo

Aunque hay varias formas de incorporar una clase Java con HTL (consulte la sección Alternativas a WCMUsePojo), la más sencilla es ampliar la clase WCMUsePojo. Para nuestro ejemplo /apps/my-example/component/info/Info.java:

package apps.my_example.components.info;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo

    ...
}

Inicialización de la clase

Cuando la clase de uso se amplía desde WCMUsePojo, la inicialización se realiza anulando el método activate, en este caso en /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();
    }

...

}

Contexto

Normalmente, el método activate se utiliza para precalcular y almacenar (en variables de miembros) los valores necesarios en el código HTL, según el contexto actual (la solicitud y el recurso actuales, por ejemplo).

La clase WCMUsePojo proporciona acceso al mismo conjunto de objetos de contexto que están disponibles en un archivo HTL (consulte el documento Objetos globales).

En una clase que extiende WCMUsePojo, se puede acceder a los objetos de contexto por nombre mediante

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

Como alternativa, se puede acceder directamente a los objetos de contexto utilizados con frecuencia mediante el método de conveniencia adecuado, tal y como se indica en esta tabla.

Objeto Método de conveniencia
PageManager getPageManager()
Page getCurrentPage()
Page getResourcePage()
ValueMap getPageProperties()
ValueMap getProperties()
Designer getDesigner()
Design getCurrentDesign()
Style getCurrentStyle()
Component getComponent()
ValueMap getInheritedProperties()
Resource getResource()
ResourceResolver getResourceResolver()
SlingHttpServletRequest getRequest()
SlingHttpServletResponse getResponse()
SlingScriptHelper getSlingScriptHelper()

Métodos de obtención

Una vez que la clase use se ha inicializado, se ejecuta el archivo HTL. Durante esta etapa, HTL generalmente extraerá el estado de varias variables de miembro de la clase use y las procesará para su presentación.

Para proporcionar acceso a estos valores desde el archivo HTL, debe definir métodos de obtención personalizados en la clase de uso según la siguiente convención de nomenclatura:

  • Un método del formulario getXyz mostrará dentro del archivo HTL una propiedad de objeto llamada xyz.

En el archivo de ejemplo siguiente /apps/my-example/component/info/Info.java, los métodos getTitle y getDescription hacen que las propiedades de objeto title y description sean accesibles en el contexto del archivo HTL.

...

public class Info extends WCMUsePojo {

    ...

    public String getLowerCaseTitle() {
        return lowerCaseTitle;
    }

    public String getLowerCaseDescription() {
        return lowerCaseDescription;
    }
}

Atributo data-sly-use

El atributo data-sly-use se utiliza para inicializar la clase de uso dentro del código HTL. En nuestro ejemplo, el atributo data-sly-use declara que queremos usar la clase Info. Podemos usar solo el nombre local de la clase porque estamos utilizando una instalación local (después de colocar el archivo de origen Java en la misma carpeta que el archivo HTL). Si estuviéramos utilizando una instalación de paquete tendríamos que especificar el nombre de clase completo.

Observe el uso en este ejemplo /apps/my-example/component/info/info.html.

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

Identificador local

El identificador info (después del punto en data-sly-use.info) se utiliza dentro del archivo HTL para identificar la clase. El ámbito de este identificador es global dentro del archivo, una vez declarado. No se limita al elemento que contiene la instrucción data-sly-use.

Observe el uso en este ejemplo /apps/my-example/component/info/info.html.

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

Obtención de propiedades

A continuación, el identificador info se utiliza para acceder a las propiedades de objeto title y description que se expusieron mediante los métodos de captador Info.getTitle y Info.getDescription.

Observe el uso en este ejemplo /apps/my-example/component/info/info.html.

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

Salida

Ahora, cuando accedamos a /content/my-example.html, devolverá el siguiente archivo /content/my-example.html.

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

Este ejemplo se ha simplificado para ilustrar su uso. En un entorno de producción, se recomienda emplear los Modelos de Sling.

Más allá de los conceptos básicos

En esta sección presentaremos algunas funciones adicionales que van más allá del sencillo ejemplo anterior.

  • Pasar parámetros a una clase de uso
  • Clase de uso de Java en paquete

Pasar parámetros

Los parámetros se pueden pasar a una clase de uso tras la inicialización. Por ejemplo, podríamos hacer algo así:

Para obtener más información, consulte Documentación del Motor de script HTL de Sling.

Clase Java agrupada

Con una clase de uso del paquete, la clase debe compilarse, empaquetarse e implementarse en AEM utilizando el mecanismo de implementación del paquete OSGi estándar. A diferencia de una instalación local, la declaración del paquete de la clase de uso debe llamarse normalmente como en este ejemplo /apps/my-example/component/info/Info.java.

package org.example.app.components;

import com.adobe.cq.sightly.WCMUsePojo;

public class Info extends WCMUsePojo {
    ...
}

Y la instrucción data-sly-use debe hacer referencia al nombre de clase completo, en lugar de solo al local, como en este ejemplo /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>

En esta página