Defining a Pluggable Service in a Confluence Plugin
The source code of the plugin used in this tutorial is available in the Atlassian public source repository. You can check out the source code here. You will find two projects within this directory:
Contains the service component and the module type definitions
A plugin which defines a report
On this page:
- Defining a Module Type
- Defining a Service that allows implementations of the Module Type to be listed
- Implement an instance of the Module Type
The example we are implementing is a reporting service that provides a way for other plugins to provide reports to be viewed through a single interface.
To complete this tutorial, you must already understand the basics of Java development: classes, interfaces, methods, how to use the compiler, and so on. You should also understand:
- How to create an Atlassian Confluence plugin project using the Atlassian Plugin SDK.
- How to compile and install your project within Confluence.
As this is an advanced plugin tutorial we will only highlight or discuss the important parts of the implementation. You should also review the source code for the two example plugins while reading this tutorial.
This tutorial contains two components:
- Reporting Service (
confluence-reporting-service) - which defines a custom report-descriptor plugin module and displays reports
- System Information Report (
system-config-report) - which implements the report-descriptor plugin module to display a simple report about the Confluence system
Report Service Plugin
The Report Service Plugin contains an user interface for viewing the registered reporters and for triggering reports. It also contains the new plugin module type that report implementing plugins can use to identify their reports.
New Module Type
We are defining a new module type called
report in this plugin which allows other plugins specify reports that they are able to produce. A report consists of several properties, used to identify each report, and a method which causes the report to be generated and the results returned. Each plugin that wishes to generate reports must implement the following
Report interface for each report they wish to export:
At this point it is possible to consider an alternative solution to the one we demonstrate here: rather than define a custom module type other plugins could explicitly and programmatically publish their
Report types in a similar manner to the Observer Pattern design pattern. The difference between these approaches will be commented on at the end of the turorial.
In order that plugins can expose their
Report types we define a new XML element to be used in the
atlassian-plugin.xml, this is achieved by extending the
and adding the new module type to the
atlassian-plugin.xml so that other plugins can use the <report> element
So that this plugin and others can query and/or generate the defined reports we implement a simple service component,
ReportService, which is exposed publicly in the plugin xml file:
DefaultReportService implementation of the
ReportService interface uses the
PluginAccessor to access all the
report plugin modules:
this means that at each invocation the list of available plugins is rebuilt, a type of dynamic lookup which is in part what allows this plugin to be "pluggable".
Report Web Interface
The admin report interface is created using a standard web work action, and web-ui module to provide a link in the Confluence admin console. If you have created a plugin with a custom action previously there should be nothing unfamiliar in the setup, if not then there are several tutorials which will easily guide you through this process.
The UI performs two basic tasks: it displays all the available reports, and displays the output of any one report. In both cases the
Action simply invokes a method on the
ReportService to find the appropriate
Report(s). Because the actions are given a path underneath
/admin default Confluence interceptors ensure that only admin users have access to the reports.
Build and install
Once these three components have been set up, you should be able to build and install the plugin in Confluence. When you access the report menu, either via the plugin configure link or the link on the admin sidebar, no reports will be listed as there are no plugins that have a
report module installed yet.
System Reporting Plugin
- Implements the
Reportand returns the system information (similar as to Confluence Admin > System Info page) formatted as a simple (undecorated) HTML page.
As we are going to extend the
Report interface provided in the Report Service plugin we will need to add it as a dependency to our maven project file. Before you can do this we need to install the service plugin into our local maven repository.
From where the service plugin is checked out type:
or (if using the plugin sdk)
to install into your local repository.
Now we can add the dependency to our pom.xml for the system reporting plugin:
Creating the Report
To create a new custom report we need to create a class that implements the
Report interface. Our example report
SystemInformationReport provides simple information about the Confluence system it is installed on.
Once the report is implemented we need to add it to our atlassian-plugin.xml config. We use the new
report module to define our report:
Build and Install into Confluence
Because the system information report plugin depends on the module defined in the reporting service plugin it must be installed into Confluence first.
While this example is kept very simple it is possible to see how it could be extended in to an advanced reporting framework where plugins could export reports covering usage, configuration, or be able to output in different formats (XML, PDF, Word) or collate several reports in to one. Alternatively this mechanism of providing a easily extensible plugin can be applied to other situations.
As mentioned earlier in the tutorial this is not the only possible solution to the problem; the
DefaultReportService performs a dynamic lookup each time all or one of the
Report instances must be fetched which as the number of installed plugins grows, or the number of defined reports, increases in overhead. Implementing the Observer pattern may also help alleviate this, but that is out of scope for this tutorial.