One of our favourite times at Atlassian as developers is ShipIt. 24 hours to hack up some awesome project, demo it to the rest of the company, and vote on whose is best. 24 hours isn’t a lot of time, which is why I’ve emphasised the hack part of that statement. The demo is held together loosely by strings of hard coded configuration, and carefully dodges crucial but yet to be implemented features.

An example of something that never gets implemented is a configuration screen for entering the details of how to connect to a remote service, for example, the base URL, authentication details and other integration configuration. Why? Because that stuff is boring! It’s tedious to write, it’s orthogonal to the actual functionality you want to implement, and it’s been done over and over before. A configuration screen doesn’t demo well, so in a demo, you never show it. And because you don’t show it, there’s no point in implementing it. Implementing the mechanism for configuring integrations is a hassle.

And it’s not just ShipIt where this is the case, in every integration plugin that I’ve written for Atlassian products, the configuration screen is the last thing I always implement. When I wrote the Atlassian Notifier, a webhooks plugin for our products, I didn’t even bother implementing a configuration screen, it’s all configured using REST.

Unified AppLinks

———————
Unified AppLinks is Atlassians solution to the problem. Introduced in FishEye 2.5, Confluence 3.5 and JIRA 4.3, AppLinks is a single point to configure all integrations from Atlassian products to other services. If you install these versions of the products today, you’ll find configuration wizards to easily walk you through connecting any one of the products in the Atlassian suite to any other product in the Atlassian suite, with authentication between them configured with the click of a button.

Before you close your browser tab thinking that this is just something for making Atlassian products talk to each other, stop, I’m not writing this to show you how to make Atlassian products talk to each other, we have plenty of documentation for that already. The point of this series of blog posts is to show you how you can easily write plugins for Atlassian products that integrate with non Atlassian products and services using AppLinks. So read on!

If you’re not familiar with using AppLinks yet, then I would encourage you to download the latest versions of our products and use AppLinks to link them together. The documentation is also full of lots of pretty screenshots of what it looks like. I don’t want to repeat any of that here, so I’m going to assume that you already have a basic understanding of how to use AppLinks to configure links to other applications.

Consuming AppLinks

—————————
What I hope to sell to you in this series of blog posts is the extendibility of AppLinks, so that you will write your own application types to extend AppLinks when you implement integration plugins. But there is no point in me showing you how to extend AppLinks if you don’t see how easy it is to consume the extensions you’ve implemented. So the remainder of this blog post is going to be about how as a plugin developer you can consume AppLinks that a user has configured.

Our example service that we are going to integrate to is going to be Twitter. I’ve chosen Twitter because most people understand it already, I don’t need to explain what it means to tweet, the concept of micro blogging, hash tags, or twitter feeds. So, in this blog post we’re going to assume that I’ve already implemented a plugin for AppLinks that provides Twitter integration, and in subsequent blog posts in this series I’m going to show how to implement that Twitter integration.

Making authenticated calls to Twitter

———————————————-
The most basic part of any integration plugin is making authenticated calls to that service. So let’s see how we do that using AppLinks. The first thing I need to do is get a hold of an ApplicationLinkService. This service provides methods to look up user configured AppLinks. It is provided as an OSGi service by the AppLinks plugin, and hence to use it in my plugin, I’m going to have to import it in my plugins `atlassian-plugin.xml` descriptor:

When looking up an AppLink to a particular service, I have two options. I can use `getApplicationLinks()`, or I can use `getPrimaryApplicationLink()`. AppLinks allows many to many associations between Atlassian products and other services, but it also has a concept of primary links, when you just want the default one that the user configured. In our case, since there is only one Twitter, we’re going to use `getPrimaryApplicationLink()`.

This method accepts a class as an argument, one that extends ApplicationType. An ApplicationType represents a type of service or application, for example, JIRA, Confluence, Bamboo, Twitter, etc. Each of these has a class associated with them, such as JiraApplicationType. In my Twitter AppLinks extension that I’ve already written, I’ve implemented a TwitterApplicationType, and so this is the class that I’m going to pass in here.

Having called this method, it will return me an ApplicationLink, or `null` if none has been configured. The application link has a number of methods for looking up information about it. Important methods include `getDisplayUrl()`, which can be used when I want to render a link to the application to the user, and `getRpcUrl()`, which is often the same as `getDisplayUrl()`, but may be different, for example, if two colocated services are exposed to the internet using HTTPS, but can access each other directly using HTTP, then an administrator might configure a different RPC URL for greater performance. In the case of Twitter, there is only one Twitter instance, so I’m not really interested in either of these methods. The method that I’m most interested in is `createAuthenticatedRequestFactory()`.

`createAuthenticatedRequestFactory()` will give me a factory that can be used to create requests to Twitter. These requests will transparently be authenticated, regardless of whether the user has configured AppLinks to use OAuth or HTTP Basic authentication, as a plugin consumer of the AppLink, I don’t need to worry about that, all I need to know is that the requests that I make using this factory will be authenticated when they’re made on Twitter.

The ApplicationLinkRequestFactory returned by this method can be used to create ApplicationLinkRequests, which extend the SAL Request interface. This interface is similar to what you may have used if you’ve used Apache commons httpclient or similar HTTP libraries, it allows setting of headers, message bodies, executing the request, passing in handlers to handle the response, etc.

Putting all this together, I can use the following code to update the current users Twitter status:
ApplicationLink appLink = applicationLinkService.getPrimaryApplicationLink(
TwitterApplicationType.class);
ApplicationLinkRequestFactory factory = appLink.createAuthenticatedRequestFactory();
factory.createRequest(Request.Method.POST,
“http://api.twitter.com/1/statuses/update.json?status=Test%20Tweet”)
.execute();

The above code will update the users Twitter status, no need to worry about signing the request with OAuth or adding HTTP Basic Authorization headers, that’s handled for me by AppLinks.

Handling User Credential Negotiation

———————————————–
There is an important exception that hasn’t been handled in the above code. If you’re familiar with OAuth, you’ll be aware that the first time a particular user interacts with the remote service, they need to do the “OAuth dance”, which is a process by which they are redirected to the providing service, they log in, grant access to the consuming service, and then are redirected back. After that process is complete, the consuming service is in possession of a token that it is able to use for every subsequent request. If AppLinks doesn’t have that token, the call to `createRequest()` will throw a CredentialsRequiredException. This is easily handled when working with AppLinks, using the following code:

try {
factory.createRequest(…);

} catch (CredentialsRequiredException e) {
response.sendRedirect(factory.getAuthorisationURI(
URI.create(“path/back/to/me”)).toString());
}

Sending a redirect is one example of what you might do, you might also decide to render a link on the page you are serving to this authorisation URI. When the user clicks it, they will be taken through the OAuth dance process, and redirected back to the page you specified.

Linking Remote Entities to Local Entities

—————————————————
What if I want to write a Confluence plugin that automatically tweets blog posts by a user with a per space configured hash tag? So for example, if I have a space called BAMB and another called JIRA, I might want tweets for blog posts in the BAMB space to have a hash tag of #Bamboo, and tweets for the JIRA space to have a hash tag of #JIRA. Although this is a rather trivial example, it is quite common when integrating Atlassian products to other services that you want to link entities, eg a Confluence space, a JIRA project, a FishEye repository, to entities on the remote side, which in our example are Twitter hash tags. AppLinks provides the functionality to do this using entity links, which you can read about in the documentation.

In order to consume entity link configuration by the user, we can use the EntityLinkService. Like the ApplicationLinkService, EntityLinkService has methods for getting primary entity links as well as all entity links configured, and accepts a class that extends EntityType when looking up entity links of a specific type. In addition, EntityLinkService methods also accept a local entity object. This would usually be a Confluence space, JIRA project or other corresponding entities depending on which product you are working with.

In my Twitter AppLinks extension, I have implemented a TwitterHashTagEntityType class to look up hash tags linked to local entities. So, if I wanted to look up the hash tag for a Confluence space, I would use the following code:

EntityLink entityLink = entityLinkService.getPrimaryEntityLink(space,
TwitterHashTagEntityType.class);

The returned EntityLink object gives me access to the hash tag using the `getKey()` method, as well as the application link associated with this entity link, using `getApplicationLink()`. I can use the ApplicationLink as before to make authenticated requests against Twitter.

A final point of interest for EntityLink is the `getDisplayUrl()` method. This gives me a URL that I can render to users that represents a link to that remote entity, for Twitter, this is a link to the hash tag. I have implemented this in my Twitter AppLinks extension as a link to the Twitter search for the hash tag, so the display url is `http://twitter.com/#!search?q=%23hashtag`.

What’s next?

—————-
Having shown how a plugin might consume user configured AppLinks, in Part 2 I will show how custom application types and entity types can be implemented. Source code examples for this blog post can be found on Bitbucket.

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now