1. Atlassian
  2. Project: Atlassian
  3. atlassian-pretty-urls



Atlassian Pretty URLs


Atlassian Pretty URLs allows a plugin to map from one URL to another. It allows basic rewriting of URLs at request time.

Atlassian Developer?

Committing Guidelines

Please see The Platform Rules of Engagement (go/proe) for committing to this module.


The Bamboo builds for this project are on EcoBAC.

Local development

Run tests in refapp: mvn verify

Run up the pretty-urls plugin and the reference plugin in refapp and allow attaching debugger:

mvn -DskipTests clean install mvn -pl atlassian-pretty-urls-reference-plugin/ -DskipTests -Djvm.debug.suspend=true amps:debug

Run tests with JIRA BTF:

mvn -DtestGroups=jira -Djira.version=x.y.z clean verify

Run in debugger with JIRA BTF:

mvn -DskipTests clean install mvn -pl atlassian-pretty-urls-reference-plugin/ -Dproduct=jira -Djira.version=x.y.z -DskipTests -Djvm.debug.suspend=true amps:debug

(for Confluence, BTF or Cloud, just substitute 'confluence' above)

Run tests with JIRA Cloud and Postgres-in-Docker:

docker login https://docker.atlassian.io mvn -Pjira-cloud,postgres84 -Djira.version=x.y.z clean verify

Run in debugger with JIRA Cloud and Postgres-in-Docker:

To use Docker with amps:run or amps:debug, you must set the value of docker.host.address on the commandline, due to issues with AMPS maven phases and property substitution. This may be localhost or may be in your DOCKER_HOST env variable.

docker login https://docker.atlassian.io mvn -DskipTests clean install mvn -Pjira-cloud,postgres84 -pl atlassian-pretty-urls-reference-plugin/ -Dproduct=jira -Djira.version=x.y.z -DskipTests -Djvm.debug.suspend=true -Ddocker.host.address= amps:debug

For JIRA Cloud, you need to have a running docker-machine and appropriate environment variables set up. If you see this error, that's what's wrong:

docker-maven-plugin:0.15.0:start failed: No url given, no DOCKER_HOST environment variable and no read/writable '/var/run/docker.sock'

External User?


Please raise any issues you find with this module in JIRA.


See below

Do you despise your plugin URLs?

How To Deploy It For Your Plugin

Put this in your pom.xml


You will then need to OBR bundle the pretty urls plugin along with your bundle.

   <!-- These go into the OBR -->

The Plugins system does not have full OBR support yet (eg AMPS cannot deploy your OBR into its started JIRA via copying it to installed-plugins directory) so you need to manual put the extra plugin in play via AMPS pluginArtifact copying


How To Make URLs Pretty

Simple Routing

The Atlassian Pretty URLs plugin allows you to facade any old style URL into one of your choosing. You do this by adding <route> elements to your atlassian-plugin.xml

<routing key="prettyurls-key" path="/prettyurls">
    <route from="/are/{verb}" to="/secure/HorribleName.jspa"/>
    <route from="/can/{verb}" to="/secure/HorribleName.jspa"/>

The first entry above will map

http://localhost:2990/jira/prettyurls/are/cool ==> http://localhost:2990/jira/secure/HorribleName.jspa?verb=cool

URL Template Parameters

It uses jax-rs syntax to take URL path parameters and make them available to the destination as either further jax-rs variables or more commonly as query parameters. Any left over parameters that are not remapped into the destination URL are passed as query parameters. For example :

http://localhost:2990/jira/prettyurls/are/cool?leftover=parameters&are=passedon ==> http://localhost:2990/jira/secure/HorribleName.jspa?verb=cool&leftover=parameters&are=passedon

You can use the template variables within the destination URL and hence allow more dynamic routing. For example given

<routing key="prettyurls-key" path="/prettyurls">
    <route from="/hello{world}/{id}" to="/plugins/servlet/hello{world}?idParameter={id}"/>

you could end up mapping to URL dynamically to differently named servlets as shown below.

http://localhost:2990/jira/prettyurls/helloCleveland/key123 ==> http://localhost:2990/jira/plugins/servlet/helloCleveland?idParameter=key123

http://localhost:2990/jira/prettyurls/helloSydney/key456 ==> http://localhost:2990/jira/plugins/servlet/helloSydney?idParameter=key123

You can find further examples of what is possible with URL Templates by reading the Oracle documentation.

HTTP Verbs

You can limit the HTTP verbs upon which routing will take place via the verbs attribute. For example :

<routing key="prettyurls-key" path="/prettyurls">
    <route from="/http/get" to="/secure/HorribleName.jspa" verbs="get"/>
    <route from="/http/post" to="/secure/HorribleName.jspa" verbs="post"/>
    <route from="/http/post_put_or_delete" to="/secure/HorribleName.jspa" verbs="post,put,delete"/>

There is also syntactic sugar for the well known HTTP verbs get, put, post, head, delete, options and patch.

<routing key="prettyurls-key" path="/prettyurls">
    <get from="/http/sugar/get" to="/secure/HorribleName.jspa"/>
    <post from="/http/sugar/post" to="/secure/HorribleName.jspa"/>

Filter Chain Location

You can control when the routing happens via the location attribute. The valid values are before-decoration, before-login and before-dispatch. The most useful location is before-dispatch.

<routing key="prettyurls-ref-rest-after-encoding" path="/prettyjson" location="before-dispatch">
    <route from="/" to="/rest/prettyjson/1.0/json"/>

<routing key="prettyurls-ref-before-login" path="/before/login" location="before-login">
    <route from="/are/{verb}" to="/secure/PrettyActionUrlsActionHorribleName.jspa"/>

<routing key="prettyurls-ref-before-decoration" path="/before/decoration" location="before-decoration">
    <route from="/get/allowed" to="/secure/PrettyActionUrlsActionHorribleName.jspa" verbs="get"/>
    <route from="/get/post/allowed" to="/secure/PrettyActionUrlsActionHorribleName.jspa" verbs="get,post"/>

Multiple Top Level Routing Matching via JAX-RS

Its possible that two or more consumer plugins can compete for the same top level path

<routing key="x" path="/prettyurl"">
    <route from="/some/path" to="/secure/SomePath.jspa"/>
    <route from="/some/other/path/{with}/{variable}" to="/secure/SomeOtherPath.jspa"/>

<routing key="y" path="/prettyurl"">
    <route from="/some/{all : .*}" to="/secure/IWantEverything.jspa"/>

In this case we need a resolution strategy. jax-rs has a strategy for this : jax-rs Request Matching

Sort [...] using the number of literal characters in each member as the primary key (descending order), 
the number of capturing groups as a secondary key (descending order) and the number of capturing groups 
with non-default regular expressions (i.e. not ‘([^  /]+?)’) as the tertiary key (descending order).

In short the more specific and longer paths will be matched first. So when multiple routing elements are competing for the same top level path then jax-rs matching is used. In the case of a single routing elements then list order is used.

In the config give above we would see :

  • /some/path would be routed to /secure/SomePath.jspa
  • /some/other/path/including/variables would be routed to /secure/SomeOtherPath.jspa
  • /some/thing-else would be routed to IWantEverything.jspa
  • /some/thing-more would be routed to IWantEverything.jspa

Routing REST Requests

If you want to route to REST resources, then you need to tweak your <rest> module type declaration to ensure it contains the FORWARD dispatcher attribute. The reason for this is that the atlassian-pretty-urls plugin uses request forwarding as its implementation and as such the REST resources must be mapped to the FORWARD dispatcher context. The default <rest> dispatcher context is REQUEST only and hence it will never match up as expected without this configuration.

<rest key="prettyurls-ref-rest" path="/prettyjson" version="1.0">

    <!--In order to allow REST calls to be intercepted your MUST include a FORWARD call here-->

How To Make Pretty URLs Decorated

JIRA does not SiteMesh decorate all URL paths (and nor should it) so you have to tell it if you want a path decorated. You can do this via the <sitemesh> module type.

<sitemesh key="unique-key-for-module-type" path="/pluginpath"/>

This will cause all text/html responses to be SiteMesh decorated.