HTTPS SSH

XNAT Module to Plugin Conversion Script

This repository contains a Groovy script that can be used to convert modules used in XNAT 1.6 to plugins that can be used in XNAT 1.7. Starting with XNAT 1.7, modules are no longer supported and support for plugins has been added. If you are upgrading to 1.7 and have custom code in 1.6 modules that you wish to keep, this code should be put in 1.7 plugins.

What the script does

Re-organize your files

The first thing the script does is re-organize the structure of the files and folders in your module. The structure of files in 1.7 plugins is different than in 1.6 modules, so things must be organized a little differently. Here is a list of the directories you might have in your module and where those files will end up in your plugin:

  • src/java -> src/main/java
  • src/schemas -> src/main/resources/schemas
  • src/templates -> src/main/resources/META-INF/resources/templates
  • src/xnat-templates -> src/main/resources/META-INF/resources/xnat-templates
  • src/xdat-templates -> src/main/resources/META-INF/resources/xdat-templates
  • src/scripts -> src/main/resources/META-INF/resources/scripts
  • src/style -> src/main/resources/META-INF/resources/style
  • src/images -> src/main/resources/META-INF/resources/images
  • repository -> src/main/repository

In addition to looking for files in directories under src, the script will also look in directories under src/main and src/main/resources/module-resources.

Inspect your code for likely problems

The next thing the script does is look through the Java code itself, looking for bits of XNAT code that you may be using and that we know have changed. Some XNAT classes and methods changed from 1.6 to 1.7. If the script detects that some of your Java classes are trying to use code that will likely no longer work in 1.7, the script will warn you and provide instructions for how you can change your code so it will work in 1.7. The script will not edit your source code during this stage, just tell you where the problems are likely to be.

We have tried to anticipate XNAT changes that may affect your modules and add warnings for them, but we can't possibly cover every change that was made to XNAT code that you may be using. The warnings produced by the script are not comprehensive; this means that just because there aren't any warnings is no guarantee that all of your Java code will work with 1.7. If you encounter any issues getting Java classes working in 1.7, please contact us. We will help you figure out why your code is not working and may add more warnings to the conversion script to help other people avoid the issue you ran into.

Create a gradle build script

By default, XNAT 1.7 plugins are built using the Gradle build tool. The script creates a gradlew gradle wrapper script and a build.gradle file pre-loaded with the most essential dependencies. If you run the script with the -b flag set, then a longer list of common dependencies will be included. Your plugin will likely only need a subset of the commonly used dependencies, so you may wish to use a tool like Gradle Lint to remove dependencies you do not use. If your module is built with an existing build tool like maven or gradle, your build files will not be copied over, so you should update the build.gradle file manually to make sure that any of these dependencies that you still need are included.

If you are new to using gradle as a build tool, you may find their documentation helpful. For instance, see their guide on using an existing gradle build and migrating from maven.

Running the Conversion Script

Clone the repo

You should first make sure you have both Git and Groovy installed and can access them from the command line. You should then use Git to clone this repository:

git clone https://bitbucket.org/xnatdev/module_to_plugin

Edit values or set arguments

In order to properly run, you need to provide the script with certain values. These can either be provided by command line arguments when executing the script, or by navigating to the module_to_plugin directory that was created when you cloned the repo, using your text editor of choice to open moduleToPlugin.groovy, and changing the values of these fields from "" at the top of the file, to whatever values you want.

If you want to set these via command line arguments, here is the syntax:

  • -m,--modulePath \<arg> - Change this to the absolute path to your module's directory. The module_to_plugin script will look for your module's code in a src directory inside the modulePathString directory. (Note that, on Windows, you will need to "escape" the backslashes in the path by doing double backslashes. For example: C:\\Users\\Me\\Modules\\module_name.)
  • -p,--pluginPath \<arg> - The path where your new plugin will be created. (See the above note about escaping backslashes on Windows paths.)
  • -n,--name \<arg> - The name of your plugin as it appears in XNAT.
  • -c,--class \<arg> - This will be the name of a Java class that the script will create for you. It will signal to XNAT that the contents of your jar are an XNAT plugin. You should follow the standard conventions for Java class names.
  • -d,--description \<arg> - A human-friendly description of your plugin. This will be shown to XNAT users who want more information about your plugin. It should be short, at most a sentence or two.
  • -b,--buildDependencies - Include extra build dependencies that your plugin may or may not use.

Execute the script

To execute the script, you must navigate on the command line to the module_to_plugin directory and execute:

groovy moduleToPlugin.groovy

If you wish to set the fields using command line arguments, your script execution will look more like:

groovy moduleToPlugin.groovy -m /path/to/my_module -p /path/to/my_new_plugin -n "The Best Plugin" -c "BestPlugin" -d "This is the best plugin."

Check the results

After running the script, you should see files in the directory you set as the pluginPathString. This will contain unchanged versions of files from your module as well as a new Java class to configure your plugin located at src/main/java/org/nrg/xnat/plugin/${pluginClassName}.java.

If you have files in your module that are not in one of the locations detailed above, you will have to copy them into your plugin manually. For example, if you have a README file at the top level of your module directory, you may want to copy that file to the top level of your plugin directory (though you may need to update any instructions in it to reflect that it is now a plugin and needs to be built and deployed differently).

If your module had any dependencies that are not included in the build.gradle file that the script created for you, you will need to add the dependencies yourself.

Additions to your plugin class

Many plugins will work fine at this stage, after being converted and cleaned up. But some plugins will require additional annotations to the plugin class before they will function properly. If your plugin meets any of these criteria, you will need to do one or two additional steps:

  • Your module has custom data types in xsd files, or
  • Your module uses Spring Component-based classes like Service, Repository, or Entity.

If your module meets any of those criteria, you will need to add configuration annotations to your plugin class. This class is in a ${pluginClassName}.java file that was created for you by the script. It is created at src/main/java/org/nrg/xnat/generated/plugin, though you can change this path to something else (as long as you also update the package statement at the top of the Java file to reflect the new location). We have a page on our wiki with more information about configuring your plugin using this class: XNAT Plugin Configurations.

Building and Deploying your Plugin

Once you have all that set up, you should be ready to build your plugin. Navigate your command line to the directory where the plugin was created, which you specified as pluginPathString. If you are on linux or mac, execute

./gradlew jar

Or, if you are on Windows, execute

gradlew jar

Running this command will create a new plugin jar at ${pluginPathString}/build/libs. You must now copy or move the plugin jar to your XNAT's plugins directory at ${XNAT_HOME}/plugins on your XNAT server. Restart tomcat, and your XNAT will see the plugin when starting up.

Troubleshooting

Make sure your code is updated

If you encounter any issues when building or deploying your plugin, your code may be trying to use XNAT methods or variables in ways that worked in 1.6, but that no longer work in 1.7. You should look through the warnings you got when running the conversion script and make sure you updated your code appropriately.

Including dependencies in your build

Your code may be trying to use a dependency that is not listed as a dependency in your build.gradle file. If you know that your code needs to reference something that is not listed under dependencies in build.gradle, you should add it. You may also need to add it to the dependencies list under buildscript if you are unable to even build without it. If the script is executed with the -b flag set, the version of build.gradle that this script copies into your plugin directory contains dependencies that many plugins will find useful, but you may not need all of them or may have other dependencies you need to add.

Including dependencies in your jar

Your plugin may build perfectly fine, but when you install it into XNAT it may prevent the system from starting. Or perhaps the system starts, but whenever you attempt to run your code it does not work. A possible cause for this is that your code needs some dependency that was present when you built, but is not present when the code is running within XNAT. If your code needs some dependency, and you know that XNAT does not include this dependency, then you will need to provide that dependency with your plugin. The easiest way to do that is to just copy the dependency's jar into the ${XNAT_HOME}/plugins directory alongside your plugin jar. For simple cases, this will work just fine and be totally sufficient.

However, that does not solve all cases. What if that dependency needs some other dependency? Then you'll have to track down multiple jars, and keep all of them together. And what if you want to distribute your plugin? It would be too much of a hassle to tell people how and where to get all the different dependency jars that your plugin needs. To solve those problems you can build a "fat jar", which is a jar that contains your code and all the dependencies it needs.

There are instructions for building a fat jar on the wiki page for creating an XNAT plugin.

Contact Us

We want to make the process of upgrading to XNAT 1.7 as easy as possible, so please contact us through the XNAT discussion group and let us know what your experience was like. We would be happy to help you work through any issues you have getting your module converted or getting the resulting plugin to work. And we want to know if you run into any issues updating your code to work with the 1.7 XNAT code, or if the script is not copying over files you think it should be copying over. We will provide you whatever help we can and update the script and this README to help others avoid any issues you ran into.