Global Search in Jira Studio

Jira Studio is our latest hosted offering, which combines Jira, Confluence, Fisheye, Crucible and SVN via a number of plugins to provide a seamless development environment to the end user. Search is an area where the integration between products has been lacking so far. Each application provides powerful search mechanisms, however there was no global mechanism to search all applications.
Implementing global search in Studio proved to be one of the more interesting features I’ve worked on so far. The requirements were:

Quick search (from navbar) results in global search by default

User can select specific application search from the quicksearch drop-down

selecting a specific application takes you to that application’s search (with results)

Studio search results: current app takes top position and returns the most results

Ie, if you search from Jira, Issues is on top, if you search from Confluence, Wiki is on top

Current app returns 5 results

All other apps return 3

Clicking on “More Results’ takes you to that application’s search screen (eg. Issues ‘More Results’ takes you to Jira search with same criteria)

After doing a technical spec I estimated this piece of work would take 81 hours.

Design

A search needs to be executed using the currently logged in user’s privileges in each application to ensure only results that a user is permitted to see are returned.
Searching via RPC was somewhat problematic because there’s no support for trusted application calls yet, so we would have had to add this ourselves to the RPC interface in Jira, Confluence and Fisheye (actually I never got as far as investigating Fisheye so I’m not sure if this is true). The only other options would have been to make authenticated calls to the RPC interface using the existing token mechanism (which would have required using a user’s existing login credentials).
Sage was even worse because it would have had the same trusted application problem as RPC, plus it would have required us to run yet another application with Studio. We really did not want this option.
Finally the third option was chosen: Adding a simple search API in SAL which was then implemented for Jira, Confluence, Fisheye and Crucible.

Implementing the SAL search API

After discussing a few options we chose to implement a very simple API, that would work for us now, rather than trying to come up with an API that would allow for all sorts of app-specific searches in some uber generic way. In the end each application’s SAL layer needs to implement this SearchProvider (comments stripped for conciseness):

SearchQuery can in fact contain additional parameters by appending them to the original query e.g.: searchString&maxHits=20. Perhaps a little too simple but it serves our purposes for now. The search will return a SearchResults object, which may contain errors, a list of matches, total time taken for the query, as well as the total number of hits available for a particular query.
A SearchMatch is defined as:

public interface SearchMatch
{
/**
* Absolute URL to reach this search match.
* @return Absolute URL to reach this search match.
*/
String getUrl();
/**
* Title of the search match
* @return Title of the search match
*/
String getTitle();
/**
* An excerpt of the search match. For example this could be a summary of the Wiki page.
* @return excerpt of the search match. May be null.
*/
String getExcerpt();
/**
* Contains more information about the source of this match.
* @return The source resourceType.
*/
ResourceType getResourceType();
}

Implementing these search providers was an interesting excercise in exploring each applications internal Search APIs (or lack thereof). From most difficult to least difficult to implement:

Confluence was by far the nicest and easiest to implement (and this is coming from a Jira developer!). We have a lot of work to do though in general to make our internal APIs more developer friendly!!

Search Aggregation

Now that SAL supports search I had to implement search aggregation to actually get some results to the user. For this I built a simple search webwork plugin in Jira, that would call a SearchAggregator in the applinks layer. This SearchAggregator would call to the local SearchProvider directly (which is available via dependency injection) and call to all remote apps registered in applinks via a RemoteSearchProvider implementation. The RemoteSearchProvider simply makes a REST call to a Search Servlet I added. This gives us trusted apps for free, since we already have all sorts of utilities in Studio to make trusted app calls to REST services.
The SearchAggregator aggregates results in parallel using a threadpool, which means the overall result will be returned as soon as the slowest resources returns. Threadlocal’s proved to be a bit of a problem when it came to detecting the currently logged in user, which is why the SearchProvider interface above requires a username to be specified.

The User Interface

As usual the user interface is what took the longest. The actual search results page was quite quick and easy since our UI team already provided a HTML mockup including CSS (you rock!). The majority of time was spent with the quicksearch dropdown, allowing users to select which application to search in:
Implementing this dropdown in one application was easy, but implementing it in Jira, Confluence and Fisheye for all the browsers we support took a LONG TIME!

Results

Here’s the results screen of running a search in Studio (scaled down slightly from original size):
Search will be rolled out to users with the next release of Studio. Before this can happen there are still a couple of things we need to cover however. There’ll be a blitz test to ensure there are no XSS attacks or other weird encoding issues with studio search. We’ll also have to focus on any UI quirks in the different apps in different browsers with the quicksearch dropdown. I’ll also be doing a load test on a real instance to ensure search isn’t too slow.
According to JST-636 I spent 84.5h on development, plus there’s still quite some work outstanding for the load and blitz tests. I went quite a bit over the original estimate due to the difficulties encountered implementing the quicksearch dropdown in the various apps and browsers. The lesson is: Don’t forget to add LOTS of padding for any non-trivial UI tasks in Studio!