Automatic plugin reinstallation with QuickReload

What is QuickReload?

QuickReload is an Atlassian plugin that significantly reduces plugin development iteration time.

It works by watching output directories for P2 .jar files to be created, then uploads them into the running Atlassian application (for example Jira or Confluence).

It aims to provide the smallest possible time between a bit of code being changed and it being loaded into the host application.

Using QuickReload

In the pom.xml for your plugin, ensure the following within the <configuration> tag:

1
2
<build>
    <plugins>
        <plugin>
            <groupId>com.atlassian.maven.plugins</groupId>
            <artifactId>jira-maven-plugin</artifactId>
            <version>${amps.version}</version>
            <extensions>true</extensions>
            <configuration>
                ...
                <enableQuickReload>true</enableQuickReload>
                ...
            </configuration>

Once you've updated your pom as shown above, you can start the product.

Whenever you make a change to your plugin, all you need to do is rebuild your .jar file using one of the following commands in a separate terminal window, and QuickReload will redeploy it to the product.

1
2
$ atlas-mvn package

or

1
2
$ mvn package

How it works

The idea behind QuickReload is quite simple. It uses a file watching library called atlassian-watch-service, which is a simple wrapper for the Java 7+ file watch APIs.

The service watches to see whether a jar has changed; if a change is detected, it examines it to see if it's an Atlassian plugin, and if it is, it calls on the plugin system to install the updated jar.

Because the file watching service raises an event to say there was a change when the jar is first created (but not yet populated with files), the QuickReload code waits a short time for the jar to be fully formed. However, the wait time is only about 10-100ms, which is barely noticeable to the user.

The plugin system doesn't care where plugin files are installed from. It can be <home>/plugins/installed-plugins or any other directory. So QuickReload uses your project's /target directory as the place from which to install the plugin.

There's no copying and no HTTP requests, making it nice and speedy!

QuickReload advanced configuration

The pom.xml convention

By default, you should not have to configure anything for QuickReload to work, because it uses a pom.xml strategy on what directories to watch for changes.

  • QR starts from the current running directory
  • QR then ascends the directory tree until it finds a pom.xml that has no parent POM
  • QR then descends from there to find all pom.xml files, and tracks their associated target directories for changed .jar files

This will allow QuickReload to watch many plugins in a multi-module Maven project.

The quickreload.properties convention

You can drop a quickreload.properties file into the project to tell QuickReload explicitly what to watch in addition to the pom.xml convention described above.

  • QR ascends the directory tree until it finds a quickreload.properties file
  • QR reads its entries and adds those directories to its watchlist

The directories can be relative to the quickreload.properties file or absolute. Also, if the directory contains a pom.xml, QR watches the associated target directory for changes.

The file looks like this:

1
2
#
# Add directories to this file, one on each line, and the QuickReload will monitor them
# and automatically load them as soon as they are compiled and assembled.
#
# You can use -Dquickreload.dirs=dir1,dir2,dir3 on the JVM command line to also specify directories
# to monitor.
#
# relative path to plugin
some/path/test-plugin

# absolute path to plugin
/Users/me/src/atlassian/servicedesk/master/plugin

The quickreload.properties $HOME convention

Lastly, QuickReload will look for a $HOME/quickreload.properties file. You could put common entries in here, but in general the pom.xml convention is the most powerful and the least amount of work to configure.

Front end alternate resource directories

QuickReload also enables a front end development dev speed enabler called "Alternate Resource Directories". These cause the web plugin system to load your JavaScript, CSS, and LESS from source directories instead of from a packaged .jar plugin.

Hence, you can edit a .js file (for example), press refresh in the browser, and it changes.

It uses the pom.xml strategy to add src/main/resources directories to the plugin system alternate resource directory loading mechanism.

There is no more need to specify -Dplugin.resource.directories, as it will be done for you.

Finally, Ii you really must, you can specify the directories to track on the command line, via

1
2
-Dquickreload.tracked=dir1,dir2,dir3

... but in general, it "just works" for Maven projects.

This allows you to develop two or more plugins at the same time, with automatic jar and resource monitoring. Cool, right?

You can put properties before a line entry via a : character. Multiple properties can be specified via the ; character

1
2
prop1=123;prop2=xyz;prop3 : /some/path

The current properties are:

  • resource: marks the path as a resource entry to be placed into the -Dplugin.resource.directories system directory

Controlling web batching

The Atlassian Web Resource system can batch together files for faster loading. But this means it's harder to debug. So there is an atlassian.dev.mode system property to control that. This used to be settable only at JVM startup, but now with QuickReload running, pressing 'B' will toggle between web batching being enabled (faster) and web batching being disabled (easier to debug).

Log output

The QuickReload plugin emits some very obvious entries to the product log:

1
2
[INFO] [talledLocalContainer] 2014-05-08 18:10:14,332 http-bio-2990-exec-26 INFO anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [labs.plugins.quickreload.PluginInstaller]
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       v
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer] Starting Quick Reload - '/Users/bbaker/src/atlassian/plugins/quickreload/test-plugin/target/quickreload-test-plugin-1.3-SNAPSHOT.jar'....
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer] 2014-05-08 18:10:14,335 http-bio-2990-exec-26 INFO anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [atlassian.plugin.loaders.ScanningPluginLoader] No plugins found to be installed
[INFO] [talledLocalContainer] 2014-05-08 18:10:16,752 http-bio-2990-exec-26 INFO anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [atlassian.plugin.manager.DefaultPluginManager] Found dependent enabled plugins for uninstalled plugin 'com.atlassian.labs.plugins.quickreload.test': [].  Disabling...
[INFO] [talledLocalContainer] 2014-05-08 18:10:16,752 http-bio-2990-exec-26 INFO anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [atlassian.plugin.manager.DefaultPluginManager] Updating plugin 'com.atlassian.labs.plugins.quickreload.test' to 'com.atlassian.labs.plugins.quickreload.test'
[INFO] [talledLocalContainer] 2014-05-08 18:10:16,752 http-bio-2990-exec-26 INFO anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [atlassian.plugin.manager.DefaultPluginManager] Disabling com.atlassian.labs.plugins.quickreload.test
[INFO] [talledLocalContainer] 2014-05-08 18:10:16,757 Timer-1 WARN      [plugins.quickreload.test.Launcher]
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer] Quick Reload Test Plugin is going out of existence!!
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer] 2014-05-08 18:10:16,760 http-bio-2990-exec-26 INFO anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [atlassian.plugin.loaders.ScanningPluginLoader] Removed plugin com.atlassian.labs.plugins.quickreload.test
[INFO] [talledLocalContainer] 2014-05-08 18:10:16,777 ThreadPoolAsyncTaskExecutor::Thread 56 WARN anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [plugins.quickreload.test.Launcher]
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer] Quick Reload Test Plugin is coming into existence!!
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer] 2014-05-08 18:10:16,785 http-bio-2990-exec-26 INFO anonymous 1090x6739x1 - 0:0:0:0:0:0:0:1 /rest/quickreload/1/install [labs.plugins.quickreload.PluginInstaller]
[INFO] [talledLocalContainer]                       ^
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]                       |
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer]           A watched plugin never boils!
[INFO] [talledLocalContainer]
[INFO] [talledLocalContainer] Quick Reload Finished (2453 ms) - '/Users/bbaker/src/atlassian/plugins/quickreload/test-plugin/target/quickreload-test-plugin-1.3-SNAPSHOT.jar'

Security

QuickReload should never be used in a production environment

There isn't any, that's the point. The cost of crypto encoding the admin:admin credentials is significant in terms of the time taken to reload a plugin, so QR doesn't do that.

HTML control panel

QuickReload has a control panel at /plugins/servlet/qr showing various runtime values, for example:

1
2
http://localhost:2990/jira/plugins/servlet/qr

REST API

QuickReload has a REST API to help you be a better developer. Visit this to begin discovering it:

1
2
http://localhost:2990/jira/rest/qr/1.0/api

Currently, you can

  • See all OSGi bundles in the system

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/bundles
    
  • See a specific OSGI bundle

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/bundles/{bundleId}
    
  • See all the OSGi services in the system

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/services
    
  • See all Atlassian Plugins in the system

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/plugins
    
  • See a specific Atlassian Plugin, including its modules and internal Spring bean context

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/plugins/{pluginKey}
    
  • See the state of a current state of a plugin, or enable/disable it using POST/DELETE

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/plugin/enabled/{pluginKey}
    
  • See the state of a current state of a plugin module, or enable/disable it using POST/DELETE

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/plugin/enabled/{moduleKey}
    
  • View the last 100 events in the application

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/events
    
  • See the list of QR-tracked directories

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/tracked
    
  • See whether web batching is enabled

    1
    2
    http://localhost:2990/jira/rest/qr/1.0/batching
    

Rate this page: