Guide - Extending the JIRA Import plugin

This guide will help you extend the JIRA Import plugin using the Project Importer SPI. Currently, you can extend the JIRA importer plugin to include data from your plugins during project imports.

On this page:

Overview

The JIRA Import plugin is used to import a JIRA project from a backup file into a JIRA instance (see documentation). One of the limitations of the JIRA Import plugin is that it cannot handle plugin data, which means that you cannot move plugin data between JIRA instances. An exception to this is custom fields, but even custom fields have limited support, e.g. the JIRA Agile sprint field might bring data across pointing to a sprint, but that sprint will not exist in the new JIRA instance.

The reason behind this limitation is that the JIRA import plugin does not have any idea of what data is stored by plugins or what the meaning and relationships with in that data are. It cannot tell what data refers to what projects or issues or even if the data is related to a project. For example, JIRA Agile is not organised around projects, but rather uses JQL to define rapid boards, etc.

The solution to this limitation is to let plugins actively participate in the import process. Read the following sections for an overview of the project import process and how your plugins can interact with the Project Importer SPI at each part of the process.

JIRA Project Importer SPI

The project import process consists of a number of steps. The Project Importer SPI allows a plugin to participate in any of these steps. The basic flow is:

  1. JIRA processes the XML, extracting information about the project and issues in the backup, and mapping configuration items, e.g. issue type ids from the source system to the values on the target system.
  2. JIRA processes the XML again, splitting it into a number of files, one for each entity type to be imported, e.g. <jiraissue><customfieldvalue>, <jiraaction>, etc.
  3. JIRA creates the project, if required.
  4. JIRA creates the issues and the issue-related data, such as comments and change history.

There are a number of basic mechanisms that your plugin needs to interact with:

  • Each data entity type (table) can be processed by the plugin, if it chooses to provide a handler for that entity type.
  • There is a collection of Mappers that the plugin can use and contribute to, to work out how data is mapped between IDs in the source and IDs in the target system.
  • The plugin can also contribute results that will appear in the user interface, summarising the results of the import, by adding results to the ProjectImportResult object.
  • Additionally, for AO data the plugin can specify the order in which the AO entities should be imported, so that they can control the rebuilding of dependencies between data.

(info) In this document, we refer to the "JIRA Project Importer SPI" or just the "SPI" as we are mostly describing a set of interfaces that plugins will need to implement to fully participate in a project import.  However, both SPI and API points will be provided and described.


In this section:

Adding to the project validation

Plugins can add to the validation that is performed before the import is done.

The process is quite complex, but in essence JIRA does a pass over the JIRA backup and gathers essential information for each project, such as the issue types and custom fields used. This information is held in the session. Once the user selects a project to import, JIRA validates the data from the backup for that project against the current system state.

The SPI described here allows plugins to join in that process.

Interface com.atlassian.jira.imports.project.ao.handler.PluggableOverviewAoEntityHandler

Defines a handler class that will be able to gather data from the backup, that can then be used for validation or other purposes. This handler will be called in the initial stages of the import before the user is presented with a list of projects, from which they select the project to import.

The plugin point for this handler is: <project-import-ao-overview-handler>.

  Show method summary...
Method Summary
void

endTable(String tableName)

          Provides the implementation an opportunity to perform some action when all rows for a table have been processed.

void endDocument()
          Provides the implementation an opportunity to perform some action when the document has finished being read.
void

handleEntity(java.lang.String entityName, java.util.Map<java.lang.String, java.lang.Object> attributes)
          This is the main method to implement when using this ImportEntityHandler. This method will provide the entity name and a complete map of attribute key/value pairs.

          The attributes may be any of String, Long, Double, Boolean or Date.

boolean

handlesEntity(java.lang.String entityName)

          Should return true if the user wishes to process this entity.

void

startDocument()
          Provides the implementation an opportunity to perform some action when the document is starting to be read.
void

setBackupOverviewBuilder(BackupOverviewBuilder backupOverviewBuilder)

          Sets the backup overview. Plugins should use BackupOverviewBuilder.addAdditionalData(String key, String projectId, Object data) to store critical backup data for each project in the backup.

          Multiple entries may be added under the same project and key.

As this is a session object, this should only contain the minimum data required to ensure that the import can proceed for a project.

Interface com.atlassian.jira.imports.project.ao.PluggableValidator

Defines a class that will be called to validate that the selected project can be imported.

Plugin developers need to understand the user flow here:

  1. The user selects a project to import.
  2. JIRA will then validate if the plugin can be imported. PluggableValidator implementations will be called during this stage.
  3. The user can then respond to errors by configuring items in JIRA.
  4. The user can then redo the validation step or select a different project to import.

The plugin point for this handler is: <project-import-validator>.

  Show method summary...
Method Summary
ValidationMessage

validate(BackupProject backupProject, I18nHelper i18n)

The backupProject will contain any data contributed by the PluggableOverviewAoEntityHandler. See Collection<Object> BackupProject.getAdditionalData(String key)

Importing data

Interface com.atlassian.jira.imports.project.ao.handler.PluggableImportAoEntityHandler

Defines a handler class that will be able to perform some operation, given an AO entity name and the entities attributes.

There are two plugin points that both use this handler, <ao-preimport-handler> and <ao-import-handler>:

  • <ao-preimport-handler>, will be called during the first import stage when the activeobjects.xml is split into files for each entity type. Plugins can gather data at this stage and store that, using instances of AbstractMapper, for use in the actual import stage.
  • <ao-import-handler>, will be called after the OfBiz data has been installed. This is the time when plugins would normally import the required data into the database.
  Show method summary...
Method Summary
void

endTable(String tableName)

          Provides the implementation an opportunity to perform some action when all rows for a table have been processed.

void endDocument()
          Provides the implementation an opportunity to perform some action when the document has finished being read.
void

handleEntity(java.lang.String entityName, java.util.Map<java.lang.String, java.lang.Object> attributes)
          This is the main method to implement when using this ImportEntityHandler. This method will provide the entity name and a complete map of attribute key/value pairs.

          The attributes may be any of String, Long, Double, Boolean or Date.

boolean

handlesEntity(java.lang.String entityName)

          Should return true if the user wishes to process this entity.

long

getEntityWeight(java.lang.String entityName)

          Return the weight for this entity. If this handler is does not handle the entity or care about its ordering it should return com.atlassian.jira.imports.project.ao.handler.PluggableImportAoEntityHandler.WEIGHT_NONE.

          This is ignored (not called) during the pre-import stage where the entities are supplied in the backup XML order.

void

startDocument()
          Provides the implementation an opportunity to perform some action when the document is starting to be read.
void

setProjectImportMapper(ImportMapper projectImportMapper)

          A setter for the ImportMapper.  This will be injected when the instance is created.

void

setProjectImportResults(ProjectImportResults projectImportResults)

          A setter for the ProjectImportResults.  This will be injected when the instance is created.

void

setBackupSystemInformation(BackupSystemInformation backupSystemInformation)

          A setter for the BackupSystemInformation.  This will be injected when the instance is created.

void

setBackupProject(BackupProject backupProject)

          A setter for the BackupProject.  This will be injected when the instance is created.

Plugins should define one or more implementation of this interface to process any Active Objects data they wish to persist into the database, and also to observe any Active Objects data they wish to observe from any other JIRA  or plugin entities.

Interface com.atlassian.jira.imports.project.handler.PluggableImportOfBizEntityHandler

Defines a handler class that will be able to perform some operation, given an OfBiz entity name and the entities attributes.

There are two plugin points that both use this handler, <ofbiz-preimport-handler> and <ofbiz-import-handler>:

  • <ofbiz-preimport-handler> will be called during the first import stage when the entities.xml is split into files for each entity type. Plugins can gather data at this stage and store that, using instances of AbstractMapper, for use in the actual import stage.
  • <ofbiz-import-handler> will be called as JIRA imports the OfBiz Data. Plugins may need to import some data during this stage, e.g. entity properties.
  Show method summary...
Method Summary
void endDocument()
          Provides the implementation an opportunity to perform some action when the document is finished being read.
void handleEntity(java.lang.String entityName, java.util.Map<java.lang.String, java.lang.String> attributes)
          This is the main method to implement when using this ImportEntityHandler. This method will provide the entity name and a complete map of attribute key/value pairs.
boolean

handlesEntity(java.lang.String entityName)

          Should return true if the user wishes to process this entity.

void

startDocument()
          Provides the implementation an opportunity to perform some action when the document is starting to be read.
void

setImportMapper(ImportMapper projectImportMapper)

          A setter for the ImportMapper.  This will be injected when the instance is created.

void

setProjectImportResults(ProjectImportResults projectImportResults)

          A setter for the ProjectImportResults.  This will be injected when the instance is created.

void

setBackupSystemInformation(BackupSystemInformation backupSystemInformation)

          A setter for the BackupSystemInformation.  This will be injected when the instance is created.

void

setBackupProject(BackupProject backupProject)

          A setter for the BackupProject.  This will be injected when the instance is created.

Plugins should define one or more implementation of this interface to process any OfBiz data they wish to persist into the database, and also to observe any OfBiz data they wish to observe from any other JIRA entities.

Class com.atlassian.jira.imports.project.mapper.AbstractMapper

Plugins should provide a concrete implementation of this class when they need to map old values from the source system to new values in the destination and/or to flag values as required.  They can, of course, extend it to provide any additional data they required to help in completing the import process. A general purpose mapper, SimpleProjectImportIdMapperImpl, is provided for use in trivial cases.

Instances of the mapper are available by calling the getPluggableMapper(String mapperKey) on the ImportMapper.

  Show method summary...
Method Summary
 void clearMappedValues()
          This will clear any mapped data that may have been entered into the mappers.
 void flagValueAsRequired(java.lang.String oldId)
          This is an internal method for use by Mappers extending AbstractMapper and should not be called from other classes.
 java.util.Collection<java.lang.String> getAllMappedIds()
          Returns a Collection of all the new IDs that are mapped to.
 java.lang.String getDisplayName(java.lang.String oldId)
          Returns a display name for the given old ID.
 java.lang.String getKey(java.lang.String oldId)
          Returns the registered "key" for the given old ID, or null if none is registered.
 java.lang.String getMappedId(java.lang.String oldId)
          Retrieves a String that corresponds to the id in the target JIRA system, null if none has been mapped.
 java.util.Collection<java.lang.String> getRegisteredOldIds()
          Returns a collection of ID's as String objects identifying all objects of the appropriate type found in the import file.
 java.util.Collection<java.lang.String> getRequiredOldIds()
          Returns a collection of ID's as String objects identifying objects from the import file that are required for the import.
 java.util.Collection<IdKeyPair> getValuesFromImport()
          Deprecated. Use getRegisteredOldIds()
 void mapValue(java.lang.String oldId, java.lang.String newId)
          This method maps a value from the backup system to a valid value in the target system.
 void registerOldValue(java.lang.String oldId, java.lang.String oldKey)
          This is an internal method for use by Mappers extending AbstractMapper and should not be called from other classes.

Interface com.atlassian.jira.imports.project.handler.PluggableImportRunnable

There are two plugin points that both use this handler, <preimport-handler> and <postimport-handler>:

  • <preimport-handler> defines a handler class that will be called after the project object is created, but before any configuration or issue data is imported. Plugins can use this handler to examine the state of the target system before the import begins.
  • <postimport-handler> defines a handler class that will be called after the all data is imported into the destination system.
  Show method summary...
Method Summary

void

run()
          Provides the implementation an opportunity to perform some action.
void

setImportMapper(ImportMapper projectImportMapper)

          A setter for the ImportMapper.  This will be injected when the instance is created.

void

setProjectImportResults(ProjectImportResults projectImportResults)

          A setter for the ProjectImportResults.  This will be injected when the instance is created.

void

setBackupSystemInformation(BackupSystemInformation backupSystemInformation)

          A setter for the BackupSystemInformation.  This will be injected when the instance is created.

void

setBackupProject(BackupProject backupProject)

          A setter for the BackupProject.  This will be injected when the instance is created.

Plugin custom field types

Interface com.atlassian.jira.imports.project.customfield.ProjectImportableCustomField

Any plugins that provide custom field types that need to be migrated need to implement the ProjectImportableCustomField interface. This interface requires the class to provide a ProjectCustomFieldImporter that will look after any data translation required during the archiving process.

  Show method summary...
Method Summary
 ProjectCustomFieldImporter getProjectImporter()
          Returns the object that will perform the actual project import functions for the custom field type.

Interface com.atlassian.jira.imports.project.customfield.ProjectCustomFieldImporter

Plugins also need to supply or use a current JIRA implementation of this interface to actually map the imported data as required.

  Show method summary...
Method Summary
 MessageSet canMapImportValue(ProjectImportMapper projectImportMapper, ExternalCustomFieldValue customFieldValue, FieldConfig fieldConfig, I18nHelper i18n)
          The custom field needs to determine if the provided custom field value, in the context of the config and project import mapper, is a valid value that can be imported.
 ProjectCustomFieldImporter.MappedCustomFieldValue getMappedImportValue(ProjectImportMapper projectImportMapper, ExternalCustomFieldValue customFieldValue, FieldConfig fieldConfig)
          The custom field needs to determine what the "mapped" value will be for the provided custom field value and return this new string representation of the value.

Contributing results

Each import handler is injected with the ProjectImportResults object. Plugins can add results to this using the following:

  Show method summary...
Method Summary
 ProjectImportResult void addResult(long count, String msgKey) 
          Add an import result.
          This method is provided to enable plugins to supply counts of items imported.
          Plugins should try to display only a small amount of the most relevant information so as not to overwhelm the user and clutter the result

Plugin XML

This section describes the key elements for your plugin descriptor, if you are using the Project Importer SPI. An example of the plugin XML is shown below:

<?xml version="1.0" encoding="UTF-8"?>
<atlassian-plugin >

    <project-import-ao-overview-handler key="myplugin-ao-overview-handler" class="com.atlassian.jira.dev.myplugin.imports.project.MyReferenceAoOverview" />
    <project-import-validator key="myplugin-import-validator" class="com.atlassian.jira.dev.myplugin.imports.project.MyProjectImportValidator" />
    <project-preimport-handler key="myplugin-preimport-handler" class="com.atlassian.jira.dev.myplugin.imports.project.MyPreImportPluginModule" />
    <project-postimport-handler key="myplugin-postimport-handler" class="com.atlassian.jira.dev.myplugin.imports.project.MyPostImportPluginModule" />
    <project-ao-preimport-handler key="myplugin-ao-preimport-handler" class="com.atlassian.jira.dev.myplugin.imports.project.MyAoPreImport" />
    <project-ao-import-handler key="myplugin-ao-import-handler" class="com.atlassian.jira.dev.myplugin.imports.project.MyAoImport" />
    <project-ofbiz-preimport-handler key="myplugin-ofbiz-preimport-handler" class="com.atlassian.jira.dev.myplugin.imports.project.MyOfBizPreImport" />
    <project-ofbiz-import-handler key="myplugin-ofbiz-import-handler" class="com.atlassian.jira.dev.myplugin.imports.project.MyOfBizImport" />

</atlassian-plugin>

 

For the definition of the contents of these elements, see below:

  Show contents of the Pre Import Entity Handler definition...

Element

Attribute

Description

<project-import-ao-overview-handler>

 

This block defines a handler that will be called while JIRA gathers data for al projects in the backup before the import starts.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableOverviewAoEntityHandler

 

  Show contents of the Pre Import Entity Handler definition...

Element

Attribute

Description

<project-import-validator>

 

This block defines a module that can validate that a selected project is OK to import.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableValidator

 

  Show contents of the Pre Import Entity Handler definition...

Element

Attribute

Description

<project-preimport-handler>

 

This block defines a handler that will be called before the import of data commences.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableImportRunnable

  Show contents of the Post Import Handler definition...

Element

Attribute

Description

<project-postimport-handler>

 

This block defines a handler that will be called after the import of data is complete.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableImportRunnable

  Show contents of the OfBiz Pre-Import Entity Handler definition...

Element

Attribute

Description

<project-ofbiz-preimport-handler>

 

This block defines a handler that will be called for each data row for OfBiz tables that are handled.

It is called during the preprocessing of the data, when all "entities.xml" entry from the backup zip file is processed in one pass and the entity types (tables) are split into separate files. Entities are processed in the order they are contained in the backup, which is alphabetical order.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableImportOfBizEntityHandler

  Show contents of the Active Objects Pre-Import Entity Handler definition...

Element

Attribute

Description

<project-ao-preimport-handler>

 

This block defines a handler that will be called for each data row for Active Objects tables that are handled.

It is called during the preprocessing of the data, when all "activeobjects.xml" entry from the backup zip file is processed in one pass and the entity types (tables) are split into separate files. Entities are processed in the order they are contained in the backup, which is alphabetical order.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableImportAoEntityHandler.

  Show contents of the OfBiz Import Entity Handler definition...

Element

Attribute

Description

<project-ofbiz-import-handler>

 

This block defines a handler that will be called for each data row for OfBiz tables that are handled.

It is called during the import of the data. The import of the data is actually performed by JIRA and generally plugins would not need to do anything at this time, but they can observe the data if they wish.

The ordering of the data is controlled by JIRA and is undefined and may change from one JIRA to another.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableImportOfBizEntityHandler

  Show contents of the AoBiz Import Entity Handler definition...

Element

Attribute

Description

<project-ao-import-handler>

 

This block defines a handler that will be called for each data row for Active Objects tables that are handled.

It is called during the import of the data. Plugins should import their data at this time. 

The ordering of the data is determined by the results of the calls to getEntityWeight(String entityName) with lowest values processed first. Plugin developers may cooperate to weight entities appropriately so plugin A's data is imported before plugin-B's data. Entities with lower weights are imported before entities with higher weights.

 

key

The key of this handler definition.  Must be unique within the plugin.

 

class

An implementation of PluggableImportAoEntityHandler

Notes

  • Active Object and Property set data is imported after JIRA Configuration data and JIRA Issues (the "jiraissue" entity).
  • Property set data is pre-processed into a joined format, joining <property-entry> and <property-????> data, i.e. an <OSPropertyString> entry will also have the entityName and propertyKey attributes.
Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport