Web Panel Renderer plugin module

Available:

Atlassian Plugin Framework 2.5 and later.

Purpose of this Module Type

The Web Panel Renderer plugin module allows plugins to define custom renderer engines for web panels (web panels are bits of HTML that will be inserted into a page.)

Configuration

The root element for the Web Panel Renderer plugin module is web-panel-renderer. It allows the following attributes and child elements for configuration:

Attributes

Name*

Description

class

The class which implements com.atlassian.plugin.web.renderer.WebPanelRenderer.

This class is responsible for turning a web panel's content into proper HTML.

See the plugin framework guide to creating plugin module instances.

state

 

Indicate whether the plugin module should be disabled by default (value='disabled') or enabled by default (value='enabled').

Default: enabled.

i18n-name-key

The localisation key for the human-readable name of the plugin module.

key

The unique identifier of the plugin module. You refer to this key to use the resource from other contexts in your plugin, such as from the plugin Java code or JavaScript resources.
1
2
<component-import
key="appProps"
interface="com.atlassian.sal.api.ApplicationProperties"/>

In the example, appProps is the key for this particular module declaration, for component-import, in this case.

name

The human-readable name of the plugin module.

Used only in the plugin's administrative user interface.

system

Indicates whether this plugin module is a system plugin module (value='true') or not (value='false'). Only available for non-OSGi plugins.

Default: false.

*class and key attributes are required.

Writing a Custom Renderer

To create your own renderer you should create a class that implements com.atlassian.plugin.web.renderer.WebPanelRenderer.

As an example we will create a plugin for the Atlassian Reference Application (version 2.5.0 or higher). We will create a web panel template renderer for FreeMarker templates, which is a format that is not supported by the Atlassian Plugin Framework out of the box. We will then also add a web panel that uses a FreeMarker template.

  1. Using the Atlassian Plugin SDK, create a new plugin for the Reference Application and make sure the generated pom.xml file uses version 2.5.0 or higher:

    1
    2
    $ atlas-create-refapp-plugin
    
  2. Add the FreeMarker library to the Maven dependencies:

    pom.xml

    1
    2
    ...
        <dependency>
            <groupId>freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.9</version>
        </dependency>
    ...
    
  3. Create your renderer class:

    1
    2
    package refapptest.freemarker;
    
    import com.atlassian.plugin.Plugin;
    import com.atlassian.plugin.web.renderer.RendererException;
    import com.atlassian.plugin.web.renderer.WebPanelRenderer;
    import freemarker.cache.ClassTemplateLoader;
    import freemarker.template.Configuration;
    import freemarker.template.DefaultObjectWrapper;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;
    
    import java.io.IOException;
    import java.io.Writer;
    import java.util.Map;
    
    public class FreeMarkerWebPanelRenderer implements WebPanelRenderer
    {
        private Template loadTemplate(String filename) throws IOException
        {
            final Configuration conf = new Configuration();
            conf.setObjectWrapper(new DefaultObjectWrapper());
            conf.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/"));
            return conf.getTemplate(filename);
        }
    
        public String getResourceType()
        {
            return "freemarker";
        }
    
        public void render(String templateFile, Plugin plugin, Map<String, Object> stringObjectMap, Writer writer)
                throws RendererException, IOException
        {
            try
            {
                loadTemplate(templateFile).process(stringObjectMap, writer);
            }
            catch (TemplateException te)
            {
                throw new RendererException(String.format(
                        "Unable to render freemarker template %s: %s", templateFile, te.getMessage()), te);
            }
        }
    
        public String renderFragment(String templateFile, Plugin plugin, Map<String, Object> stringObjectMap)
                throws RendererException
        {
            throw new AssertionError("Not yet implemented.");
        }
    }
    

    Note how the WebPanelRenderer interface declares two render methods: one that takes the name of a template file and one that takes the whole template as a String. In this example we have only implemented the former method. The latter is left as an exercise for you. The consequence of this is that we will not be able to embed our FreeMarker content in atlassian-plugin.xml.

  4. Add the new renderer to atlassian-plugin.xml:

    atlassian-plugin.xml

    1
    2
    ...
        <web-panel-renderer key="freemarkerWebPanelRenderer" class="refapptest.freemarker.FreeMarkerWebPanelRenderer"/>
    ...
    
  5. Add a web panel to the Reference Application's administration page that uses this new renderer:

    atlassian-plugin.xml

    1
    2
    ...
        <web-panel key="aFreeMarkerPanel" location="atl.admin.body">
            <resource name="view" type="freemarker" location="templates/mytemplate.ftl"/>
        </web-panel>
    ...
    
  6. Add your FreeMarker template:

    src/main/resources/templates/mytemplate.ftl

    1
    2
    <#assign color = "DarkRed">
    <div style="color: ${color};">
        <p>
            This is a FreeMarker Web Panel!
        </p>
    
        <#assign people = [{"name":"Joe", "age":25}, {"name":"Fred", "age":18}]>
        <ul>
        <#list people as person>
            <li>${person.name} is ${person.age}</li>
        </#list>
        </ul>
    </div>
    
  7. Start up the Reference Application using the command: $ atlas-mvn refapp:run

  8. Go to: localhost:5990/refapp/admin

Known Limitations

You may have noticed how the configuration for our FreeMarker's template loader uses a freemarker.cache.ClassTemplateLoader instance which expects templates to be on the classpath. To do this, FreeMarker's ClassTemplateLoader constructor takes a Class instance and then calls Class.getResource() when it needs to load a template.

In our example we use FreeMarkerWebPanelRenderer.class, which means that our renderer is limited to rendering templates that live in its own plugin JAR file. This is sufficient for this tutorial which has the renderer, the web panel and the template all in the same plugin. However, it would not work when the renderer is shared with other plugins and needs to render a template that lives in another plugin JAR.

If you want to build a shared FreeMarker renderer this way, you would have to implement your own freemarker.cache.TemplateLoader. Instead of taking a Class instance, your template loader would take the ClassLoader that is returned by plugin.getClassLoader().

To keep the example clear and simple, we have chosen to accept this limitation. However, note that it has been addressed properly in the full source code that is available below.

Source Code

To access the full source code for this plugin, you can:

Web Panel Plugin Module
Plugin Modules

Rate this page: