Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

On this page:

Table of Contents
minLevel1
maxLevel6
outlinefalse
styledefault
typelist
printabletrue

In this section, we address the technical aspects that are common to all three types of extensions: workflow, dashboard, and custom entity.

How to implement extensions

All the extensions are Java code (or other JVM-compatible language, like Groovy) to be deployed in Jira as a P2 Jira plugin (app). The extension can be an additional feature in an existing app or a standalone app. For example, a vendor of an app called "X" might develop a PC PCJ extension for the app as an added feature that either goes into the same .jar, or into a separate .jar (called "X extension for Project Configurator") and then distributes it to the Marketplace alongside app "X". The same P2 app can contain an arbitrary combination of workflow, dashboard, or custom entity extensions.

The first option has one technical advantage: it is easier to access and manipulate objects created by app X from the same app , than from a separate one. In this second case, app X would need to export the packages and classes that provide that access/manipulation functionality, and app "X extension for Project Configurator" would have to import and use them. The first option also offers a better, more frictionless user experience. End users can see that by installing compatible versions of X and PCPCJ, migration simply works without having to do anything else. On the other hand, if the extension is delivered in a separate app, the end user would have to install it (in addition to PC PCJ and X) in order to enable the migration of content from X. In favor of a separate app, if app X is already quite large in terms of project size, you may feel wary of adding a new feature to it.

How to identify a

...

PCJ extension

All PC PCJ extensions will be identified by the key of the P2 app to which they belong.

Version compatibility

All PC PCJ extensions must declare which version of PC PCJ they are compatible with. This is done by adding a parameter to the app's atlassian-plugin.xml file, as shown below:

atlassian-plugin.xml

Code Block
languagexml
titleatlassian-plugin.xml
<?xml version="1.0" encoding="UTF-8"?>

<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>
  <param name="min-pc-version-supported">3.8.0</param>
 </plugin-info>
 <!-- add our i18n resource-->
 <resource type="i18n" name="i18n"location="sample-extension-one"/>
 <!-- add our web resources-->
 <web-resource key="sample-extension-one-resources" name="sample-extension-one Web Resources">
  <dependency>com.atlassian.auiplugin:ajs</dependency>
  <resource type="download" name="images/"location="/images"/>
  <context>sample-extension-one</context>
 </web-resource>

</atlassian-plugin>

Note the min-pc-version-supported parameter. This will be interpreted as the extension in this app is compatible with PC PCJ version 3.8.0 , or newer. Version strings are compared as defined in the Semantic Versioning 2.0.0 specification. This parameter is used to filter apps that contain PC PCJ extensions from those that do not. Therefore, if this parameter is not added to the atlassian-plugin.xml file, this app will not be treated as a valid extension by PCPCJ.

Maven dependencies

Your app will need access to the extension-spi jar to use all the interfaces and classes described in this document. Add this dependency to your pom.xml file:

pom.xml

Code Block
languagexmltitlepom.xml
...
	<dependency>
		<groupId>com.awnaba.projectconfigurator</groupId>
		<artifactId>extension-spi</artifactId>
		<version>${projectconfigurator.version}</version>
		<scope>provided</scope>
	</dependency>
...

Some extensions will have to use also the class ObjectAlias, which is defined in a different jar (operations-api). In rare cases, extensions might require other classes from this same jar. In any of these cases, add the following dependency:

pom.xml

xml
Code Block
title
languagexmlpom
.
...
	<dependency>
		<groupId>com.awnaba.projectconfigurator</groupId>
		<artifactId>operations-api</artifactId>
		<version>${projectconfigurator.version}</version>
		<scope>provided</scope>
	</dependency>
...
Tipinfo
title

Where to find the .jar and Javadoc files

Both jars, including their Javadoc, are published to the following URLs: https://nexus.adaptavist.com/content/repositories/external/com/awnaba/projectconfigurator/extension-spi/ https://nexus.adaptavist.com/content/repositories/external/com/awnaba/projectconfigurator/operations-api/

Importing packages

As defined in the Maven dependencies section, the extension will need to use some packages provided by Project Configurator. These will be available through OSGI. Functionally speaking, it would be inconvenient if the extension had to resolve those import packages when it is installed, as there is no guarantee that Project Configurator will be installed in Jira before the extension. The most sensible thing would be that those packages are imported when they are actually needed (this means when an export or import is going to be run by PCPCJ). From the OSGI point of view, this implies that those packages must be declared as "DynamicImport-Package" and not as "Import-Package".

This would be specified in the pom.xml file as:

pom.xml

Code Block
languagexmltitlepom.xml
<build>
	<plugins>
		<plugin>
			<groupId>com.atlassian.maven.plugins</groupId>
			<artifactId>jira-maven-plugin</artifactId>
			<version>${amps.version}</version>
			<extensions>true</extensions>
			<configuration>
				.....
		<!-- See here for an explanation of default instructions: -->
		<!--https://developer.atlassian.com/docs/advanced-topics/configuration-of-instructions-in-atlassian-plugins -->
			<instructions>
				.....

					<!-- Add package import here -->
					<Import-Package> 
						org.springframework.osgi.*;resolution:="optional",
						org.eclipse.gemini.blueprint.*;resolution:="optional",

						<!--Note the packages from PC must be in DynamicImport-Package,
						so the following exclusion is added here -->
						!com.awnaba.projectconfigurator.*,
						*
					</Import-Package>
					<!--Packages from Project Configurator must be imported dynamically to allow the extension to interact with them, even if PCPCJ is installed later -->
					<DynamicImport-Package>
 						com.awnaba.projectconfigurator.*
					</DynamicImport-Package>
					.....

The Hollywood Principle

Creating an extension consists of implementing some of the interfaces which that are defined in the extension-spi-XXXX.jar. You do not have to call the methods offered by those interfaces. PC PCJ will call them at the right times during the export or import operations.

Infotip
title

Remember!

"Don't call us; we'll call you."

Welcome, lazy developers!

In addition to the Hollywood Principle, you do not have to create all of the objects those methods return. PC PCJ offers you some components that act as factories that create many of those objects. These include:

Factory

Type it will create

extensionservices/SimpleReferenceProcessorFactory

extensionservices/ReferenceProcessorComposer

common/ReferenceProcessor<W>

customentities/IdentifierFactory

customentities/PartialIdentifier

customentities/InstanceIndependentIdentifier

How to create objects in an extension

The lifecycle of objects created by an extension is very important for a smooth user experience. If their creation is triggered before PC PCJ is installed in Jira, that would crash with a Java ClassNotFoundException, since those interfaces would not yet be available. On the other hand, we need those objects to have already been created when the export or import is running.

The SPI , and the framework that uses it in PC, PCJ are designed so that you can satisfy that lifecycle requirement following very simple guidelines, leveraging the power of the Atlassian Spring Scanner. You only need to annotate those classes to associate them with a dynamic application context. This context will be started when extensions are required by PC PCJ (when export, import, or reporting operations are being run by PCPCJ) , so that those Spring beans are instantiated only when they are needed, and PC PCJ is guaranteed to be present and working at that moment.

...

More precisely, classes implementing the following interfaces must be available as Spring beans within the context pc4j-extensions:

  • HookPointCollection

  • GlobalCustomEntity

  • ChildCustomEntity

The rest of the classes in the extension may be Spring beans or not.

...

As this is a development within the context of a P2 Jira app, it is assumed that the extension app is using Spring and Atlassian Spring Scanner version 2.

How to inject

...

PCJ dependencies into your extension

The PC PCJ extension will need to get an instance of the factory interfaces mentioned above. The implementations of these factories are available as Spring components. The usual methods of injecting a dependency in a component in Spring are sufficient. For example:

...