Skip to end of metadata
Go to start of metadata

Available:

Confluence 1.4 and later

 

XWork plugin modules enable you to deploy XWork / WebWork actions and views as a part of your plugins.

On this page:

The XWork Plugin Module

Each XWork module is deployed as a plugin module of type xwork and contains one of more XWork package elements.

Here is an example atlassian-plugin.xml file containing a single XWork module:

  • The xwork element has no class attribute.
  • You can specify multiple package elements within the xwork element. These are standard XWork package elements, just as you would specify in xwork.xml.
  • Ensure the <result> entry appears on a single line with no spaces.

Writing an Action

For information on how to write a WebWork action, please consult the WebWork documentation.

WebWork actions must implement com.opensymphony.xwork.Action. However, we recommend you make your action extend ConfluenceActionSupport, which provides a number of helper methods and components that are useful when writing an Action that works within Confluence.

Other action base-classes can be found within Confluence, but we recommend you don't use them - the hierarchy of action classes in Confluence is over-complicated, and likely to be simplified in the future in a way that will break your plugins.

Accessing Your Actions

Actions are added to the XWork core configuration within Confluence, which means they are accessed like any other action!

For example, given the above atlassian-plugin.xml, the livesearch action would be accessed at http://yourserver/confluence/plugins/livesearch/livesearch.action.

Creating a Velocity Template for Output

Your Velocity template must be specified with a leading slash (/) in the plugin XML configuration, and the path must correspond to the path inside the plugin JAR file.

In the above example, the Velocity template must be found in /templates/extra/livesearch/livesearchaction.vm inside the plugin JAR file. In the example plugin's source code, this would mean the Velocity template should be created in src/main/resources/template/extra/livesearch/.

Inside your Velocity template, you can use $action to refer to your action, and many other variables to access Confluence functionality. See Confluence Objects Accessible From Velocity for more information.

Notes

Some issues to be aware of when developing or configuring an XWork plugin:

  • Your packages should always extend the default Confluence package. It is useful to be aware of what this provides to you in the way of interceptors and result types. Extending any other package will modify that package's configuration across the entire application, which is not supported or desirable.
  • You can give your packages any namespace you like, but we recommend using /plugins/unique/value - that is prefixing plugin packages with /plugins and then adding a string globally unique to your plugin. The only name you can't use is servlet as the /plugins/servlet URL pattern is reserved for Servlet Module.
  • Views must be bundled in the JAR file in order to be used by your actions. This almost always means using Velocity views.
  • It is useful to be aware of the actions and features already bundled with Confluence, for example your actions will all be auto-wired by Spring (see Accessing Confluence Components from Plugin Modules) and your actions can use useful interfaces like PageAware and SpaceAware to reduce the amount of work they need to do.
  • Currently only WebWork Modules are protected by the temporary secure administrator sessions. Other plugin types, such as REST services or servlets are not checked for an administrator session.

    All webwork modules mounted under /admin will automatically be protected by secure administrator sessions. To opt out of this protection you can mark your class or webwork action method with the WebSudoNotRequired annotation. Conversely, all webwork actions mounted outside the /admin namespace are not protected and can be opted in by adding the WebSudoRequired annotation.

    Both of these annotations work on the class or the action method. If you mark a method with the annotation, only action invocations invoking that method will be affected by the annotations. If you annotate the class, any invocation to that class will be affected. Sub-classes inherit these annotations.

Important Security Note

If you are writing an XWork plugin, it is very important that you read this security information: XWork Plugin Complex Parameters and Security

Example

The LiveSearch example is a neat example of an Ajax-style Confluence plugin which uses a bundled XWork module to do it's work:

Find this example in the /plugins/macros/livesearch directory within your Confluence distribution.

See also

  • No labels

28 Comments

  1. Is there a way to modify the livesearch macro so that it only searches in a certain space?

    thanks in advance

    1. At this point, not without making modifications to the livesearch macro itself. If you would like to see this feature, please raise a feature request via http://jira.atlassian.com

      Regards,
      -Daniel

    2. Since Confluence 2.1 you can specify a spaceKey parameter. For example:

      {livesearch:spaceKey=ds}

      will list only pages from the Demonstration Space

      Cheers,
      Jens

  2. There's actually a bug for that here....

    http://jira.atlassian.com/browse/CONF-4546

    but it doesn't seem to be working in 2.1.4 as indicated there.

  3. I'm creating a plugin. the XWork part is not working properly. The following is part of plugin.xml file.

    The problem happens when to forward to the preview result. I got the following exception:

    Icon

    org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource '/ /plugins/news /plugins/news/templates/preview.vm '

    Can anyone give me some idea? Thanks

    1. Few comments:

      Namespacing
      You have specified the /plugins/news namespace, and still prepended the namespace to the action name ... this would mean the action is at http://confluence.atlassian.com/plugins/news/plugins/news/preview.action ... I assume you want http://confluence.atlassian.com/plugins/news/preview.action, so just remove plugins/news/ from the begining of the action element's name attribute.

      Whitespace
      I would remove the whitespace around the result contents and have <result...>/plugin/news/templates/preview.vm</result> instead.

      VM Location
      Finally, check that the preview.vm file is in the "plugins/news/templates" folder in your jar (simply open the jar in any zip viewer). If it isnt there then adjust the deployment path or your location in the result body.

  4. Thanks, Dan. After removed white space and changed the action name, it works.
    My action config now is:

    While, in the sample plugin dynamictasklist, the action config is:

    In my case, the actual action URL is built by ActionNameSpace+ResultURL, while in dynamictasklist plugin it is ResultURL. Why is it diffrent?

    1. In dynamictasklist the .vm file path starts with '/'. That is a signal for the XWork engine to start from the top of the webapp's (in this case Confluence's) context path. If you want the same result, just add '/' to the start of your result URL.

      1. The problem might be the white space? It seems that the result entry should not have any whitespace if the result type is velocity. If the first character is not "/", then XWork will prefix the namespace string to the result URL.

  5. The livesearch plugin doesn't seem to work for me anymore after upgrading from 2.1.5 to 2.2.9. Very sad, because me and my colleagues love it (smile)

     I'm not a java expert but this does pop up in the logs:

    2006-10-23 21:47:59,920 ERROR [getaheadplugin.dwr.impl.SignatureParser] error Parameter mismatch parsing signatures section in dwr.xml on line:
    +SearchDWR.doSearch(List<String>, List<String>, Map<String,String>, List<String>, int)
    2006-10-23 21:48:10,796 WARN [getaheadplugin.dwr.impl.DefaultConverterManager] warn Missing type info for doSearch(0<0>). Assuming this is a map with String
    +keys. Please add to <signatures> in dwr.xml
    2006-10-23 21:48:10,821 WARN [getaheadplugin.dwr.impl.DefaultConverterManager] warn Missing type info for doSearch(1<0>). Assuming this is a map with String
    +keys. Please add to <signatures> in dwr.xml
    2006-10-23 21:48:10,822 WARN [getaheadplugin.dwr.impl.DefaultConverterManager] warn Missing type info for doSearch(2<0>). Assuming this is a map with String
    +keys. Please add to <signatures> in dwr.xml
    2006-10-23 21:48:10,823 WARN [getaheadplugin.dwr.impl.DefaultConverterManager] warn Missing type info for doSearch(2<1>). Assuming this is a map with String
    +keys. Please add to <signatures> in dwr.xml
    2006-10-23 21:48:10,824 WARN [getaheadplugin.dwr.impl.DefaultConverterManager] warn Missing type info for doSearch(3<0>). Assuming this is a map with String
    +keys. Please add to <signatures> in dwr.xml
    2006-10-23 21:48:10,825 WARN [getaheadplugin.dwr.impl.DefaultConverterManager] warn Missing type info for doSearch(4<0>). Assuming this is a map with String
    +keys. Please add to <signatures> in dwr.xml
    

    If anyone can advise me on how to fix this, please let me know!

    1. Hi Menso,

      Where did you download your livesearch plugin from?

      I checked the latest source for the livesearch plugin within Confluence source code and it is not using DWR for its AJAX requests.

      Can you provide us with the livesearch plugin jar you are using?

      Please put your reply in a support request at http://support.atlassian.com and we'll handle it there.

      Cheers,
      Dave

    2. Those messages are generated by the Advanced Search plugin - and can be ignored as the assumptions it makes are correct. In a later release a <signatures> section may be added to the dwr xml.

      This would not stop the livesearch plugin from working.

  6. The LiveSearchAction plugin is kind of useless as an example, since most of the implementation is actually done in SiteSearchAction (the source code for which is not availalbe in the examples directory). Is there something else I can look at as an example of how to implement an Action?

    1. If you mean "how to implement an Action class", that's really easy. A Confluence action has three characteristics:

      1. It extends com.atlassian.confluence.core.ConfluenceActionSupport.
      2. It has an execute() method that returns a result String. The method gets called when the action URL gets a request, and the result String is matched against the results in atlassian-plugin.xml to forward to a Velocity template. Predefined results are constants in ActionSupport - SUCCESS, ERROR, INPUT, etc.
      3. It has setFoo() methods called by Spring to inject dependencies and by Webwork to set query parameters, and getBar() methods called by Velocity when you write "$action.bar".

      An extremely short example looks like this:

      Accessing this action via test.action?pageId=12345 will run the execute() method, forward to the Velocity template mapped to the 'success' result, and allow you to write $action.pageCreator in Velocity to retrieve the page creator for the page with the given pageId.

      There are hundreds of actions in the Confluence source code, if you want to see more complicated examples. The mapping from Actions to Velocity in Confluence is done via the xwork.xml file.

      1. Anonymous

        when I call the action I know how to call test.action, but how to I get the extra ?pageId=12345appended to the action from the VM file

        1. It depends on which page you want to operate on.

          If you want to link back to the page that contains the link to test.action, then it is the id of that page. 

          If you are building the link in a velocity macro in xml, you might be able to use $pageId

          From java, you can get it from the renderContext.

          If you want to link to another page, then you will have to use the appropriate managers to find the id.

      2. Matt,

        How would I code the <result> element if I want to reload the current page?

        Example: I have a macro with a button on a page. When the user clicks the button, I want the action to be invoked, and when it completes, I want the current page to reload. (After the action is completed, the macro will produce different output than the button.)

        I've tried:

        <result name="success" type="redirect">${page.urlPath}</result>

        But that doesn't work. (I get a 404 not found.)

        I must be missing something obvious.

        Thanks!

  7. I want to add a Action-conversion.properties file for my action.  Where do I put this file and what kind of configuration do I need to do in either the plugin config file or the pom file?

    1. Hi Peter,

      Could you please clarify further on what you are trying to achieve?

      Cheers,
      Tony

    2. Hi Peter,

      I also tried this, and here is the result of my analysis:

      I think this is not possible, if you want to use the plugin deployment, as XWork will try to load your conversion class using the WebappClassLoader, which will not find the class within your plugin JAR. (I got {{ClassNotFoundException}}s)

      However, it should work if you install your plugin in WEB-INF/lib. In this case MyAction-conversion.properties should be in the same directory as MyAction.class.

      @Tony: The conversion.properties files are used to set complex properties on the action class as described here: http://wiki.opensymphony.com/display/WW/Type+Conversion

      Or does anybody know workarounds for this??

      Cheers,
      -Stefan

  8. Can you overwrite the values in xworks.xml with values in a plugin?  For example is there a way to do this?
    <atlassian-plugin name='List Search Macros' key='confluence.extra.livesearch'>
    ...

    <xwork name="my.login" key="my.login">
    <package name="my.login" extends="default"> <!-- no namespace should mean "/" -->

    <default-interceptor-ref name="defaultStack" />

    <action name="livesearch" class="com.atlassian.confluence.user.actions.LoginAction">
    <result name="success" type="velocity">/my/login-with-my-custom-stuff-in-here.vm</result>
    <result name="error" type="velocity">/my/login-error.vm</result>
    </action>

    </package>
    </xwork>
    </atlassian-plugin>

    I may also want to create my own custom actions that forward to custom vm files that overload base confluence actions (through a plugin). 

    1. Yeah, you can do that but you have to define the same extends and namespace.

      When overloading the base confluence action make sure you implement the appropriate interfaces if you want reproduce the very same behaviour:

      i.e.:

      That said, overload the actions only if is absofreakinglutly necessary... it can get messy if you want to interact with other plugins that might want do the same...

  9. Anonymous

    Hi,

    I have been asked to implement a label aggregation component for confluence. When a user clicks on a label, this usually points to a default page (/label/theLabel). I need to be able to override that landing page with something of my own. Should I be looking into webworks/XWorks to achieve this? Any help here would be very welcome.

     -Kevin

    1. You might be better asking questions like this on the developer list/forum.

      You will want to create an xwork action for your new page, unfortunately there is no easy way to override the default actions in confluence from a plugin. (It can be done if you want to edit the confluence source, but this will make updating very painful). Have a look at Dave Peterson's conveyor library which might be of some assistance.

      http://www.customware.net/repository/display/AtlassianPlugins/Confluence+Conveyor+Library

  10. Hi all, i'm a newbie about confluence, and i need to write an action that do the same thing like quicksearch standard action in confluence but to redirect the result in another page, in a specific result-search page in my space.
    My intention is to apply a theme to the result search page, that  i understood , looking around on forums is a global page that don't maintain the  specific space's theme from where the quicksearch was invoked. But this page gain the global theme of confluence, and i can't apply my custom theme to confluence, but only to a specific space.

    i'm trying to redirect the action of quicksearch to a page inside specific space , with my theme. (it is possible?)

    Here what i done:

     <xwork name="pnxactions" key="pnxactions">
           <package name="pnxtheme" extends="default" namespace="/plugins/pnxstheme">
            <default-interceptor-ref name="defaultStack" />
           <action name="pnxsearch" class="com.atlassian.confluence.search.actions.SearchSiteAction" method="doDefault">
               <interceptor-ref name="defaultStack"/>
               <result name="input" type="velocity">/components/pnx/searchdecorator/searchsitepnx.vm</result>
           </action>
           <action name="dopnxsearch" class="com.atlassian.confluence.search.actions.SearchSiteAction">
               <interceptor-ref name="validatingStack"/>
               <result name="error" type="velocity">/components/pnx/searchdecorator/searchsitepnx.vm</result>
               <result name="input" type="velocity">/components/pnx/searchdecorator/searchsitepnx.vm</result>
               <result name="success" type="velocity">/components/pnx/searchdecorator/searchsitepnx.vm</result>
           </action>
            </package>
        </xwork>

    (Just cut and copy from xwork.xml)

    I created all my vm and vmd files , but the problem is that the succes page is something like a page out from confluence context/style/CSS.

    Is like a page out of any space, that display correctly results and icons near the link too (the info about if the link is for a page ,an account or other that match search's filters), but all the rest is white page with no customization, no confluence's theme.

    Anyone can help me to find a solution about this problem?.

    Thanks in advance, and sorry for my english is a painful (smile) ....

    1. Hi,

      In order to access your plugin, it seems that you need to put the following url:

      <context path>/plugins/pnxstheme/<YourWebwordAction>
      

      Confluence has provided decorator which will decorate your page when certain url is being requested. As your url-pattern is not fulfilled any url pattern defined in the decorators.xml file. It is not decorated by Confluence.

      Cheers,

      1. Yes i know that, i overrided the main.vmd ,changed the part where it link to the standard quicksearch with this:


        As you suggested, i used as path the fullfilled url: /plugins/pnxtheme/dopnxsearch.action

        And it works , i'm getting a result from query.The problem is only that no style is applied to the page renderizzed.

        I'm trying setting a redirect to a static page added in my space , this mean that a page named "Search" in my case must be created before the plugin is invoked,(is not really a good solution i know). But the problem is that using the redirect function on results page of action can't access the space key from context of confluence

        this is  how i tried to change:

        I used this list of key (to access the space variable):

        but no one work for me.. the result is always page not found and the path confluence si trying to reach this:

        /display//Search and seems that space is not available in the plugin.

        I got this option from xwork.xml in confluence, where is used to link to home page of a space:

        But in my plugin seems that i'm out from any space (smile) ... the problem persist damnit.

        1. Anonymous

          Hi,

          In order for your plugin to be decorated, you need to have a meta tag defined within head tag. Like this:

          Copy/Paste that block, it should work (smile)