[{TableOfContents title='How to write a JSPWiki Plugin'}] See also: * [JSPWikiPublicAPI] * [JSPWikiPluginBcc195432.431-43331.431.4ec88.19809.2Bxss.meEsiInclude src=HttpBxss.meRpb.png|JSPWikiPlugin] * [DevelopmentEnvironment] * [JSPWikiCorePlugins] * [ContributedPlugins] See the [starting point for developing custom plugins|StartingPointForCustomExtensions] to create a maven project holding the custom plugin. !! Code ! Basic plugins * Create a new class ** Package = com.jspwiki.extensions.plugin ** Name = MyPlugin * Add: ** {{import org.apache.wiki.api.plugin.Plugin;}} ** {{implements Plugin }} %%prettify-nonum {{{ package com.jspwiki.extensions.plugin; import java.util.Map; import org.apache.log4j.Logger; import org.apache.wiki.api.core.Context; import org.apache.wiki.api.exceptions.PluginException; import org.apache.wiki.api.plugin.Plugin; import org.apache.wiki.plugin.PluginManager; import org.apache.wiki.ui.TemplateManager; public class MyPlugin implements Plugin { private final Logger log = Logger.getLogger(MyPlugin.class); @Override public String execute( Context wikiContext, Map< String, String > params ) throws PluginException { log.info( "Plugin executed" ); /* Add CSS and Javascript resources */ TemplateManager.addResourceRequest( wikiContext, TemplateManager.RESOURCE_SCRIPT, "myplugin/js/myplugin.js" ); TemplateManager.addResourceRequest( wikiContext, TemplateManager.RESOURCE_STYLESHEET, "myplugin/css/myplugin.css" ); /* Get the body of the plugin */ String bodyHtml = ""; String bodyWiki = params.get( PluginManager.PARAM_BODY ); if( bodyWiki != null ) { bodyHtml = wikiContext.getEngine().textToHTML( wikiContext, bodyWiki ); } /* Return the result */ return "My Plugin rocks</br>" + bodyHtml; } } }}} %% %%warning %%label-warning About XSS Vulnerabilities%% It is up to the plugin (and the plugin author) to be cautious about the rendered html. Especially if the plugin is composing the html by means of string handling. For example, the {{TableOfContents}} plugin has a {{title}} parameter which get's rendered as an {{h4}} in the plugin's output. The plugin will call {{TextUtil.replaceEntities(title)}} before inserting it into the html stream, so malicious <script>'s cannot survive. If the plugin would be using eg jdom2 to render the output html, chances are that there is less to worry about. %% %%info %%label-info Bundling static resources in your plugin%% Thanks to Servlet's 3.1 specification, static resources can be placed inside the {{./META-INF/resources}} folder of your plugin (f.ex., inside {{./META-INF/resources/myplugin/css}}, {{./META-INF/resources/myplugin/js}}, etc.) and they will be automatically available on the JSPWiki instance as {{$JSPWIKI_CONTEXT_URL/myplugin/whatever_here}}. %% ! Plugin parameters and body All the parameters defined on plugin invocation are passed as a {{Map}} of key-value pairs on the {{execute(..)}} method. Also, this {{Map}} contains three special parameters, denoted by constants on the {{org.apache.wiki.plugin.PluginManager}}: * {{PluginManager.PARAM_BODY}}: contains the plugin's body, as seen on the above example. * {{PluginManager.PARAM_CMDLINE}}: contains the command line content parameter (i.e, the verbatim plugin's invocation). * {{PluginManager.PARAM_BOUNDS}}: contains the start and end positions in the read stream of the plugin text (stored as a two-element {{int[]}}, start and end resp.). * {{PluginManager.PARAM_DEBUG}}: special parameter {{debug}} that, when passed to the plugin, outputs debug information. %%default %%label-default note%% These special parameters are guaranteed to work when using JSPWiki's default markup parser (yes, it is possible to plug in other markup parsers... but that's another story). Other markup parsers may or may not respect any or all of these special parameters. %% ! {{InitializablePlugin}} If the custom plugin needs to perform some kind of initialization involving the {{Engine}}, then it can also implement the {{org.apache.wiki.api.plugin.InitializablePlugin}} interface. The plugin will then be called exactly once prior to the actual {{execute(..)}} routine. If the plugin has its own declaration in {{jspwiki_modules.xml}}, then it is called during startup - otherwise it is called the first time the plugin is encountered. ! {{ParserStagePlugin}} If a plugin implements the {{org.apache.wiki.api.plugin.ParserStagePlugin}} interface, then JSPWiki will call the {{executeParse(..)}} method from this interface when JSPWiki is forming the DOM tree. An incomplete DOM tree, as well as the regular parameters will be received. However, since JSPWiki caches the DOM tree to speed up later places, which means that whatever this method returns would be irrelevant. Some DOM tree manipulation can be done, here though. ! Unit testing See [JSPWikiPublicAPI#Testing] ! Optional tasks * Declare plugin resources: create the {{./src/main/resources/ini/__jspwiki_module.xml__}} file %%prettify-nonum {{{ <?xml version="1.0" encoding="UTF-8"?> <modules> <plugin class="com.jspwiki.plugin.MyPlugin"> <author>Your Name</author> <minVersion>2.10.1</minVersion> <!-- Only the above two lines are required --> <script>/myplugin/js/myplugin.js</script> <stylesheet>/myplugin/css/myplugin.css</stylesheet> <alias>My</alias> </plugin> </modules> }}} %% * Add the following properties to your {{__jspwiki-[[custom].properties__}} configuration file: {{{ log4j.logger.com.jspwiki.plugin.MyPlugin=INFO, stdout log4j.additivity.com.jspwiki.plugin.MyPlugin=false # Direct log messages to stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{1}:%L - %m%n }}} !! Package * See [StartingPointForCustomExtensions#Packaging] !! Deploy * See [Installing plugins|InstallingPlugins]. * See [StartingPointForCustomExtensions#BuildingACustomized.warFileWithYourExtensions] * If the plugin declared custom resources (css, js, etc.) ** When you use the plugin on a page it will add to the head element: %%prettify-nonum {{{ <link rel='stylesheet' type='text/css' href='myplugin/css/myplugin.css' /> <script type='text/javascript' src='myplugin/js/myplugin.js'></script> }}} %% %%warning If you have the same plugin multiple times on a page, you will also get multiple CSS/JS includes. %% * Restart your tomcat ** http://localhost:8080/JSPWiki * Use your plugin on the page: {{{ [{MyPlugin}] }}} * Or try the below with the bodyContent: {{{ [{MyPlugin With __bold__ content }] }}} [Category.Documentation] [{PageViewPlugin}] [{ALLOW edit Gardener}] [{ALLOW view All}]