HTL Java Use-API
The HTL Java Use-API enables an HTL file to access helper methods in a custom Java class.
Use Case
The HTL Java Use-API enables an HTL file to access helper methods in a custom Java class through data-sly-use
. This allows all complex business logic to be encapsulated in the Java code, while the HTL code deals only with direct markup production.
A Java Use-API object can be a simple POJO, instantiated by a particular implementation through the POJO’s default constructor.
The Use-API POJOs can also expose a public method, called init, with the following signature:
/**
* Initializes the Use bean.
*
* @param bindings All bindings available to the HTL scripts.
**/
public void init(javax.script.Bindings bindings);
The bindings
map can contain objects that provide context to the currently executed HTL script that the Use-API object can use for its processing.
A Simple Example
This example illustrates the usage of the Use-API.
We start with an HTL component, called info
, that does not have a use-class. It consists of a single file, /apps/my-example/components/info.html
<div>
<h1>${properties.title}</h1>
<p>${properties.description}</p>
</div>
We also add some content for this component to render at /content/my-example/
:
{
"sling:resourceType": "my-example/component/info",
"title": "My Example",
"description": "This Is Some Example Content."
}
When this content is accessed, the HTL file is executed. Within the HTL code, we use the context object properties
to access the current resource’s title
and description
and display them. The output file /content/my-example.html
will be:
<div>
<h1>My Example</h1>
<p>This Is Some Example Content.</p>
</div>
Adding a Use-Class
The info
component as it stands does not need a use-class to perform its simple function. There are cases, however, where you need to do things that cannot be done in HTL and so you need a use-class. But keep in mind the following:
For example, suppose that you want the info
component to display the title
and description
properties of the resource, but all in lowercase. Since HTL does not have a method for lowercasing strings, you will need a use-class. We can do this by adding a Java use-class and changing /apps/my-example/component/info/info.html
as follows:
<div data-sly-use.info="Info">
<h1>${info.lowerCaseTitle}</h1>
<p>${info.lowerCaseDescription}</p>
</div>
Additionally we create /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;
}
}
Please see the Javadocs for com.adobe.cq.sightly.WCMUsePojo
for more details.
Now let’s walk through the different parts of the code.
Local vs. Bundle Java Class
The Java use-class can be installed in two ways:
- Local - In a local install, the Java source file is placed alongside the HTL file, in the same repository folder. The source is automatically compiled on demand. No separate compilation or packaging step is required.
- Bundle - In a bundle install, the Java class must be compiled and deployed within an OSGi bundle using the standard AEM bundle deployment mechanism (see the section Bundled Java Class).
To know which method to use when, keep these two points in mind:
- A local Java use-class is recommended when the use-class is specific to the component in question.
- A bundle Java use-class is recommended when the Java code implements a service that is accessed from multiple HTL components.
This example uses a local install.
Java Package is Repository Path
When a local install is used, the package name of the use-class must match that of the repository folder location, with any hyphens in the path replaced by underscores in the package name.
In this case Info.java
is located at /apps/my-example/components/info
so the package is apps.my_example.components.info
:
package apps.my_example.components.info;
import com.adobe.cq.sightly.WCMUsePojo;
public class Info extends WCMUsePojo {
...
}
Extending WCMUsePojo
While there are a number of ways of incorporating a Java class with HTL (see the section Alternatives to WCMUsePojo
), the simplest is to extend the WCMUsePojo
class. For our example /apps/my-example/component/info/Info.java
:
package apps.my_example.components.info;
import com.adobe.cq.sightly.WCMUsePojo;
public class Info extends WCMUsePojo
...
}
Initializing the Class
When the use-class is extended from WCMUsePojo
, initialization is performed by overriding the activate
method, in this case in /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();
}
...
}
Context
Typically, the activate method is used to precompute and store (in member variables) the values needed in your HTL code, based on the current context (the current request and resource, for example).
The WCMUsePojo
class provides access to the same set of context objects as are available within an HTL file (see the document Global Objects.)
In a class that extends WCMUsePojo
, context objects can be accessed by name using
<T> T get(String name, Class<T> type)
Alternatively, commonly used context objects can be accessed directly by the appropriate convenience method as listed in this table.
Getter Methods
Once the use-class has initialized, the HTL file is run. During this stage HTL will typically pull in the state of various member variables of the use-class and render them for presentation.
To provide access to these values from within the HTL file, you must define custom getter methods in the use-class according to the following naming convention:
- A method of the form
getXyz
will expose within the HTL file an object property calledxyz
.
In the following example file /apps/my-example/component/info/Info.java
, the methods getTitle
and getDescription
result in the object properties title
and description
becoming accessible within the context of the HTL file.
...
public class Info extends WCMUsePojo {
...
public String getLowerCaseTitle() {
return lowerCaseTitle;
}
public String getLowerCaseDescription() {
return lowerCaseDescription;
}
}
data-sly-use Attribute
The data-sly-use
attribute is used to initialize the use-class within your HTL code. In our example, the data-sly-use
attribute declares that we want to use the class Info
. We can use just the local name of the class because we are using a local install (having placed the Java source file is in the same folder as the HTL file). If we were using a bundle install we would have to specify the fully qualified class name.
Note the usage in this /apps/my-example/component/info/info.html
example.
<div data-sly-use.info="Info">
<h1>${info.lowerCaseTitle}</h1>
<p>${info.lowerCaseDescription}</p>
</div>
Local Identifier
The identifier info
(after the dot in data-sly-use.info
) is used within the HTL file to identify the class. The scope of this identifier is global within the file, after it has been declared. It is not limited to the element that contains the data-sly-use
statement.
Note the usage in this /apps/my-example/component/info/info.html
example.
<div data-sly-use.info="Info">
<h1>${info.lowerCaseTitle}</h1>
<p>${info.lowerCaseDescription}</p>
</div>
Getting Properties
The identifier info
is then used to access the object properties title
and description
that were exposed through the getter methods Info.getTitle
and Info.getDescription
.
Note the usage in this /apps/my-example/component/info/info.html
example.
<div data-sly-use.info="Info">
<h1>${info.lowerCaseTitle}</h1>
<p>${info.lowerCaseDescription}</p>
</div>
Output
Now, when we access /content/my-example.html
it will return the following /content/my-example.html
file.
<div>
<h1>my example</h1>
<p>this is some example content.</p>
</div>
Beyond the Basics
In this section introduces some further features that go beyond the simple example described previously.
- Passing parameters to a use-class
- Bundled Java use-class
Passing Parameters
Parameters can be passed to a use-class upon initialization.
For details, please refer to the Sling HTL Scripting Engine documentation.
Bundled Java Class
With a bundled use-class the class must be compiled, packaged, and deployed in AEM using the standard OSGi bundle deployment mechanism. In contrast with a local install, the use-class package declaration should be named normally as in this /apps/my-example/component/info/Info.java
example.
package org.example.app.components;
import com.adobe.cq.sightly.WCMUsePojo;
public class Info extends WCMUsePojo {
...
}
And the data-sly-use
statement must reference the fully qualified class name, as opposed to just the local class name as in this /apps/my-example/component/info/info.html
example.
<div data-sly-use.info="org.example.app.components.info.Info">
<h1>${info.title}</h1>
<p>${info.description}</p>
</div>