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.

<h4>Example use-case - <i>Search a page based on tags</i></h4>
<ol>
    <li>Go to <b>Tools > Operations > Tagging</b> and click <i>Create Namespace</i> to create a namespace for your tags.
    <img src="/images/blog-media/2016-09-05-a-primer-on-programmatic-tagging-in-aem/blog-createNamespace.png" alt="createNamespace" class="img-responsive"/>
    </li>
    <li>Add your first tag as shown.
        <img src="/images/blog-media/2016-09-05-a-primer-on-programmatic-tagging-in-aem/blog-createTag.png" alt="createTag" class="img-responsive"/>
    </li>
    <li>Go to the page properties of the Geometrixx Demo Site's <i>en</i> version.
        <img src="/images/blog-media/2016-09-05-a-primer-on-programmatic-tagging-in-aem/blog-pageProperties.png" alt="pageProperties" class="img-responsive"/>
    </li>
    <li>Select the tag that you just created and save the properties.
        <img src="/images/blog-media/2016-09-05-a-primer-on-programmatic-tagging-in-aem/blog-chooseTag.png" alt="chooseTag" class="img-responsive"/>
    </li>
    <li>Go to Geometrixx Demo Site and search for your tag and also, the tag namespace. Both should display the <b>Geometrixx Demo Site's</b> <i>en</i> page in the results, as it is the page the tags are associated with.
        <img src="/images/blog-media/2016-09-05-a-primer-on-programmatic-tagging-in-aem/blog-searchTag.png" alt="searchTag" class="img-responsive"/>
        <img src="/images/blog-media/2016-09-05-a-primer-on-programmatic-tagging-in-aem/blog-searchNamespace.png" alt="searchNamespace" class="img-responsive"/>
    </li>
    <li>You can also list all the Pages that are using your tags by clicking on your tag in <b>Tools > Operations > Tagging</b>. You may want to check the location of the page by hovering over the name in the references list.
    <img src="/images/blog-media/2016-09-05-a-primer-on-programmatic-tagging-in-aem/blog-tagReferance.png" alt="tagReferance" class="img-responsive"/>
    </li>

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

<h4>Let's create a Sling Servlet first</h4>
    <p>
        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.
        <br/>
        <i>Note : You may want to follow <a target="_blank" href="https://docs.adobe.com/docs/en/aem/6-1/develop/dev-tools/ht-projects-maven.html">this</a> and include the uber-jar in your POM dependencies before proceeding.</i></p>

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!
    }
}
            
    <p>
        Now, a good URL to call the servlet will be <a href="http://localhost:4502/test.tags.html" title="http://localhost:4502/test.tags.html" target="_blank">this</a>, once the exercise is complete.
    </p>

<h4>Obtaining the TagManager</h4>
 <p>The <a href="https://docs.adobe.com/docs/en/cq/5-6-1/javadoc/com/day/cq/tagging/JcrTagManagerFactory.html" target="_blank">JcrTagManagerFactory </a> service is a factory that will produce an instance of the JCR-based <a href="https://docs.adobe.com/docs/en/cq/5-6-1/javadoc/com/day/cq/tagging/TagManager.html" target="_blank">TagManager</a> from the <i>com.day.cq.tagging</i> 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 <i>doGet()</i> method of the servlet that does the aforementioned.
 </p>
 <pre><code>

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

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

<h4>Creating the Tags!</h4>
    <p>Tags can be created by the <i>createTag()</i> method of a TagManager. As you can see, the first tag <i>tag1</i> is located in <i>/etc/tags/programmaticTestNamespace/</i> where <b>programmaticTestNamespace</b> is the tag <a href="https://docs.adobe.com/docs/en/aem/6-1/administer/content/tags.html#Tag Features" target="_blank">namespace</a> and hence, can contain more than one tag. Namespaces help in tag categorization. An <i>AccessControlException</i> object might be thrown if the current user in the session doesn't have enough privilege to create tags. An <i>InvalidTagFormatException</i> 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 <i>tag2</i> is created by the TagManager obtained from the ResourceResolver. We are obtaining the TagManager instance in two ways to demonstrate those very ways. <i>tag2</i> is also in the same namespace as <i>tag1</i> and you can see them in the repository once the program is executed after completion. You can also verify their existence in the <i>Tagging Console</i>.

    Add the following to your servlet's <i>doGet()</i> method.
    </p>
    <pre><code>

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");

<h4>Verify that the Tags have been created</h4>
<p>One can verify whether the tags have been created at the mentioned location by resolving them as <i>Resources</i>. All one needs to do is to use the <i>getResource()</i> method of the ResourceResolver and pass the tag locations as arguments.

Add the following lines to your servlet's <i>doGet()</i> method.
</p>

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 mentioned lines because they 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!