Coding a Sample Auto Tag AEM 56 Bundle on IntelliJ IDEA 12

Goal


This post is about creating a sample OSGI bundle (what is an OSGI bundle? Any search engine will bring you loads of information) from scratch on IntelliJ IDEA 12. Read this good article on CQ listeners

Here we create a bundle with


2) When a new page is created, listener automatically creates a new tag with page name and assigns it to the page. So basically some sample code to create and assign tags.


Install


Download and Install AEM (Day CQ) 561, IntelliJ IDEA 12 and Maven 310


Setup Maven


1) To add the dependency jars to your IDE, install and setup Maven

2) Download Maven and extract it to C:\dev\apache-maven-3.1.0.

3) Open System Environment Variables and add the System Varilable M2_HOME=C:\dev\apache-maven-3.1.0

4) Add the User Variable M2=%M2_HOME%\bin


New IDEA Module


1) In your IDEA project, Select File -> New Module -> Maven Module and enter the module name autotag



2) Enter the following 

                     GroupId: com.mysample.autotag
                     ArtifactId: autotag
                     Version: 1.0

3) Check "Create from archetype" and click "Add archetype"


4) Enter the following information and click ok

                        GroupdId: com.day.jcr.vault
                        ArtifactId: multimodule-content-package-archetype
                        Version: 1.0.2
                        Repository: http://repo.adobe.com/nexus/content/groups/public




5) Add the following maven properties

                        appsFolderName - autotag
                        artifactName - Auto Tag Listener 
                        packageGroup - Test Company



6) Here is a screen shot with all the details entered. Click Finish



7) Here is my autotag module in IDEA



8) Maven dependencies were already imported and created on file system. For example, the dependency "org.osgi"



On file system, the jars are available in 



9) Lets delete the unnecessary source files created by archetype; later we'll add our listener code. At the time of this writing i deleted files under "C:\dev\code\projects\autotag\bundle\src\main\java\com\mysample\autotag". Here is my module now with "C:\dev\code\projects\autotag\bundle\src\main\java" added as module source




Sample Listener Logic


1) Lets create a folder listeners and add some sample listener code. Here we are adding a JCR observation listener. This listener operates at JCR level and so has no knowledge of sling web framework, we operate on the raw jcr properties.





2) Here is the listener source code. The annotation "@Reference" for "repository" makes the jcr repository available for querying nodes. "activate" and "deactivate" methods are self-explanatory. 

Line 31: we are registering the listener for "NODE_ADDED" events only. So when a new page is created, a node is added in JCR under "/content"; the NODE_ADDED event fires and this listener catches execution.

package com.mysample.autotag.listeners;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;

@Component
public class AutoTagListener implements EventListener {
    private final Logger LOGGER = LoggerFactory.getLogger(AutoTagListener.class);

    @Reference
    private SlingRepository repository;

    private Session session;
    private ObservationManager observationManager;

    protected void activate(ComponentContext context) throws Exception {
        session = repository.loginAdministrative(null);
        observationManager = session.getWorkspace().getObservationManager();

        observationManager.addEventListener(this, Event.NODE_ADDED, "/", true, null,
                null, true);
        LOGGER.info("Added JCR event listener - AutoTagListener");
    }

    protected void deactivate(ComponentContext componentContext) {
        try {
            if (observationManager != null) {
                observationManager.removeEventListener(this);
                LOGGER.info("Removed JCR event listener - AutoTagListener");
            }
        } catch (RepositoryException re) {
            LOGGER.error("Error removing the JCR event listener - AutoTagListener", re);
        } finally {
            if (session != null) {
                session.logout();
                session = null;
            }
        }
    }

    public void onEvent(EventIterator it) {
        try {

        }catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        return;
    }
}


Install and Test Bundle


1) In your IDEA click on "Maven Projects" on the right side of your screen




2) Under Profiles -> Check "autoInstallBundle", "autoInstallPackage". Under "Reactor Project" right click on "install' and "Run Maven Build". Make sure your AEM (CQ) instance is up and running before you attempt this.




3) If the install is successful, in CRX Lite you can see the installed component bundle



4) Log "C:\dev\code\install\author\crx-quickstart\logs\error.log" shows the autotag bundle installed



5) Bundles console "http://localhost:4502/system/console/bundles", confirms the bundle installation



The Real Listener


1) Lets add some useful logic in the listener. The logic we are going to add creates a tag with page name in CRX and assigns it to the page

2) Add the following dependency to C:\dev\code\projects\autotag\pom.xml
            
                com.day.cq.tagging
                cq-tagging
                5.6.2
            
3) Add the following dependency to C:\dev\code\projects\autotag\bundle\pom.xml
        
            com.day.cq.tagging
            cq-tagging
        

The jars for necessary dependency are imported to "C:\Users\nalabotu\.m2\repository\com\day\cq\tagging\cq-tagging\5.6.2". If the jar is not available, get it from CRX (/libs/cq/tagging/install/cq-tagging-5.6.2.jar) and place it in the location

2) Add necessary logic to listener

Line 25: Declare a variable for tag namespace. Namespaces are like containers for tags. Tags that are going to be created by this listener are stored in the namespace "mysample"

Line 30, 31: Create a reference to tag manager implementation (a tag manager object for playing with tags)

Line 67, 74: A node added event is fired when a page content node is created. So we get the page content node, page node and continue with tag creation. If the node created is not of our interest (say an audit node) we skip the event processing

Line 85: Check if the namespace exists. A null means the namespace doesn't exist, so create one

Line 90: Create the tag with page name

Line 95: Create the cq:tags property on page content node and set it with the tag created above.

Line 96: Very important, save the changes

package com.mysample.autotag.listeners;

import com.day.cq.tagging.JcrTagManagerFactory;
import com.day.cq.tagging.Tag;
import com.day.cq.tagging.TagManager;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;

@Component
public class AutoTagListener implements EventListener {
    private final Logger LOGGER = LoggerFactory.getLogger(AutoTagListener.class);

    private static final String NAMESPACE = "/etc/tags/mysample";

    @Reference
    private SlingRepository repository;

    @Reference
    JcrTagManagerFactory tmf;

    private Session session;
    private ObservationManager observationManager;

    protected void activate(ComponentContext context) throws Exception {
        session = repository.loginAdministrative(null);
        observationManager = session.getWorkspace().getObservationManager();

        observationManager.addEventListener(this, Event.NODE_ADDED, "/", true, null,
                null, true);
        LOGGER.info("Added JCR event listener - AutoTagListener");
    }

    protected void deactivate(ComponentContext componentContext) {
        try {
            if (observationManager != null) {
                observationManager.removeEventListener(this);
                LOGGER.info("Removed JCR event listener - AutoTagListener");
            }
        } catch (RepositoryException re) {
            LOGGER.error("Error removing the JCR event listener - AutoTagListener", re);
        } finally {
            if (session != null) {
                session.logout();
                session = null;
            }
        }
    }

    public void onEvent(EventIterator it) {
        try {
            while (it.hasNext()) {
                Event event = it.nextEvent();
                LOGGER.info("AutoTagListener - new add event: ", event.getPath());

                Node pageContentNode = session.getNode(event.getPath());

                if( ( pageContentNode == null ) || !pageContentNode.getPrimaryNodeType().isNodeType("cq:PageContent")){
                    LOGGER.debug("Skip processing node: " + event.getPath());
                    return;
                }

                Node pageNode = pageContentNode.getParent();

                if( ( pageNode == null ) || !pageNode.getPrimaryNodeType().isNodeType("cq:Page")){
                    LOGGER.debug("Skip processing node: " + pageNode);
                    return;
                }

                TagManager tMgr = tmf.getTagManager(session);
                Tag superTag = tMgr.resolve(NAMESPACE);
                Tag tag = null;

                if(superTag == null){
                    tag = tMgr.createTag(NAMESPACE, "My Sample", "My Sample tags", true);
                    LOGGER.info("Tag Name Space created : ", tag.getPath());
                }

                tag = tMgr.createTag(NAMESPACE + "/" + pageNode.getName(), pageNode.getName(), "Auto tag : " + pageNode.getName(), true);

                String tagArray[] = new String[1];
                tagArray[0] = tag.getNamespace().getName() + ":" + tag.getPath().substring(tag.getPath().indexOf(NAMESPACE) + NAMESPACE.length() + 1);

                pageContentNode.setProperty("cq:tags", tagArray);
                session.save();
            }
        }catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        return;
    }
}

3) Reinstall the component (Run Maven Goal "install" )

If you see the following error in error.log

02.09.2013 17:08:21.097 *WARN* [127.0.0.1 [1378159701028] POST /crx/packmgr/service.jsp HTTP/1.1] com.day.jcr.vault.packaging.impl.JcrPackageImpl Refusing to recreate snapshot Test Company/.snapshot:autotag-content:1.0, already exists.

Remove the previously installed bundle from OSGI container (http://localhost:4502/system/console/bundles)



Remove the previously installed component from CRX (http://localhost:4502/crx/de/index.jsp#/apps, Right click on "autotag" and "Delete")





4) Run the maven goal "install"

Test and Check


1) Create a page "Listener Test" of any template type in siteadmin console (http://localhost:4502/siteadmin)



2) Check the Tagging console (http://localhost:4502/tagging). The tag listener-test should have been created under namespace "My Sample"



3) In CRX (http://localhost:4502/crx) check the tags node (/etc/tags/mysample/listener-test)



4) Check the page "Listener Test" properties in CRX




5) Check if tag "listener-test" is assigned to the page by opening Side Kick -> Pages tab -> Page Properties -> Tags/Keywords



6) Check if the tag is assigned by navigating to the page (http://localhost:4502/cf#/content/test-site/listener-test.html) and searching with tags:listener-test in Content Finder Pages tab



3 comments:

  1. Hi Sreekanth,

    Thanks a lot for sharing this. Will try this at my end and post back my queries/doubts.

    ReplyDelete
  2. hi all
    how to read or retrive tags under/etc/tags/namespace propertice

    ReplyDelete
  3. Hi does this code still work under 6.3.3 having some trouble compiling since its ideal 13 and a couple other revs...

    This is exactly what I need for a project so any guidance would be awesome

    ReplyDelete