A primer on programmatic tagging in AEM

A primer on programmatic tagging in AEM

The purpose of this blog is to introduce the AEM developer to writing tags in AEM Applications via the Tagging API. This post assumes that the reader is familiar with basic tagging in AEM, but here and there, things will be explained for the ease of the reader.
For the sake of simplicity, the links to the local AEM console in the post assumes the port number where the author AEM instance is running in the reader's machine to be 4502.

Overview

What is Tagging? Adobe says: "Tagging allows content to be categorized and organized". Basically tagging is assigning one or more keywords to a piece of Content so that it can be identified whenever necessary based on its categorization. That piece of content could be a page, an asset etc. The entire Adobe guide on tagging is here. Tags are generally assigned to Pages and Assets. You can create tags via the Tagging Console or programmatically.

Example use-case - Search a page based on tags

  1. Go to Tools > Operations > Tagging and click Create Namespace to create a namespace for your tags. createNamespace

  2. Add your first tag as shown. createTag

  3. Go to the page properties of the Geometrixx Demo Site's en version. pageProperties

  4. Select the tag that you just created and save the properties. chooseTag

  5. Go to Geometrixx Demo Site and search for your tag and also, the tag namespace. Both should display the Geometrixx Demo Site's en page in the results, as it is the page the tags are associated with. searchTag searchNamespace

  6. You can also list all the Pages that are using your tags by clicking on your tag in Tools > Operations > Tagging. You may want to check the location of the page by hovering over the name in the references list. tagReferance


This tutorial will help you create and assign such tags programmatically, so that the process are automated, faster and scalable, including an exercise for the reader which assumes that the user knows Java, Sling-API and JCR-API usage in advance. The author will explain the classes used in the program as they are encountered.

Requirements for the exercise

  • A running AEM instance
  • Preferably administrator rights to the JCR
  • Your choice of IDE

Exercise

Let's create a Sling Servlet first

This servlet is created to demonstrate the usage of the Tagging API inside it, so that a simple servlet call is enough to complete the purpose of the exercise.
Note : You may want to follow this and include the uber-jar in your POM dependencies before proceeding.


import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.felix.scr.annotations.*;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.tagging.InvalidTagFormatException;
import com.day.cq.tagging.JcrTagManagerFactory;
import com.day.cq.tagging.Tag;
import com.day.cq.tagging.TagManager;

@Component(metatype=true)
@Service
@Properties({
    @Property(name="sling.servlet.resourceTypes", value="sling/servlet/default"),
    @Property(name="sling.servlet.selectors", value="tags"),
    @Property(name="sling.servlet.extensions", value="html"),
    @Property(name="Sling.servlet.methods", value="GET"),
    @Property(name="service.description", value="This is a demo Tag Manager servlet")
})
public class TagServlet extends SlingAllMethodsServlet{
    public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response){
        //This block will be filled soon!
    }
}
            
Now, a good URL to call the servlet will be this, once the exercise is complete.

Obtaining the TagManager

The JcrTagManagerFactory service is a factory that will produce an instance of the JCR-based TagManager from the com.day.cq.tagging package. TagManager basically manages the tags by cleaning up tags, creating tags, resolving to tags based on a path etc. It is to be noted that TagManager can also be obtained from the ResourceResolver. So, let's add the code to the doGet() method of the servlet that does the aforementioned.


ResourceResolver resourceResolver = request.getResourceResolver();
Session session = resourceResolver.adaptTo(Session.class);

TagManager tagManager1 = jcrTagManagerFactory.getTagManager(session);
TagManager tagManager2 = resourceResolver.adaptTo(TagManager.class);
    

Creating the Tags!

Tags can be created by the createTag() method of a TagManager. As you can see, the first tag tag1 is located in /etc/tags/programmaticTestNamespace/ where programmaticTestNamespace is the tag namespace and hence, can contain more than one tag. Namespaces help in tag categorization. An AccessControlException object might be thrown if the current user in the session doesn't have enough privilege to create tags. An InvalidTagFormatException is thrown if the format of the TagID is wrong. Note that this tag is created using the TagManager obtained from the JcrTagManagerFactory. The second tag tag2 is created by the TagManager obtained from the ResourceResolver. We are obtaining the TagManager instance in two ways to demonstrate those very ways. tag2 is also in the same namespace as tag1 and you can see them in the repository once the program is executed after completion. You can also verify their existence in the Tagging Console. Add the following to your servlet's doGet() method.


Tag tag1 = null;
Tag tag2 = null;

try {
       tag1 = tagManager1.createTag("/etc/tags/programmaticTestNamespace/tag1", "First tag", "First tag description");
       log.error("****Creating tag1");
} catch (java.security.AccessControlException e) {
       log.error("****Access Control Exception");
} catch (InvalidTagFormatException e) {
       log.error("****Invalid tag Format Exception");
} 
log.error("****tag1 created");

try {
        tag2 = tagManager2.createTag("/etc/tags/programmaticTestNamespace/tag2", "Second tag", "Second tag description");
        log.error("****Creating tag2");
} catch (java.security.AccessControlException e) {
        log.error("****Access Control Exception");
} catch (InvalidTagFormatException e) {
        log.error("****Invalid tag Format Exception");
} 
log.error("****tag2 created");

Verify that the Tags have been created

One can verify whether the tags have been created at the mentioned location by resolving them as Resources. All one needs to do is to use the getResource() method of the ResourceResolver and pass the tag locations as arguments. Add the following lines to your servlet's doGet() method.


resource1 = resourceResolver.getResource("/etc/tags/programmaticTestNamespace/tag1");
log.error("****resource1 created at " + resource1.getPath());
resource2 = resourceResolver.getResource("/etc/tags/programmaticTestNamespace/tag2");
log.error("****resource2 created at " + resource2.getPath()); 

Tags can be adapted-To from a Resource!

The adaptTo() method of the Resource adaptable will help the user to obtain the Tag instances as Resources. The resources can also be resolved to the corresponding Node in the jcr. Also, a Node can be obtained from a Tag using its adaptTo() method because Tag implements the Adaptable interface as well. Similarly, a Resource can also be obtained from a Tag instance by the adaptTo method. You may want to re-read the mentioed lines because htey are very important! Add the following lines to complete the doGet() method.


Tag tag1converted = (resource1 != null ? resource1.adaptTo(Tag.class) : null);
log.error("****tag1converted");
Tag tag2converted = (resource2 != null ? resource2.adaptTo(Tag.class) : null);
log.error("****tag2converted");
        
Node node1fromTag1resource = (resource1 != null ? resource1.adaptTo(Node.class) : null );
Node node1fromTag1tag = (tag1 != null ? tag1.adaptTo(Node.class) : null);
try {
        log.error("****Node locations are same ? " + node1fromTag1resource.getPath().equals(node1fromTag1tag.getPath()));
} catch (RepositoryException e) {
         log.error("****Repository exception");
}
        
Resource resource1fromTag1 = tag1.adaptTo(Resource.class);
log.error("Resource and Tags same ? " + resource1fromTag1.getPath().equals(tag1.getPath()));
Resource resource2fromTag2 = tag2.adaptTo(Resource.class);
log.error("Resource and Tags same ? " + resource2fromTag2.getPath().equals(tag2.getPath()));

Verify that your servlet works

If there is no error in your servlet code, you should be able to see the following in your log dashboard. Also, your Tagging Console should display your tags and so should your CRX repository.

If the tags have been created, the output in your repository will be like the following : tagCRXDE

Similarly, successful tag creation should produce the following log messages : tagLogs



Hurray! You're done with this exercise and you now know a little bit more about Tagging in AEM!

Share this post

0 Comments

comments powered by Disqus