How to use Studio's Jobs Framework - CMCC 12

Last updated 9 days ago

This tutorial shows how to use the jobs framework to trigger a background process via a user action and monitor its progress. In the given example, the result of the job will be newly created content.

Implementing the Studio Server Part

JobFactory

Let’s start with the Java part of the implementation. To define a new job, you first have to set up a new com.coremedia.rest.cap.jobs.JobFactory that is responsible for creating new com.coremedia.rest.cap.jobs.Job instances:

public class ContentCreationJobFactory implements JobFactory {

  @Autowired
  private ContentCreationService contentCreationService;

  public ContentCreationJobFactory() {
  }

  @Override
  public boolean accepts(@NonNull String jobType) {
    return jobType.equals("createContent");
  }

  @NonNull
  @Override
  public Job createJob() {
    return new CreateContentJob(contentCreationService);
  }
}

The factory implementation is quite simple. It implements the interface JobFactory and tells the framework to create new instances of class CreateContentJob. It also checks if it is responsible for a given job type. In this case it only accepts jobs with the type "createContent". Additionally, we have injected the class ContentCreationService here, which takes care of the actual content creation.

Next, you have to add the factory to your Spring configuration:

@Bean
public ContentCreationJobFactory contentCreationJobFactory() {
  return new ContentCreationJobFactory();
}

Next, you will take a closer look at the Job implementation.

Job

public class CreateContentJob implements Job {
  private String targetFolder;
  private ContentCreationService contentCreationService;

  CreateContentJob(ContentCreationService contentCreationService) {
    this.contentCreationService= contentCreationService;
  }

  @Nullable
  @Override
  public List<Content> call(@NonNull JobContext jobContext) throws JobExecutionException {
    return contentCreationService.createContent(targetFolder, jobContext);
  }

  @SuppressWarnings("unused") //used by JobsFramework
  public void setTargetFolder(String targetFolder) {
    this.targetFolder = targetFolder;
  }
}

In this example, the whole logic of the actual content creation is delegated to the ContentCreationService which we will cover in the next section. The interesting part here is the property targetFolder. The value is passed by the client as JSON parameter during the job creation in the Studio client API. To make this parameter known to the Java implementation, you have to define a corresponding setter method here, in this case public void setTargetFolder(String targetFolder).

The parameter is passed later to the ContentCreationService.

Jobs and JobContext

Let’s see how the actual implementation in the ContentCreationService may look like:

List<Content> createContent(String targetFolder, JobContext jobContext) {
  List<Content> createdContent = new ArrayList<>();

  //progress calculation for the executing job
  int amountToProcess = 10;

  for (int i=0; i<amountToProcess ; i++) {
     //TODO implement actual content creation here and add it to the result 'createdContent'

     //progress notification for the executing job
    jobContext.notifyProgress(i / amountToProcess);
  }

  return createdContend;
}

For the sake of simplicity, we haven’t implemented the details of the content creation here. The important part is the usage of the JobContext here. Each time a content is created, the framework and also the client get notified, that progress has been made. The Job is finished once the amount of progress equals 1.

The result of the job is returned to the client. In this example, it is a list of Content instances which will be converted to client-side Content RemoteBeans automatically. If you pass any other data, ensure that it can be serialized to JSON.

The Java part for creating a new Job is finished. Let’s take a look on the client-side next.

Implementing the Studio Client Part

Similar to the Java backend, you also have to declare a job implementation for the Studio client:

public class CreateContentJob extends RemoteJobBase implements BackgroundJob {
  private var targetFolder:String
  private var ctx:JobContext;

  public function CreateContentJob(targetFolder:String) {
    this.targetFolder = targetFolder;
  }

  override public function execute(jobContext:JobContext):void {
    this.ctx = jobContext;
    super.execute(jobContext);
  }

  override protected function getJobType():String {
    return  "createContent";
  }

  override protected function getParams():Object {
    return {
      targetFolder: targetFolder
    };
  }

  override protected function mayRetry():Boolean {
    return false;
  }

  public function getNameExpression():ValueExpression {
    return ValueExpressionFactory.createFromValue(msg);
  }

  public function getIconClsExpression():ValueExpression {
    return ValueExpressionFactory.createFromValue(item.getTypeCls());
  }

  public function getErrorHandler():Function {

  }

  public function getSuccessHandler():Function {

  }
}

The class extends from RemoteJobBase which provides some basic functionality for jobs. The implementation of the interface BackgroundJob ensures that the visualization of the progress is added to the Jobs window, which is located in the upper right corner of Studio. The interface requires the implementation of the following methods:

  • getNameExpression(): Returns a ValueExpression which contains the name of the job to display.

  • getIconClsExpression(): Returns a ValueExpression which contains the icon class to display for this job.

  • getErrorHandler(): The method to call when the error button is displayed in case of an error.

  • getSuccessHandler(): The method to call when the success button is displayed after the job has been finished.

Also, note that the getParams() method returns the value for the targetFolder parameter as defined in the Java backend. The job type matches the one in Java defined too: "createContent".

Finally, let’s take a look how the job is invoked:

var job:CreateContentJob = new CreateContentJob(targetFolder);
var trackedJob:TrackedJob = jobService.executeJob(job,
        //on success
        successCallback,
        //on error
        function (result:Object):void {
        });

This code can be added as handler implementation for an action or a button. Again it supports an error and a success handler which are called as a result of the actual REST call.

Summary

This How-To gave a brief introduction into Studio’s job framework. Feel free to leave a comment if you miss something.

Copyright © 2024 CoreMedia GmbH, CoreMedia Corporation. All Rights Reserved.
Loading...