XWiki Plugins: Tips & Tricks

The ever growing XWiki documentation already explains how to write very simple plugins, so I won’t duplicate any of the information there. Instead I will focus on more advanced aspects, in particular on interfacing with XWiki itself, and using some of the not-very-obvious extension points.

For illustration I will use my own, not yet released, UML Plugin. This plugin allows users to attach their UML diagrams to a page, and then display them in the page, as they would do with any image. Most of the work is done by uml2svg, which, as you can imagine, converts UML diagrams to SVG, and then by Batik which renders the SVG to a PNG which is displayed in the page. Apache Batik is included in the standard XWiki distribution, so we don’t need to worry about it.

Distributing Data Using an XWiki Application
However, uml2svg is a big XSL transformation, and the XSLT engine should load it in order to do its processing. I chose to have uml2svg.xsl as an attachment to a page in an XWiki application. Eventually XWiki applications and plugins will be merged, but now they are distinct, separate concepts. Now only plugins can contain Java code, while only applications can contain wiki data, and, as you might imagine, in many cases you will need both.

The easiest way to create an XWiki application is to create all the pages locally, and export the whole content of your local wiki to a XAR file. Then unzip this file, delete all pages that are of no interest to you, and all their entries from package.xml, and finally, archive the file back using zip.

For my UML plugin the XAR only contains one document at this time: “UmlPlugin.XslTransformation”. The package.xml file looks like this:


<?xml version="1.0" encoding="ISO-8859-1"?>

<package>
<infos>
<name>UmlApplication</name>
<description>A helper application for the UML plugin. Contains the uml2svg XSL Transformation file.</description>
<licence>LGPL</licence>
<author>XWiki.Admin</author>
<version>0.18</version>
<backupPack>true</backupPack>
</infos>
<files>
<file defaultAction="0" language="">UmlPlugin.XslTransformation</file>
</files>
</package>

The exported XslTransformation document contains the XSLT file as a binary attachment:

<?xml version="1.0" encoding="ISO-8859-1"?>

<xwikidoc>
<web>UmlPlugin</web>
<name>XslTransformation</name>
...
<attachment>
<filename>uml2svg.xsl</filename>
<filesize>375897</filesize>
<author>XWiki.Admin</author>
<date>1171806408000</date>
<version>1.1</version>
<comment></comment>
<content>... elided binary content ...</content>
</attachment>
...
<content>This page is used internally by the UML plugin. Please don't modify or delete this page directly.</content>
</xwikidoc>

If you also use an XWiki application for the data of your plugin — even if only for documentation, then remember to distribute it to your users, who will have to import the pages.

Loading Data from Resources
When writing this article I realized there is actually a better way to load my XSLT transformation, that does not involve XWiki applications. I can just bundle uml2svg.xsl with my plugin, and then load it using

getClass().getClassLoader().getResourceAsStream("uml2svg.xsl")

Both methods work, but I suppose XWiki applications are better suited for distributing the documentation of a plugin, not resources that are directly required by the plugin.

Custom Syntax with Radeox Macros
For my plugin I needed special syntax for referencing the attached UML diagrams in wiki pages. While there are probably also other ways to do this (Velocity macros or Groovy scripts), I did this using a Radeox macro. The syntax for inserting a diagram is very simple:

{uml:xmi=Diagram.xmi}

The definition of macro is given by the UmlMacro class:


package com.xpn.xwiki.plugin.uml;

public class UmlMacro extends BaseLocaleMacro
implements LocaleMacro, XWikiMacro {
...
public void execute(Writer writer, MacroParameter macroParams)
throws IllegalArgumentException, IOException
{
...
}

Finally, remember to add the macro to the Radeox configuration files. Add it to the xwiki.jar/META-INF/services/com.xpn.xwiki.render.macro.XWikiMacro file:
...
com.xpn.xwiki.plugin.uml.UmlMacro

and to xwiki.jar/radeox_markup_xwiki.properties:
...
macro.uml.name=uml

Adding New Struts Actions
Now that our macro is in place, we will have to be able to process it meaningfully. The main idea is that for images this is a two step process:

  1. The user agent asks for the page containing the uml macro. If the image is found in the cache then it’s used, otherwise one is generated by the two step process I described in the introduction. In both cases the URL of the image is added to the rendered page.
  2. The user agent receives the rendered page, containing the URL of the image, and makes a new request for the image. Since this temporary image is not stored in the database but in a temporary directory, a special Struts action is needed in order to retrieve it.

In XWiki Struts actions have to inherit XWikiAction:


package com.xpn.xwiki.plugin.uml;

public class UmlAction extends XWikiAction {
public String render(XWikiContext context) throws XWikiException {
...
}
}

New actions also have to be added to struts-config.xml:

<action path="/uml/"
type="com.xpn.xwiki.plugin.uml.UmlAction"
name="uml"
scope="request">
</action>

In order to create image URLs with the new action you can use:

context.getDoc().getAttachmentURL(imageName, "uml", context);

Privileges for Actions
Finally, you need to set the privileges required to perform the action. In this case view permissions are enough, so we add a corresponding line in XWikiRightServiceImpl.java then recompile XWiki (very ugly, I know):

public String getRight(String action) {
if (actionMap == null) {
actionMap = new HashMap();
actionMap.put("login", "login");
...
actionMap.put("uml", "view");
}
...
}

Conclusion
Creating useful XWiki plugins is not as easy as it could be, with non-documented extension points scattered all over the place. Fortunately XWiki 2.0 plans to improve this a lot, but until then these tips could come handy to novice plugin writers.

Advertisements

2 Responses to XWiki Plugins: Tips & Tricks

  1. MelvNg says:

    Very useful info! Thanks for sharing 🙂

  2. jolie post , merci pour l’info

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: