Article summary

Summary

Discusses how to create a custom Adobe Experience Manager 6.4 event handler that responds to JCR events, such as when a node is created. This article uses a Maven Archetype 13 project to create the project. 

A special thank you to Arun Patidar, a top AEM community member, for contributing towards this article.

Digital Marketing Solution(s) Adobe Experience Manager 6.4
Audience Developer
Required Skills Java, HTML, JCR
Version 6.4

Introduction

You can develop a custom JCR Event Listener for Adobe Experience Manager 6.4 that responds to events that occur at the JCR level. For example, you can write an event handler to respond to the following JCR events:

  • A node was added
  • A node was moved
  • A node was deleted
  • A property was added to a node
  • A property was changed
  • A property was deleted

To create an AEM event handler, you create an OSGi bundle that contains a class that implements javax.jcr.observation.EventListener. For information, see EventListener.

Note:

The Maven Archetype 13 project uses Declartive Services annotations. For information, see OFFICIAL OSGI DECLARATIVE SERVICES ANNOTATIONS IN AEM

Create an Experience Manager System User

Create an Experience Manager System User that can access JCR data. To successfully query JCR data, create an Experience Manager System user by performing these tasks.

1. Open http://localhost:4502/crx/explorer/index.jsp.

2. Login as admin.

3. Click User Administration.

4. Click Create System User. Name the user data (data is used in this article).

5. Set the UserId.

6. Click Save

7. Access the user page at http://localhost:4502/useradmin.

8. Select the data user.

9. From the right-hand pane, select the Permissions tab.

10. Click all the checkboxes that represent the permissions (click the top row in permissions for this example).

11. Click the Save button located in the top menu bar (located above the Path heading).

Configure the Sling Mapper Service

The next step is to configure the Apache Sling Service User Mapper service by adding a new entry. Enter the following value:

Event64.core:datawrite=data

where:

  • Event64.core – is the Bundle-SymbolicName value of the OSGi bundle this is developed in the upcoming sections of this article.
  • datawrite – the name of the sub service (you reference this value in the Java code - used in the repository.loginService method)
  • data – the system user account with data privileges.

To create an entry in the Apache Sling Mapper service, perform these tasks:

1. Go to the Apache Sling Mapper service at http://localhost:4502/system/console/configMgr.

2. Click OSGI, Configurations.

2. Scroll to an entry named Apache Sling Service User Mapper Service.

3. Enter the value Event64.core:datawrite=data.

4. Click Save.

Create an AEM Maven 13 archetype project

You can create an Experience Manager archetype project by using the Maven archetype plugin. In this example, assume that the working directory is C:\AdobeCQ.

M10
Files generated by Maven 12 Archetype

To create an Experience Manager archetype project, perform these steps:

1. Open the command prompt and go to your working directory (for example, C:\AdobeCQ).

2. Run the following Maven command:

mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=com.adobe.granite.archetypes -DarchetypeArtifactId=aem-project-archetype -DarchetypeVersion=13 -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/

3. When prompted, specify the following information:

  • groupId - Event64
  • artifactId - Event64
  • version - 1.0-SNAPSHOT
  • package -  com.adobe.community
  • appsFolderName - Event64
  • artifactName - Event64
  • componentGroupName - Event64
  • cssId - Event64
  • packageGroup - Event64
  • siteName - Event64

4. WHen prompted, specify Y.

5. Once done, you will see a message like:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:42 min
[INFO] Finished at: 2016-04-25T14:34:19-04:00
[INFO] Final Memory: 16M/463M
[INFO] ------------------------------------------------------------------------

6. Change the working directory to Event64 and then enter the following command.

mvn eclipse:eclipse

After you run this command, you can import the project into Eclipse as discussed in the next section.

Add Java files to the Maven project using Eclipse

To make it easier to work with the Maven generated project, import it into the Eclipse development environment, as shown in the following illustration.

project
Eclipse Import Project Dialog

Note:

Do not worry about the errors reported in Eclipse. It does not read the POM file where the APIs are resolved. You build the bundle with Maven. Eclipse is used to edit the Java files and the POM file.

To create a JCR Event Listener, use the SimpleResourceListener class, as shown in the following illustration.

code
Use the SimpleResourceListener class

SimpleResourceListener class

Add Java application logic to the SimpleResourceListener class that logs changes to the AEM JCR. In this example, a message is logged when a node or property is added to a path under /apps/example. The following code represents this class.

package com.adobe.community.listeners;

import java.util.HashMap;
import java.util.Map;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
 
import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;
import org.apache.sling.api.resource.LoginException;
 
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Activate;
 
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.osgi.service.component.ComponentContext; 
import javax.jcr.observation.EventIterator ; 
 
@Component(immediate=true,
service= EventListener.class)
 
public class SimpleResourceListener implements EventListener{
 
  
    Logger log = LoggerFactory.getLogger(this.getClass());
     private Session adminSession;
      
     
     @Reference
     org.apache.sling.jcr.api.SlingRepository repository;
      
     @Activate
     public void activate(ComponentContext context) throws Exception {
     log.info("activating ExampleObservation");
     try {
    	 adminSession = repository.loginService("datawrite",null);
         adminSession.getWorkspace().getObservationManager().addEventListener(
          this, //handler
          Event.PROPERTY_ADDED|Event.NODE_ADDED, //binary combination of event types
          "/apps/example", //path
          true, //is Deep?
          null, //uuids filter
          null, //nodetypes filter
          false);
      
          
     } catch (RepositoryException e){
      log.error("unable to register session",e);
      throw new Exception(e);
     }
    }
    @Deactivate
    public void deactivate(){
     if (adminSession != null){
      adminSession.logout();
     }
    }
      
    public void onEvent(EventIterator eventIterator) {
      try {
        while (eventIterator.hasNext()){
          log.info("something has been added : {}", eventIterator.nextEvent().getPath());
        }
       } catch(RepositoryException e){
       log.error("Error while treating events",e);
      }
     }
    }

Note:

Notice that datawrite (the value configured by using the Sling Mapping Service) is used in this line of code: adminSession = repository.loginService("datawrite",null); 

Modify the Maven POM file

Add the following POM dependency to the POM file located at C:\AdobeCQ\Event64.

<dependency>
    <groupId>com.adobe.aem</groupId>
    <artifactId>uber-jar</artifactId>
    <version>6.4.0</version>
    <classifier>apis</classifier>
    <scope>provided</scope>
</dependency>
                
  <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-atinject_1.0_spec</artifactId>
       <version>1.0</version>
       <scope>provided</scope>
   </dependency>

When you add new Java classes under core, you need to modify a POM file to successfully build the OSGi bundle. You modify the POM file located at C:\AdobeCQ\Event64\core.

The following code represents this POM file.

<?xml version="1.0" encoding="UTF-8"?>
<!--
 |  Copyright 2017 Adobe Systems Incorporated
 |
 |  Licensed under the Apache License, Version 2.0 (the "License");
 |  you may not use this file except in compliance with the License.
 |  You may obtain a copy of the License at
 |
 |      http://www.apache.org/licenses/LICENSE-2.0
 |
 |  Unless required by applicable law or agreed to in writing, software
 |  distributed under the License is distributed on an "AS IS" BASIS,
 |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 |  See the License for the specific language governing permissions and
 |  limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>Event64</groupId>
        <artifactId>Event64</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>Event64.core</artifactId>
    <packaging>bundle</packaging>
    <name>Event64 - Core</name>
    <description>Core bundle for Event64</description>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.sling</groupId>
                <artifactId>maven-sling-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <!-- Import any version of javax.inject, to allow running on multiple versions of AEM -->
                        <Import-Package>javax.inject;version=0.0.0,*</Import-Package>
                        <Sling-Model-Packages>
                            com.adobe.community.core
                        </Sling-Model-Packages>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- OSGi Dependencies -->
        <dependency>
            <groupId>com.adobe.aem</groupId>
            <artifactId>uber-jar</artifactId>
            <classifier>apis</classifier>
        </dependency>
     
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-atinject_1.0_spec</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.cmpn</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>osgi.annotation</artifactId>
        </dependency>
        <!-- Other Dependencies -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.jcr</groupId>
            <artifactId>jcr</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.adobe.aem</groupId>
            <artifactId>uber-jar</artifactId>
            <classifier>apis</classifier>
        </dependency>
        <dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.models.api</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
        </dependency>
        <dependency>
            <groupId>junit-addons</groupId>
            <artifactId>junit-addons</artifactId>
        </dependency>
    </dependencies>
</project>

Build the OSGi bundle using Maven

To build the OSGi bundle by using Maven, perform these steps:

  1. Open the command prompt and go to the C:\AdobeCQ\Event64.
  2. Run the following maven command: mvn -PautoInstallPackage install.
  3. The OSGi component can be found in the following folder: C:\AdobeCQ\Event64\core\target. The file name of the OSGi component is Event64-1.0-SNAPSHOT.jar.

The command -PautoInstallPackage automatically deploys the OSGi bundle to AEM.

View the Active OSGi bundle

After you deploy the OSGi bundle by using the Maven command, you can see it in an active state in the Adobe Apache Felix Web Console.

OSGi
The OSGi bundle deployed to Experience Manager

View your OSGi bundle by performing these steps:

  1. Login to Adobe Apache Felix Web Console at http://server:port/system/console/bundles (default admin user = admin with password= admin).
  2. Click the Bundles tab, sort the bundle list by Id, and note the Id of the last bundle.

Viewing event messages

Open CRXDE lite and create the following path:

/apps/example

Now add two folders under exampe named templates and compnents, as shown in this illustration. 

example
Add two folders under /apps/example

Because you added two nodes under /apps/example, the event listener you created is invoked. You can view the following messages in the log file. 

9.01.2018 11:43:07.649 *INFO* [sling-oak-observation-770] com.aem.community.core.listeners.SimpleResourceListener something has been added : /apps/example/components/jcr:createdBy19.01.2018 11:43:07.649 *INFO* [sling-oak-observation-770] com.aem.community.core.listeners.SimpleResourceListener something has been added : /apps/example/components/jcr:created

See also

Join the AEM community at: Adobe Experience Manager Community

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy