Global App Configuration SPI

On this page:

SPI API Reference

If you need more technical information on the latest SPI packages and interfaces, please read the complete API reference.

Get Started

Jira apps may store configuration data that does not belong to any project but applies to all projects - i.e., "global" configuration. The Service Provider Interface for global app configuration provides the facilities for moving such configuration between different Jira instances. Configuration Manager will handle all the heavy load around moving the right configuration elements which are referenced in the global configuration - for example, custom fields, users and groups, etc. When creating a snapshot, users will be allowed to choose whether to include a global app configuration. You can learn more about migrating global app data with CMJ from this document.

This integration point is available since SPI 1.5.0 and requires Configuration Manager version 6.4.5.

GlobalConfigurationHandler

The SPI for global app configuration consists of only one interface - com.botronsoft.cmj.spi.configuration.global.GlobalConfigurationHandler.

/** * Implement this interface to handle export/import for custom configuration which is global for the Jira instance. * * The implementation of this interface is responsible for serializing/deserializing global configuration data and recording references to * Jira configuration elements like users, groups, custom fields, etc. * * @see ConfigurationReferenceCollector * @see ConfigurationReferenceLookup */ @PublicSpi public interface GlobalConfigurationHandler { /** * Invoked when a configuration is being exported. This method will be called by Configuration Manager when the app which implements it * is selected for export. Implementors may return {@link Optional#empty()} if there is no configuration to be exported. * * Implementers may call {@link ConfigurationReferenceCollector} methods to handle references to other configuration objects. * * @param exportContext * context of the export operation. * @return an {@link Optional} with the exported configuration or {@link Optional#empty} if the app does not store any global * configuration. * * @see ExportContext */ Optional<String> exportConfiguration(ExportContext exportContext); /** * Invoked when a configuration is being imported. * * Implementers can call {@link ConfigurationReferenceLookup} methods to retrieve the respective matching configuration objects referred * with {@link ConfigurationReferenceCollector}. * * @param configuration * the configuration as serialized by {@link GlobalConfigurationHandler#exportConfiguration(ExportContext)}. * @param importContext * context of the import operation. * * @see ImportContext */ void importConfiguration(String configuration, ImportContext importContext); /** * Invoked when configuration needs to be deleted. This method will be called by Configuration Manager when app data is deleted. * */ void deleteConfiguration(); }

An app may declare only one implementation of this interface.

Below, you will find details about how the different methods of this interface will be invoked by Configuration Manager.

  • exportConfiguration is invoked when a project snapshot is being created, and the global configuration of an app that implements this interface is selected for export. The method will also be invoked during a system snapshot creation if the "Export Global App Data" option is selected. The method may return an empty Optional if there is no global configuration currently present.

  • importConfiguration is invoked when a snapshot with a global configuration for a given app is being deployed, and the global configuration is not empty - i.e. if exportConfiguration returned a non-empty Optional during snapshot creation.

  • deleteConfiguration is invoked when a snapshot with a global configuration for a given app is deployed. The global configuration is empty - i.e. if exportConfiguration returned an empty Optional during snapshot creation.

Configuration Serialization and Versioning

The SPI does not impose any restrictions on how the configuration in each property value is serialized, only that the end result should be a String.

Collecting References

The global app data may contain references to other configuration elements in Jira, such as custom fields, saved filters, etc. It is essential that during export, Configuration Manager is notified about these references because the IDs of these elements may be different between the source and the target instance, and Configuration Manager will match them and provide the correct IDs during import.

This can be achieved by invoking the methods of the ConfigurationReferenceCollector interface, accessible via the ExportContext interface. The key must be a unique identifier, which will be used when importing the configuration to resolve the reference on the target instance. The keys need to be unique only within the type of the configuration element - i.e., you can use the same key for a resolution or a status. In this sense, the Jira internal identifiers can be used as keys as well.

Resolving References

When deploying a snapshot, all collected references to other configuration elements must be resolved because the identifiers of these elements are most probably different on the target system.

Use the ConfigurationReferenceLookup interface, accessible via the ImportContext interface. It provides convenient methods for resolving references by the same keys which were provided when collecting these references. The methods return java.util.Optional, because, in certain situations, references may be unresolvable. SPI implementations should be developed to handle this possibility.

Merge vs. Restore

When a configuration is imported, it may be necessary to distinguish between the merge and restore modes in which Configuration Manager operates. In merge mode, a handler may choose to keep the global app configuration that already exists on the target system and only adds what is new. In restore mode, the whole configuration may be overwritten. A handler may check the current mode by retrieving the ImportMode value via ImportContext.getImportMode().

Registering the Handler with Configuration Manager

There are two options for registering the handler with Configuration Manager - via Java annotations or via the atlassian-plugin.xml

Via Java annotations

Annotate the handler class with the ConfigurationManagerSpiHandler annotation:

@ConfigurationManagerSpiHandler public class SampleAnnotatedGlobalConfigurationHandler implements GlobalConfigurationHandler { ... }

In addition, the following entry needs to be added to the atlassian-plugin.xml which specifies the Java packages which contain the handlers:

<!-- Configuration Manager SPI Handler Packages --> <configurationManagerSpiHandler key="configuration-manager-spi-handler-packages"> <package>com.mycompany.app.handlers</package> </configurationManagerSpiHandler>

Only one entry is needed per app - multiple packages may be defined if required. Configuration Manager will scan the classes in these packages for the SPI annotations.

Via atlassian-plugin.xml

Another approach is to directly declare the handler in atlassian-plugin.xml and create a <globalConfigurationHandler> tag with the attributes below.

Here is the list of supported attributes:

Attribute

Purpose

Attribute

Purpose

The unique key of the SPI implementation.

Required: yes

The implementation class - must extend the com.botronsoft.cmj.spi.configuration.global.GlobalConfigurationHandler.

Required: yes