Arti­cle updat­ed on Dec 5, 2017.

Today, in the part four of the intro­duc­tion to the HTML Tem­plate Lan­guage (HTL), for­mer­ly known as Sight­ly, I’ll share a deep-dive on how to use the Java Use-API to imple­ment your cus­tom (com­plex) log­ic into your com­po­nents.

Inter­est­ed in the oth­ers parts? Here they are: part 1, part 2, part 3, part 5.

The basic nota­tion of the Use-API looks like this is an HTL com­po­nent:

<div data-sly-use.myComponent="com.myproject.MyComponent">
    ${myComponent.calculatedValue}
</div>

For this exam­ple, to show the full range of pos­si­bil­i­ties, let’s also pass a para­me­ter, so the con­tent of the data-sly-use attribute must be changed to an expres­sion with an option:

<div data-sly-use.myComponent="${'com.myproject.MyComponent' @ param1='one', param2='two'}">
    ${myComponent.calculatedValue}
</div>

In this exam­ple you have the fol­low­ing:

  • the class ‘com.myproject.MyComponent’ is instan­ti­at­ed
  • two para­me­ters are passed to the object via expres­sion options
  • the iden­ti­fi­er ‘myCompo­nent’ is used to expose the result­ing object
  • the method get­Cal­cu­lat­ed­Val­ue() is called

Now let’s look at the imple­men­ta­tion for this, you have 7(!) options:

  1. Class that imple­ments the Use inter­face
  2. Class that extends WCMUse­Po­jo class
  3. Class that is adapt­able from Resource (resource.adaptTo(YourClass))
  4. Class that is adapt­able from Request (request.adaptTo(YourClass))
  5. Class that is adapt­able from avail­able adapters in your com­po­nent
  6. OSGi ser­vice
  7. POJO class

Actu­al­ly, there is even a 8th option, but I wrote a sep­a­rate arti­cle for that one:
Using serv­er-side JavaScript with the HTML Tem­plate Lan­guage

Below, I will show an exam­ple of the 7 Java options, so that you can see what is need­ed for each.
You can switch the imple­men­ta­tion between all 7 options with­out chang­ing any­thing in the component’s HTL file.

Option 1: Class implementing the Use interface

In this case you need to imple­ment init(), and do the all the log­ic in there. Via the bind­ings-object you can access all the objects also avail­able on the com­po­nent.

import org.apache.sling.scripting.sightly.pojo.Use;

public class MyComponent implements Use {

    private String value;

    @Override
    public void init(Bindings bindings) {
        // All standard objects are available as bindings
        Resource resource = (Resource) bindings.get("resource");

        // Parameters are also passed as bindings
        String param1 = (String) bindings.get("param1");
        String param2 = (String) bindings.get("param2");

        value = resource.getPath() + param1 + param2;
    }

    public String getCalculatedValue() {
        return value;
    }
}

It would also have been pos­si­ble to make the “val­ue” mem­ber of the class pub­lic to access it direct­ly from the HTL file, instead of cre­at­ing a get­Cal­cu­lat­ed­Val­ue method.

Option 2: Class extending WCMUsePojo class

This option is sim­i­lar like the Use-inter­face, but has some more helper func­tion­al­i­ty that you can use. Meth­ods like getRe­source(), getCur­rent­Page() etc are already there for you to use.

import com.adobe.cq.sightly.WCMUsePojo;

public class MyComponent extends WCMUsePojo {

    private String value;

    @Override
    public void activate() {
       // Convenience methods allow to access the default bindings
       Resource resource = getResource();

       // Parameters are can be accessed via a get() method
       String param1 = get("param1", String.class);
       String param2 = get("param2", String.class);

       value = resource.getPath() + param1 + param2;
    }

    public String getCalculatedValue() {
        return value;
    }
}

Option 3: Class adaptable from Resource

The code exam­ple giv­en here show how to make your class capa­ble of being adapt­ed from a Resource. Based on that Resource-object you need to pass in the right info to your POJO. In this case you can have a plain POJO with­out any depen­den­cy to AEM or HTL.

NOTE: In this option, you can­not access the para­me­ters.

@Model(adaptables = Resource.class)
public class MyComponent {

  @Inject
  private String text;

  private String modifiedText;

  @PostConstruct
  protected void init() {
    modifiedText = text + "modified";
  }

  public String getModifiedText() {
    return modifiedText;
  }
}

Option 4: Class adaptable from Request

Like option 3, but now based on the request.

@Model(adaptables = SlingHttpServletRequest.class)
public class MyComponent {

    @Inject
    private SlingHttpServletRequest request;

    @Inject 
    private MyService myService;

    private String value;
   
    @PostConstruct
    protected void init() {
      value = myService.execute(request);
    }

    public String getValue() {
      return value;
    }
}

 

Option 5: Flexible adapters

Avail­able since AEM6.3.1.1. (AEM6.3+SP1CFP1) you can now spec­i­fy what adapt­able should be used (not only Resource or Request.

Here an exam­ple on how you can use this.

<sly data-sly-use.session="${'javax.jcr.Session' @ adaptable = resource.resourceResolver}" />

${session.userID}

Option 6: OSGi-service

You can also use an OSGi-ser­vice in the data-sly-use attrib­ut­es, how­ev­er you can’t pass in para­me­ters

Option 7: POJO class

Last but not least you can also use a POJO class in your HTL use-api, you can’t pass in para­me­ters. But it might come handy in case you want to use con­stants that are locat­ed in a class.
Main require­ment is that the class has a con­struc­tor that has no para­me­ters.

Conclusion

The great thing of the Use-API is that you have sev­er­al options to imple­ment the log­ic on the serv­er-side. And you can mix options in your com­po­nents, depend­ing on the require­ments you have. I hope you enjoyed this part, I am already think­ing of part 5.

@heervisscher

Read-on

Here are the oth­er arti­cles of my intro­duc­tion series:

Oth­er posts on the top­ic:

And here oth­er resources to learn more about it:

0 comments