Home » Software Development » Atlassian » Atlassian Confluence Job Config Module Example

About Joel Patrick Llosa

I graduated from Silliman University in Dumaguete City with a degree in Bachelor of Science in Business Computer Application. I have contributed to many Java related projects at Neural Technologies Ltd., University of Southampton (iSolutions), Predictive Technologies, LLC., Confluence Service, North Concepts, Inc., NEC Telecom Software Philippines, Inc., and NEC Technologies Philippines, Inc. You can also find me in Upwork freelancing as a Java Developer.

Atlassian Confluence Job Config Module Example

We are going to learn to create a simple Job Config Module for the Atlassian Confluence Server in this article. This Confluence Plugin Module Type is available in version 5.10 or later. The most common use of the Job Config Module is when we want our application to run scheduled and repeatable tasks. Let us begin.

1. Requirements

  1. Atlassian SDK
  2. Mars Eclipse
  3. Have created a simple Atlassian Confluence add-on. See Atlassian Confluence Add-on Development Examples if you haven’t done so.
  4. Familiar with Apache Maven.

2. Create the Plug-in

We create the plugin by running the atlas-create-confluence-plugin command in our terminal. Type in com.javacodegeeks.example for the groupId and job-config-module for the artifactId. Accept the defaults for version and package by pressing ENTER. Press Y to finish and accept everything. This will create the stub code for our plugin.

3. Prune the Skeleton Code

Delete some of the unnecessary files that were generated. Our job-config-module directory should contain the following files:

  • pom.xml
  • README
  • LICENSE
  • Under “src/main/resources” – atlassian-plugin.xml, job-config-module.properties, css folder, images folder, js folder, and META-INF folder (all folders contain their default files)
  • Under “src/main/java” – com.javacodegeeks.example package and under it VerifyStatusPageJob.java

We have deleted the “test” directory which we will not need. We have also replaced the generated package and removed the generated java files in it. We will be creating the VerifyStatusPageJob.java later.

4. Modify the pom.xml

We need to add a dependency and some import package entries in our pom.xml. Check out Apache Maven if you don’t know where to insert the lines below.
pom.xml

snipped...

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.6.RELEASE<version>
  <scope>provided</scope>
</dependency>

snipped...

<!-- Add package import here -->
  <Import-Package>
    com.atlassian.sal.api.transaction,
    com.atlassian.confluence.xhtml.api,
    com.atlassian.confluence.pages,
    org.springframework.osgi.*;resolution:="optional",
    org.eclipse.gemini.blueprint.*;resolution:="optional",
    *
  </Import-Package>

snipped...

The above shows that we will be using the Spring Framework library. We need to import com.atlassian.sal.api.transaction, com.atlassian.confluence.xhtml.api, and com.atlassian.confluence.pages because we will be injecting some of its objects.

We then execute atlas-mvn eclipse:eclipse to create our .classpath and .project files so that we will be able to import this Maven project into Eclipse.

5. Add the Job Config Module in the Plugin Descriptor

atlassian-plugin.xml

<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">
    <plugin-info>
        <description>${project.description}</description>
        <version>${project.version}</version>
        <vendor name="${project.organization.name}" url="${project.organization.url}" />
        <param name="plugin-icon">images/pluginIcon.png</param>
        <param name="plugin-logo">images/pluginLogo.png</param>
    </plugin-info>

    <!-- add our i18n resource -->
    <resource type="i18n" name="i18n" location="job-config-module"/>
    
    <!-- add our web resources -->
    <web-resource key="job-config-module-resources" name="job-config-module Web Resources">
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        
        <resource type="download" name="job-config-module.css" location="/css/job-config-module.css"/>
        <resource type="download" name="job-config-module.js" location="/js/job-config-module.js"/>
        <resource type="download" name="images/" location="/images"/>

        <context>job-config-module</context>
    </web-resource>
    
    <job-config name="Verify Status Page" key="verifyStatusPageJobConfig">
        <job key="verifyStatusPageJob" perClusterJob="true"/>
        <schedule cron-expression="0 0 1 * * ?" jitterSecs="10"/> <!-- everyday at 1am -->
        <managed editable="true" keepingHistory="true" canRunAdhoc="true" canDisable="true"/>
    </job-config>

</atlassian-plugin>

Take note of the highlighted lines. It describes our Job Config Module. The job-config name represents how this job config will be referred to in Confluence. The key represents the internal name for the job. The key points to the JobRunner component. The key is also the class name with a lowercased first letter. A true perClusterJob means that the job will only run once in a cluster rather than on every node. The cron-expression means that the job is ran everyday at 1:00 a.m. The jitterSecs provides the random jitter to prevent many processes from doing similar things all at once. When editable is true the job’s schedule can be edited. When keepingHistory is true the job’s history persists and survives server restarts. When canRunAdhoc is true the job can be executed manually. When canDisable is true the job can be enabled or disabled.

6. Modify the Properties File

We add the line in our job-config-module.properties like below. This text will be displayed in the Scheduled Jobs Administration Screen.
job-config-module.properties

#put any key/value pairs here
scheduledjob.desc.verifyStatusPageJobConfig=Verify Space Status

7. Create the JobRunner Component

VerifyStatusPageJob.java

package com.javacodegeeks.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.atlassian.confluence.content.render.xhtml.DefaultConversionContext;
import com.atlassian.confluence.content.render.xhtml.XhtmlException;
import com.atlassian.confluence.pages.Page;
import com.atlassian.confluence.pages.PageManager;
import com.atlassian.confluence.xhtml.api.MacroDefinition;
import com.atlassian.confluence.xhtml.api.MacroDefinitionUpdater;
import com.atlassian.confluence.xhtml.api.XhtmlContent;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.renderer.RenderContext;
import com.atlassian.sal.api.transaction.TransactionCallback;
import com.atlassian.sal.api.transaction.TransactionTemplate;
import com.atlassian.scheduler.JobRunner;
import com.atlassian.scheduler.JobRunnerRequest;
import com.atlassian.scheduler.JobRunnerResponse;

@Component
public class VerifyStatusPageJob implements JobRunner {

	private final PageManager pageManager;
	private final XhtmlContent xhtmlContent;
	private final TransactionTemplate transactionTemplate;
	
	@Autowired
	public VerifyStatusPageJob(@ComponentImport PageManager pageManager,
			@ComponentImport XhtmlContent xhtmlContent, @ComponentImport TransactionTemplate transactionTemplate) {
		this.pageManager = pageManager;
		this.xhtmlContent = xhtmlContent;
		this.transactionTemplate = transactionTemplate;
	}
	
	@Override
	public JobRunnerResponse runJob(JobRunnerRequest request) {
		if (request.isCancellationRequested()) {
			return JobRunnerResponse.aborted("Job cancelled.");
		}
		
		transactionTemplate.execute(new TransactionCallback() {
			@Override
			public Void doInTransaction() {
				Page page = pageManager.getPage("ds", "Space Status"); // space key, page title
				page.setBodyAsString(updatePage(page));
				
				return null;
			}
		});
		
		return JobRunnerResponse.success("Job finished successfully.");
	}
	
	private String updatePage(final Page page) {
		try {
			return xhtmlContent.updateMacroDefinitions(page.getBodyAsString(), 
					new DefaultConversionContext(new RenderContext()), new MacroDefinitionUpdater() {
				@Override
				public MacroDefinition update(MacroDefinition macroDefinition) {					
					if (macroDefinition.getName().equals("status")) {
						macroDefinition.setTypedParameter("colour", "Yellow");
						macroDefinition.setTypedParameter("title", "Pending");
					}
					return macroDefinition;
				}
				
			});
		} catch (XhtmlException e) {
			e.printStackTrace();
		}
		
		return page.getBodyAsString();
	}
}

This class implements the JobRunner interface which is a requirement for all Job Config Modules. We are able to inject objects like PageManager using @ComponentImport because we have imported this package in our pom.xml. Remember, we edited the pom.xml in the fourth step? On to where the action is, the runJob method is executed by the Atlassian Scheduler. We need to wrap our job execution in a transaction because we are making use of our own component which is not declaratively wrapped in a transaction via Spring configuration.

Our job searches for the “Space Status” page (we will be creating this page) in the “Demonstration Space”. The space key for “Demonstration Space” is ds. After that, the page is searched for the Status macro. The Status macro color and title are then changed to yellow and pending, respectively.

8. Try the Plugin

Let’s run the plugin by executing atlas-run in the terminal. Use admin as the password and username. We can access Confluence at http://localhost:1990/confluence. Firstly, we will create the Space Status page. The Space Status page should look like the one below. Don’t forget that “UNDER REVIEW” is a Status macro.

Space Status Page Job Config Module

Space Status Page

Go to the Scheduled Jobs Administration section (click on the cog at the upper right corner) and locate the Verify Space Status job. Execute the job by clicking on Run. The Administration section looks like the one below.

Scheduled Jobs Page Job Config Module

Scheduled Jobs Administration Section

Go back to the Space Status page or reload it and you should see that “UNDER REVIEW” has changed to “PENDING”. It should look like the one below.

Updated Space Status Page Job Config Module

Final Output

9. Summary of the Job Config Module Example

That was easy, wasn’t it? To summarize, we must implement the JobRunner interface to create a Job Config Module component. The main work of our Job must execute in a transaction. Our Job can execute in a scheduled manner based on a cron expression. The key name must be the same as the class name of the component. For more information, check out Job Config Module and Job Module.

10. Download the Source Code

This is an example of building a Job Config Module for Atlassian Confluence Server.

Download
You can download the source code of this example here: atlassian-confluence-job-config-module-example.zip.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

 

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments