Multiple paths handling in EventHandler not working | Community
Skip to main content
thatsmeadarsh
Level 3
October 7, 2021
Solved

Multiple paths handling in EventHandler not working

  • October 7, 2021
  • 3 replies
  • 6529 views

I need to get the events while the property 'jcr:lastModified' is either added or modified. Also I only need to watch certain paths. I tried to add properties like this. I also checked the event console http://localhost:4502/system/console/events where I couldn't find my class. The debugger is also not reaching to the handleEvent method. Is this the correct way to do this.

 

@8220494(immediate = true, service = EventHandler.class, property = {
Constants.SERVICE_DESCRIPTION + "= This event handler listens the events on asset addition/modification",
EventConstants.EVENT_TOPIC + "=org/apache/sling/api/resource/Resource/ADDED",
EventConstants.EVENT_TOPIC + "=org/apache/sling/api/resource/Resource/CHANGED",
EventConstants.EVENT_FILTER + "(&" + "(|(path=/content/dam/custom-path1/*/jcr:content)(path=/content/dam/custom-path2/*/jcr:content)) (|("
+ SlingConstants.PROPERTY_CHANGED_ATTRIBUTES + "=*jcr:lastModified) " + "(" + ResourceChangeListener.CHANGES
+ "=*jcr:lastModified)))" })
public class PreviewS3AssetEventHandler implements EventHandler {

@9944223
public void handleEvent(Event event) {
String event1 = event.getTopic();
String event2 = event1;

}

}

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by Vijayalakshmi_S

Hi @thatsmeadarsh,

Since we are looking for property change/add event on a Resource, we can make use of specific Listener named "ResourceChangeListener"https://sling.apache.org/apidocs/sling9/org/apache/sling/api/resource/observation/ResourceChangeListener.html

Sample snippet : (tried and works in my local - AEM 6.5.0)

Have used the PATHS as is without pattern. Glob pattern is allowed, check the description and use per your need - https://sling.apache.org/apidocs/sling9/org/apache/sling/api/resource/observation/ResourceChangeListener.html#PATHS

package com.aem.demoproject.core.listeners;

import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

@Component(service = ResourceChangeListener.class, immediate = true, property = {
        ResourceChangeListener.PATHS + "=/content/dam/demo",
        ResourceChangeListener.PATHS + "=/content/dam/we-retail/en/features",
        ResourceChangeListener.CHANGES + "=CHANGED",
        ResourceChangeListener.CHANGES + "=ADDED",
        ResourceChangeListener.PROPERTY_NAMES_HINT + "=jcr:lastModified"
})
public class SampleResourceChangeListener implements ResourceChangeListener {

    private final Logger LOG = LoggerFactory.getLogger(this.getClass());

    @Override
    public void onChange(List<ResourceChange> list) {
        LOG.info("On add/change of jcr:lastModified");
    }
}

3 replies

Vijayalakshmi_S
Vijayalakshmi_SAccepted solution
Level 10
October 7, 2021

Hi @thatsmeadarsh,

Since we are looking for property change/add event on a Resource, we can make use of specific Listener named "ResourceChangeListener"https://sling.apache.org/apidocs/sling9/org/apache/sling/api/resource/observation/ResourceChangeListener.html

Sample snippet : (tried and works in my local - AEM 6.5.0)

Have used the PATHS as is without pattern. Glob pattern is allowed, check the description and use per your need - https://sling.apache.org/apidocs/sling9/org/apache/sling/api/resource/observation/ResourceChangeListener.html#PATHS

package com.aem.demoproject.core.listeners;

import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

@Component(service = ResourceChangeListener.class, immediate = true, property = {
        ResourceChangeListener.PATHS + "=/content/dam/demo",
        ResourceChangeListener.PATHS + "=/content/dam/we-retail/en/features",
        ResourceChangeListener.CHANGES + "=CHANGED",
        ResourceChangeListener.CHANGES + "=ADDED",
        ResourceChangeListener.PROPERTY_NAMES_HINT + "=jcr:lastModified"
})
public class SampleResourceChangeListener implements ResourceChangeListener {

    private final Logger LOG = LoggerFactory.getLogger(this.getClass());

    @Override
    public void onChange(List<ResourceChange> list) {
        LOG.info("On add/change of jcr:lastModified");
    }
}
thatsmeadarsh
Level 3
October 7, 2021

Thanks @vijayalakshmi_s  and @arunpatidar  for your response. Resource change listener seems to be more appropriate option for me. However I am wondering if it is possible to inject the path properties from an OSGI configuration, cause we are looking for dynamic path listener.

thatsmeadarsh
Level 3
October 9, 2021

Hi @thatsmeadarsh

You can make use of ObjectClassDefinition(OCD) for providing component configuration properties dynamically from Config Admin. 

Sample snippet :

  • resource_paths() here will be evaluated as resource.paths which is the constant value for ResourceChangeListener.PATHS
    • Same goes with other two. 
  • If you would like to have the Listener working with specified default values for the very first time it is deployed/when you don't provide the config values via Config Admin(/configMgr), use the @Activate method with Config as the param. 
  • Otherwise, you can remove the method -> Once the code is deployed, provide the desired config values via /configMgr and then Listener would work with respective property and its values. 
package com.aem.demoproject.core.listeners;

import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

@Component(service = ResourceChangeListener.class, immediate = true)
@Designate(ocd = SampleResourceChangeListener.Config.class)
public class SampleResourceChangeListener implements ResourceChangeListener {

    private final Logger LOG = LoggerFactory.getLogger(this.getClass());

    @Override
    public void onChange(List<ResourceChange> list) {
        LOG.info("On add/change of jcr:lastModified, listener activated with config via OCD");
    }

    @Activate
    protected void activate(SampleResourceChangeListener.Config configValues) {
        LOG.debug("Config values={}", configValues.resource_paths());
    }

    @ObjectClassDefinition(name = "SampleResourceChangeListener", description = "Resource change Listener Registration properties")
    public @interface Config {
        @AttributeDefinition(name = "Paths", description = "ResourceChangeListener Paths property")
        String[] resource_paths() default {"/content/dam/demo"};

        @AttributeDefinition(name = "Changes", description = "ResourceChangeListener Changes property")
        String[] resource_change_types() default {"CHANGED"};

        @AttributeDefinition(name = "Properties", description = "ResourceChangeListener PropertyNamesHint property")
        String[] resource_property_names_hint() default {"jcr:lastModified"};
    }
}

 


Thanks @vijayalakshmi_s  for sharing this handy solution this really saved my day 🙂

arunpatidar
Community Advisor
Community Advisor
October 7, 2021

Hi,

You can combine the path in single rule e.g.

path=/content/dam/myproj/(folder1|folder2)/*/jcr:content

EventConstants.EVENT_FILTER + "(&" + "(|(path=/content/dam/myproj/(folder1|folder2)/*/jcr:content)(|("
+ SlingConstants.PROPERTY_CHANGED_ATTRIBUTES + "=*jcr:lastModified) " + "(" + ResourceChangeListener.CHANGES
+ "=*jcr:lastModified)))" })

 

Arun Patidar
Adobe Employee
September 26, 2023

In my case adding multiple paths worked with below syntax

 

@Component(service = EventHandler.class, immediate = true, property = { EventConstants.EVENT_TOPIC + "=" + ReplicationAction.EVENT_TOPIC, EventConstants.EVENT_FILTER + "=(|(paths=/content/projectname/*)(paths=/content/dam/projectname/*))" }) @ServiceDescription("Listener to listen on replication action in the resource tree") @Designate(ocd = ReplicationListener.SolrSearchPropertiesConfiguration.class) public class ReplicationListener implements EventHandler {

  Especially when we are working on Sling events like Activate or deactivate, the above code will be convenient because you have to listen to activate or deactivate events on specific paths under your project-related folders only in Assets and Sites. Something similar was even suggested by @arunpatidar  in an answer here.