Your achievements

Level 1

0% to

Level 2

Tip /
Sign in

Sign in to Community

to gain points, level up, and earn exciting badges like the new
BedrockMission!

Learn more

View all

Sign in to view all badges

SOLVED

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

Art_Broussard
Level 2
Level 2

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 {

    @reference
    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-job...
I've also exhausted my search skills on this topic.

AEM 6.5 Sling Jobs
1 Accepted Solution
Vijayalakshmi_S
Correct answer by
Community Advisor
Community Advisor

Hi @Art_Broussard,

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.
    }
}

 

View solution in original post

8 Replies
Vijayalakshmi_S
Community Advisor
Community Advisor

Hi @Art_Broussard,

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.

Vijayalakshmi_S_0-1624915003769.png

 

ChitraMadan
Community Advisor
Community Advisor

Hi @Art_Broussard,

 

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

Hi @Art_Broussard 

 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

 

Art_Broussard
Level 2
Level 2

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;
	}
}

 

 

Vijayalakshmi_S
Correct answer by
Community Advisor
Community Advisor

Hi @Art_Broussard,

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.
    }
}

 

View solution in original post

Dipti_Chauhan
Community Advisor
Community Advisor

Hi @Art_Broussard 

  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;
    }
    
  
}