Trouble setting up a sling job on AEM 6.5. What am I missing? | Community
Skip to main content
Art_Bird
Level 2
June 28, 2021
Solved

Trouble setting up a sling job on AEM 6.5. What am I missing?

  • June 28, 2021
  • 9 replies
  • 7571 views

I'm trying to create a Sling job and not having much luck. I've followed the docs on the Apache and Adobe sites but if keeps throwing a null pointer exception. I figure I've missed an important step that wasn't in the docs I read. Also, everything I've read thats AEM related is based on a watcher seeing a change to the JCR or a scheduled task that runs at a set time. We want to trigger it without a JCR update.

 

My goal is to have a user perform an action that ends with a job being created and immediately ran. This would mean a servlet or API is hit and it adds the job and triggers it to run immediately. I've written code to do this but it throws the NPE on the jobManager.addJob() method call.

 

This is the Apache example code that I've based my code on.

Create the job

import org.apache.sling.jobs.JobManager; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import java.util.Map; import java.util.HashMap; @Component public class MyComponent { @3214626 private JobManager jobManager; public void startJob() { final Map<String, Object> props = new HashMap<String, Object>(); props.put("item1", "/something"); props.put("count", 5); jobManager.addJob("my/special/jobtopic", props); } }

 

Job consumer

import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.consumer.JobConsumer; @Component @Service(value={JobConsumer.class}) @Property(name=JobConsumer.PROPERTY_TOPICS, value="my/special/jobtopic",) public class MyJobConsumer implements JobConsumer { public JobResult process(final Job job) { // process the job and return the result return JobResult.OK; } }

What I've been basing my work on.
Apache docs https://sling.apache.org/documentation/bundles/apache-sling-eventing-and-job-handling.html
Adobe https://experienceleague.adobe.com/docs/experience-manager-cloud-service/operations/asynchronous-jobs.html%3Flang%3Den
I've also exhausted my search skills on this topic.

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 @art_bird,

I suggest to try using the below as is separately (as two Java classes) and see if it works. If yes, then you can add it to your actual business logic. 

 

JobComponent.java (OSGi component that adds Job on activation - addJob on Activate method)

As we are adding the Job on activation, you should be able to see the LOG messages on installing/successful activation of your bundle. (Change the log level you are using accordingly - Debug/Info whichever it is set to.)

package com.aem.demoproject.core.listeners; import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.JobManager; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; @Component public class JobComponent { @Reference private JobManager jobManager; public static final String JOB_TOPIC="com/sling/eventing/page/job"; private final Logger LOG = LoggerFactory.getLogger(this.getClass()); @Activate protected void activate(){ addJob(); } public void addJob(){ LOG.debug("Inside add job"); Map<String,Object> param = new HashMap<String,Object>(); param.put("eventPath","/content/demo"); Job job = jobManager.addJob(JOB_TOPIC,param); LOG.info("Job "+job.getTopic()+" is created successfully on "+job.getCreated().getTime()); } }

JobConsumerImpl.java:

package com.aem.demoproject.core.listeners; import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.consumer.JobConsumer; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(service=JobConsumer.class, immediate = true, property = {JobConsumer.PROPERTY_TOPICS + "=" + JobComponent.JOB_TOPIC}) public class JobConsumerImpl implements JobConsumer { private final Logger LOG = LoggerFactory.getLogger(this.getClass()); @Override public JobResult process(Job job) { LOG.info("Inside job process method"); String eventPath = (String) job.getProperty("eventPath"); LOG.info("Event path={}", eventPath); return JobResult.OK; // Return based on actual implementation logic. } }

 

9 replies

Vijayalakshmi_S
Level 10
June 28, 2021

Hi @art_bird,

Could you please cross check the OSGi component (where you are adding the job) is active and the JobManager Reference is satisfied and bound to Service implementation.

 

ChitraMadan
Community Advisor
Community Advisor
June 28, 2021

Hi @art_bird,

 

Can you please try to add immediate=true with your components, as this will immediately activate your components.

@Component(immediate = true)
 
Thanks,
Chitra
Dipti_Chauhan
Community Advisor
Community Advisor
June 29, 2021

Hi @art_bird 

 JobManager is normally from org.apache.sling.event.jobs.JobManager  package not from "org.apache.sling.jobs.JobManager" . you able to compile this with package?

 

Thanks

Dipti

 

shelly-goel
Adobe Employee
Adobe Employee
June 29, 2021
Art_Bird
Art_BirdAuthor
Level 2
June 29, 2021

I've updated the code I'm using based on what you all have suggested. Still getting the nullPointerException when jobManager.addJob(TOPIC, props) is ran.

@shelly-goelI made the adjustments to use R6 and switched to @OSGiService

@dipti_chauhanPackages are updated.

@chitramadanUsing immediate=true.

@vijayalakshmi_sNot seeing JobManager referenced in the component.

 

import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.JobManager; import org.osgi.service.component.annotations.Component; import org.apache.sling.models.annotations.injectorspecific.OSGiService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; import java.util.HashMap; @Component public class TestStartJob { private static final Logger LOGGER = LoggerFactory.getLogger(TestStartJob.class); @OSGiService private JobManager jobManager; private static final String TOPIC = "my/special/jobtopic"; public void startJob() { try { final Map<String, Object> props = new HashMap<String, Object>(); props.put("foo", "bar"); Job job = jobManager.addJob(TOPIC, props); String jobTopic = job.getTopic(); LOGGER.debug(jobTopic); } catch (Exception e){ LOGGER.debug(e.getMessage()); } } }

 

import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.consumer.JobConsumer; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component( service = JobConsumer.class, property = { JobConsumer.PROPERTY_TOPICS + "=my/special/jobtopic" }, // One of the few cases where immediate = true; this is so the Event Listener starts listening immediately immediate = true ) public class TestJobConsumer implements JobConsumer { private static final Logger log = LoggerFactory.getLogger(TestJobConsumer.class); @Override public JobResult process(final Job job) { job.getProperty("foo"); return JobConsumer.JobResult.OK; } }

 

 

shelly-goel
Adobe Employee
Adobe Employee
June 30, 2021
@art_bird - Try with this package as well org.apache.sling.jobs.JobManager; The sling documentation mentions this pacakge: https://sling.apache.org/documentation/bundles/apache-sling-eventing-and-job-handling.html#jobs-guarantee-of-processing
Vijayalakshmi_S
Vijayalakshmi_SAccepted solution
Level 10
June 29, 2021

Hi @art_bird,

I suggest to try using the below as is separately (as two Java classes) and see if it works. If yes, then you can add it to your actual business logic. 

 

JobComponent.java (OSGi component that adds Job on activation - addJob on Activate method)

As we are adding the Job on activation, you should be able to see the LOG messages on installing/successful activation of your bundle. (Change the log level you are using accordingly - Debug/Info whichever it is set to.)

package com.aem.demoproject.core.listeners; import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.JobManager; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; @Component public class JobComponent { @Reference private JobManager jobManager; public static final String JOB_TOPIC="com/sling/eventing/page/job"; private final Logger LOG = LoggerFactory.getLogger(this.getClass()); @Activate protected void activate(){ addJob(); } public void addJob(){ LOG.debug("Inside add job"); Map<String,Object> param = new HashMap<String,Object>(); param.put("eventPath","/content/demo"); Job job = jobManager.addJob(JOB_TOPIC,param); LOG.info("Job "+job.getTopic()+" is created successfully on "+job.getCreated().getTime()); } }

JobConsumerImpl.java:

package com.aem.demoproject.core.listeners; import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.consumer.JobConsumer; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(service=JobConsumer.class, immediate = true, property = {JobConsumer.PROPERTY_TOPICS + "=" + JobComponent.JOB_TOPIC}) public class JobConsumerImpl implements JobConsumer { private final Logger LOG = LoggerFactory.getLogger(this.getClass()); @Override public JobResult process(Job job) { LOG.info("Inside job process method"); String eventPath = (String) job.getProperty("eventPath"); LOG.info("Event path={}", eventPath); return JobResult.OK; // Return based on actual implementation logic. } }

 

Dipti_Chauhan
Community Advisor
Community Advisor
June 30, 2021

Hi @art_bird 

  I just tested below mentioned code snippet with 6.4 and it is working fine. Can you compare you class with this?

package ********; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.apache.sling.event.jobs.JobManager; @Component(immediate = true, label = "TEST") @Service(value = TestEmailService.class) public class TestEmailServiceImpl implements TestEmailService { @Reference private JobManager jobManager; @Override public List<String> sendEmail(Map<String, String> emailParams, String[] recipients) { final List<String> failureList = new ArrayList<String>(); Map<String,Object> emailParamsObj = new HashMap<String,Object>(); emailParamsObj.putAll(emailParams); emailParamsObj.put("recipients", String.join(",", recipients)); jobManager.addJob("test/email/job", emailParamsObj); return failureList; } }

 

January 27, 2022

Hello,

 

I had the same problem. The reason for jobManager being null is wrong import:

 

this is bad:

import org.apache.felix.scr.annotations.Reference;

 

this is good:

import org.osgi.service.component.annotations.Reference;

 

aanchal-sikka
Community Advisor
Community Advisor
November 6, 2023

Please refer to https://techrevel.blog/2023/11/06/enhancing-efficiency-and-reliability-by-sling-jobs/#scheduled-jobs

 

It has the relevant code snippet.

We need to use org.apache.sling.event.jobs.JobManager instead of org.apache.sling.jobs.JobManager. Rest all stays the same

Aanchal Sikka