Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,366,371
Community Members
 
Community Events
168
Community Groups

Extend your Jira Server/Data Center app with ModuleType Part 2

Part 1

Change our app

Now we need to add support for modules to our calculator.

First uncomment the jira-core dependency in the pom.xml file.

<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-core</artifactId>
<version>${jira.version}</version>
<scope>provided</scope>
</dependency>

Then add com.atlassian.plugin.osgi.bridge.external to Import-Package in the pom.xml file

<Import-Package>org.springframework.osgi.*;resolution:="optional", com.atlassian.plugin.osgi.bridge.external, org.eclipse.gemini.blueprint.*;resolution:="optional", *</Import-Package>

Next add our module descriptor.

src/main/java/ru/matveev/alexey/atlassian/calculator/module/OperationModuleDescriptor.java

public class OperationModuleDescriptor extends AbstractModuleDescriptor<Operation>
{
public OperationModuleDescriptor(final @ComponentImport ModuleFactory moduleFactory)
{
super(moduleFactory);
}

@Override
public Operation getModule()
{
return moduleFactory.createModule(moduleClassName, this);
}
}

As you can see we created this module descriptor as AbstractModuleDescriptor of the Operation interface type.

Next, we need to register our module descriptor.

src/main/java/ru/matveev/alexey/atlassian/calculator/module/BasicModuleTypeFactory.java

@ModuleType(ListableModuleDescriptorFactory.class)
@Named
public class BasicModuleTypeFactory extends
SingleModuleDescriptorFactory<OperationModuleDescriptor>
{
@Autowired
public BasicModuleTypeFactory(HostContainer hostContainer)
{
super(hostContainer, "calculatorOperation", OperationModuleDescriptor.class);
}
}

As you can see We registered our module descriptor under the calculatorOperation name.

Done.

Now apps can define calculatorOperation in their atlassian-plugin.xml file.

But let's also change our CalculatorService.

When we need to look for operations in modules of external apps.

I changed src/main/java/ru/matveev/alexey/atlassian/calculator/service/CalculatorService.java to this one:

@Named
public class CalculatorService {
private final SumOperation sumOperation;
private final PluginAccessor pluginAccessor;
public CalculatorService(final @ComponentImport PluginAccessor pluginAccessor, SumOperation sumOperation) {
this.sumOperation = sumOperation;
this.pluginAccessor = pluginAccessor;
}

public int calculate(String operation, int val1, int val2) throws OperationNotFoundException {
if (operation.equals(sumOperation.getName())) {
return sumOperation.calculate(val1, val2);
}
Operation operationModule = this.getModuleForOperationName(operation);
if (operationModule != null) {
return operationModule.calculate(val1, val2);
}
throw new OperationNotFoundException(String.format("Operation %s not found", operation));
}

private Operation getModuleForOperationName(String operationName) {
List<OperationModuleDescriptor> operationModuleDescriptors =
pluginAccessor.getEnabledModuleDescriptorsByClass(OperationModuleDescriptor.class);
for (OperationModuleDescriptor operationModuleDescriptor : operationModuleDescriptors)
{
if (operationName.equals(operationModuleDescriptor.getModule().getName())) {
return operationModuleDescriptor.getModule();
}
}
return null;
}
}

I added getModuleForOperationName which returns a reference to a module in an external app if the operation name we want to execute equals to the name of the operation provided by this module.

And then I added these lines to the calculate method:

Operation operationModule = this.getModuleForOperationName(operation);
if (operationModule != null) {
return operationModule.calculate(val1, val2);
}

First, we look for a module in another app which provides implementation of the operation we need and then we run the calculate method on the found module.

That is all with the calculator app. Now let's write an extension to our app.

Calculator-extension

I created an ordinary plugin from Atlassian SDK.

I added dependency to the jar file of the calculator app. I need it to use the Operation interface defined in the calculator app.

<dependency>
<groupId>ru.matveev.alexey.atlassian</groupId>
<artifactId>calculator</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${project.basedir}/../calculator/target/calculator-1.0.0-SNAPSHOT.jar</systemPath>
</dependency>

Then I created the minus operation.

src/main/java/ru/matveev/alexey/atlassian/operation/MinusOperation.java

public class MinusOperation implements Operation {
@Override
public String getName() {
return "minus";
}

@Override
public int calculate(int val1, int val2) {
return val1 - val2;
}
}

As you can see I implemented this class from the Operation interface and defined two methods: getName (returns the "minus" value) and calculate.

And now I can add calculatorOperation module to the atlassian-plugin.xml file.

src/main/resources/atlassian-plugin.xml

 <calculatorOperation key="minus-operation"  class="ru.matveev.alexey.atlassian.operation.MinusOperation"/>

And that is it. Install this app to the same Jira instance where the Calculator app is installed.

Test extension app

I installed our two apps to the same Jira instance.

Screenshot 2020-09-06 at 21.07.34.png

And now I will execute our http://localhost:2990/jira/rest/calculator/1.0/calculate REST endpoint with the following request body:

{"operation": "minus", "value1": 1, "value2" : 3}

As you can see I am trying to use the minus operation from our calculator-extension app. And here is the result:

Screenshot 2020-09-06 at 20.56.35.png

And the result is -2 as expected. We did what we wanted. We added a new operation in an external app for our calculator app. Now other apps can extend our calculator with their own operations.

You can find the final code here.

0 comments

Comment

Log in or Sign up to comment
TAGS

Atlassian Community Events