Dashboard > Atlassian Plugins > ... > Libraries > Confluence Conveyor Library
  Atlassian Plugins Log In | Sign Up   View a printable version of the current page.  
  Confluence Conveyor Library

Added by David Peterson , last edited by David Peterson on May 28, 2008  (view change)
Labels: 

This library allows plugins to 'convey' users to another location when they access built-in actions.

Details

Name Confluence Conveyor
Current Version 0.5.0
JavaDoc API  

Maven 2

Dependency XML

<dependency>
  <groupId>org.randombits.confluence<groupId>
  <artifactId>confluence-conveyor</artifactId>
  <version>0.5.0</version>
</dependency>

Repository XML

<repository>
  <id>atlassian-m2-contrib</id>
  <name>Atlassian Maven 2 Contributor Repository</name>
  <url>https://maven.atlassian.com/contrib</url>
  <snapshots>
    <enabled>false</enabled>
  </snapshots>
</repository>

Instructions

Overriding the built-in XWork actions is a bit tricky. There are methods for overriding actions by defining them in the atlassian-plugin.xml file. However, you will find that random plugin installations, JDK upgrades or Confluence versions will disable your overrides.

The solution was to build a library which lets you explicitly override actions in a reliable manner. We use it in the Scaffolding Plugin. The best thing is probably to look at that plugin's source code and emulate it. Essentially, there are three steps:

1. Add the 'confluence-conveyor' library as a dependency in your project's pom.xml file.

<dependency>
    <groupId>org.randombits.confluence</groupId>
    <artifactId>confluence-conveyor</artifactId>
    <version>0.5.0</version>
</dependency>

You will also need the 'contributors' maven 2 repository in your repository list:

<repository>
    <id>atlassian-m2-contrib</id>
    <name>Atlassian Maven 2 Contributor Repository</name>
    <url>https://maven.atlassian.com/contrib</url>
    <snapshots>
        <enabled>false</enabled>
    </snapshots>
</repository>

2. Add the ConveyorListener to your atlassian-plugin.xml file. This kicks off the code which lets you override the existing action.

<listener name='Action Conveyor' class='org.randombits.confluence.conveyor.ConveyorListener' key='actionConveyor'>
    <description>Sets up the action conveyor for this plugin.</description>
</listener>

3. Add a 'conveyor-config.xml' file to the root of your plugin resources - the same location as 'atlassian-plugin.xml' is located. This is where you specify what actions you want to override. You can also specify new actions and packages if you wish - I prefer to have all my XWork definitions in one place, so I put them all in 'conveyor-config.xml'. However, you can leave the non-override actions in atlassian-plugin.xml if you wish - both options work fine.

The main difference between conveyor-config.xml and standard XWork is that there are new elements which let you explicitly override an existing package and/or action. This is helpful because it means you won't accidentally override an existing action, it has to be explicit. Also, when overriding, you can choose to only override specific sections, or action responses, which means it is less likely to break with future versions of Confluence where new actions have been added, new responses changed, or even different action classes used.

Here is a simple example of 'conveyor-config.xml':

<?xml version="1.0"?>

<conveyor-config>
    <package-override name="pages" namespace="/pages">
        <!-- Overrides the standard 'editpage' action completely -->
        <action-override name="editpage" class="foo.bar.MyEditAction" method="doDefault">
            <interceptor-ref name="defaultStack"/>
            <result name="success" type="velocity">/templates/myplugin/editpage.vm</result>
            <result name="error" type="velocity">/templates/myplugin/error.vm</result>
        </action-override>

        <!-- Overrides the 'docreatepage' action, only replacing the 'cancel' result -->
        <action-override name="docreatepage" inherit="true">
             <result name="cancel" type="redirect">/alternate/cancel/location.action</result>
        </action-override>

        <!-- Adds a new action to the /pages namespace -->
        <action name="newaction" class="foo.bar.NewAction">
             <result name="success" type="velocity">/templates/myplugin/new.vm</result>
        </action>    

    </package-override>

    <!-- Adds a whole new package to confluence, as you would in atlassian-plugin.xml -->
    <package name="myPackage" extends="default" namespace="/plugins/myplugin">
        <default-interceptor-ref name="defaultStack"/>

        <action name="myaction" class="foo.bar.MyAction">
            <result name="success" type="velocity">/templates/myplugin/myaction.vm</result>
        </action>    
    </package>
</conveyor-config>

There are two new elements above:

a) <package-override> - explicitly overrides an existing package. Any existing actions from that package will continue to work as per-usual, unless explicitly overridden with the <action-override> element.
b) <action-override> - explicitly overrides an existing action. If you wish to keep most of the original action definition, but override specific results or other values, specify 'inherit=true' (see the 'docreatepage' example above). Otherwise, the new definition will completely replace the existing one.

As indicated by the example, you can add new <action> elements into either <package-override> or <package> definitions. The library will not let you accidentally override an existing package or action without using <package-override> or <action-override> explicitly.

Also, be aware that currently there is no good way to manage the situation where two separate plugins try to override the same action. The library will check for an existing override and bail with an error in the log file, but so far I haven't come up with a good way to determine who 'wins'. It will probably require an administration screen which allows admins to choose. But for the moment, it's whichever plugin Confluence decides to load first which wins.

I am having problem getting the Scaffold plugin and the Approvals Workflow Plugin (see APRV-14).

If the AWP is loaded first, then we get this exception:

com.opensymphony.xwork.config.ConfigurationException: No existing action was found to override: editpage
	at org.randombits.confluence.conveyor.config.ConveyorConfigurationProvider.init(ConveyorConfigurationProvider.java:197)

Note that the AWP is not using this library, it is not overriding editpage but overriding viewpage of the pages package (as per atlassian-plugin.xml):

<package name="pages" extends="pages" namespace="/pages">
    <default-interceptor-ref name="validatingStack"/>
    ...
    <action name="viewpage" class="com.comalatech.confluence.workflow.actions.ViewPageAction">
        <result name="viewreleased" type="redirect">/pages/releaseview.action?pageId=${helper.page.id}${actionParameters}</result>
        <result name="error" type="velocity">/pages/viewpage.vm</result>
        <result name="input" type="velocity">/pages/viewpage.vm</result>
        <result name="page" type="velocity">/pages/viewpage.vm</result>
        <result name="possiblealternatives" type="velocity">/pages/alternativepages.vm</result>
        <result name="blogpost" type="velocity">/pages/viewblogpost.vm</result>
    </action>
    ...
</package>

Somehow the Conveyor library is not finding existing actions of a package that has been overriden, even though the action in question has not been overriden at all...

Any ideas?

Hmm. Probably what is happening is that the Conveyor library is finding AWP's override package, which does not have 'editpage', instead of the original package, which does have that action. From memory, it wasn't really allowing for that possibility.

There are two fixes possible:

1. Fix the Conveyor library so that it will keep looking to find the correct 'pages' package.
2. Convert AWP to use the Conveyor library.

#1 should be done anyway, and I'll do that when I get a chance. #2 is up to the developers of AWP, but it would be a good idea, since they will soon come across the same problem we did, which is that their plugin will stop working with random combinations of plugins and JVMs. Simply overriding the 'pages' package the way they are currently is how Scaffolding used to work, but we discovered is not a reliable method.



Updated by Nithya Kannan
Feb 21, 2008 18:03

I am having a problem with my DashboardTheme plugin and Scaffolding-plugin-2.6-dr8
I get the below error while uploading my plugin :

Error: There was a problem loading the module descriptor: org.randombits.confluence.conveyor.ConveyorListener.
Error loading configuration file conveyor-config.xml

I am overriding editpage action in the DashboardTheme plugin,

<package-override name="pages" extends="default" namespace="/pages">

        <action-override name="editpage" class="com.atlassian.confluence.pages.actions.EditPageAction" method="doDefault">
            <interceptor-ref name="defaultStack"/>
            <result name="error" type="velocity">/templates/macros/editpage.vm</result>
            <result name="input" type="velocity">/templates/macros/editpage.vm</result>
            <result name="success" type="velocity">/templates/macros/editpage.vm</result>
        </action-override>

</package-override>

I get an exception that editpage action is already overridden in the Scaffolding Plugin
The 'editpage' action has already been overridden: net.customware.confluence.plugin.scaffolding.actions.RedirectEditAction

But if i try to disable Scaffolding Plugin, then the DashboardTheme plugin is working fine,
but then on enabling the Scaffolding Plugin again, it throws the same conveyor-config error
that editpage action is already overriden in DashboardTheme plugin.

Can anybody help me in enabling both the plugins?

Unfortunately it's not possible to have two plugins override the same action at present, thus the error message which presents itself. The main problem is, how do you decide who gets control?

What is your plugin trying to achieve? Could it be achieved in some other manner?



Updated by Daniele Montagni
May 23, 2008 06:14

Sorry, I've made a mistake on my previous question.

but I have a new question:
Could I include internazionalization file inside the conveyor-config.xml for the actions?
if not, how can I do the same approach that I've used into the atlassian-plugin?

thanks
Daniele

Internationalisation works the same way as for regular plugins - put the <resource type='i18n'...> definition into your atlassian-plugins.xml file. Conveyor just changes where the XWork actions are defined, they still have access to the standard plugin features.

I'm trying to do exactly that (overriding landing pages) but not for /page. I'm trying to override the landing page of the labels. My problems are:

 1. I don't know the values to specify for labels for
<package-override name="pages" extends="default" namespace="/pages">2. labels don't seem to use .action urls, so how do I find out which actions I want to override?

Any help on this would be greatly appreciated.

Cheers,

Kevin  

Hi Kevin,

To figure out what your values should be, check out the 'xwork.xml' file from Confluence. If you have the source code, it is in '/confluence-project/confluence/src/etc/java' directory. If you just have the server, you will have to expand the WEB-INF/lib/confluence-*.jar file, and 'xwork.xml' will be in the root directory.

Once you have that, track down the <action> definition for the package/action you are interested in. The 'name', 'extends' and 'namespace' should match whatever is defined for the original package you're overriding. The action name will also match, and you can specify if you want to inherit the default definition, or completely replace it with your new one.

Let me know if you have any further questions.

Im trying the following code in the "conveyor-config.xml"

 But it is not working, without any errors.

<?xml version="1.0"?>

<conveyor-config>
        <!- Overrides the standard 'login' action ->
        <action-override name="login" class="com.atlassian.confluence.user.actions.LoginAction">
            <interceptor-ref name="defaultStack"/>
            <result name="error" type="velocity">/login_ext.vm</result>
            <result name="success" type="velocity">/login_ext.vm</result>
        </action-override>
</conveyor-config>

Can I override the login-action?

 Thanks
Daniel

Hi Daniel,

You need to have the <action-override> inside a <package-override>, specifically that containing the standard login action, which you can find in the 'xwork.xml' file in Confluence. Also, I would suggest putting your .vm files into a unique subdirectory for future-proofing... Something like:

<conveyor-config>
    <package-override name="default">
        <!-- Overrides the standard 'login' action -->
        <action-override name="login" class="com.atlassian.confluence.user.actions.LoginAction">
            <interceptor-ref name="defaultStack"/>
            <result name="error" type="velocity">/my/plugin/key/login_ext.vm</result>
            <result name="success" type="velocity">/my/plugin/key/login_ext.vm</result>
        </action-override>
    </package-override>
</conveyor-config>

Actually, it may get a little trickier, because 'login.action' is still a special case, and may be hijacked at a higher level by the security system. You'll have to experiment...



Updated by Daniel Koch
Sep 18, 2008 04:27

Hi David,

I use confluence 2.9.1 and use the following setup:

"1.0"?>


    <package-override name="default">
       
        "login" class="com.atlassian.confluence.user.actions.LoginAction">
            "defaultStack"/>
            "error" type="velocity">misc/login.vm
            "success" type="velocity">misc/login.vm
       
    package-override>

The overriding works but with a strange side effect. If I edit a page and press the "cancel" button I get a blank screen. The atlassian-confluence.log came up with the following entry:

 2008-09-17 19:27:43,025 WARN [http-8080-Processor3] [com.opensymphony.xwork.DefaultActionInvocation] executeResult No result defined for action net.customware.confluence.plugin.scaffolding.actions.RedirectEditAction and result cancel
2008-09-17 20:24:34,683 ERROR [http-8080-Processor1] [confluence.conveyor.config.ConveyorConfigurationProvider] addPackageOverride An action with the specified name already exists in the 'pages' package: checkforscaff; net.customware.confluence.plugin.scaffolding.actions.RedirectEditAction
 -- url: /admin/plugins.action | userName: admin | action: plugins

Do you have an idea to solve this problem?
Thanks, Daniel

Hi Daniel - sorry, missed this comment back when you posted it. The solution would be to add a 'cancel' response type, with an appropriate action. Not sure what that would be for login, though...

I used this conveyor library to over ride the people directory action in the default package.

My conveyor-config.xml is as follows

<?xml version="1.0"?>

<conveyor-config>
<!-- overriding people directory action only in the default package -->
    <package-override name="default" >
        <!-- Overrides the standard 'peopledirectory' action completely -->
        <action-override name="peopledirectory" class="com.mycompany.confluence.plugins.myplugin.PeopleDirectoryAction" inherit="true">
            <interceptor-ref name="validatingStack"/>
            <result name="oldsearch" type="redirect">/dopeopledirectorysearch.action?searchQueryBean.queryString=${oldSearchString}&amp;showOnlyPersonal=${showOnlyPersonal}&amp;startIndex=${oldStartIndex}</result>
            <result name="browsepeople" type="redirect">/browsepeople.action?startIndex=${oldStartIndex}</result>
            <!-- doesn't ever produce 'success' --><!--<result name="success" type="velocity">/users/peopledirectory.vm</result>-->
            <result name="error" type="velocity">/notpermitted.vm</result>
        </action-override>
    </package-override>
</conveyor-config>

and my atlassian-plugin.xml is as follows

<atlassian-plugin key="${atlassian.plugin.key}" name="myPlugin">
    <plugin-info>
        <description></description>
        <version>1.0</version>
        <!-- TODO: Add vendor details -->
    </plugin-info>

    <listener name='Action Conveyor' class='org.randombits.confluence.conveyor.ConveyorListener' key='actionConveyor'>
    	<description>Sets up the action conveyor for this plugin.</description>
	</listener>

    <xwork name="FirewallAction" key="com.mycompany.confluence.plugins.myplugin.FirewallAction">
        <package name="FirewallAction" extends="default">
	        <action name="peopledirectory" class="com.mycompany.confluence.plugins.myplugin.PeopleDirectoryAction">
		            <interceptor-ref name="validatingStack"/>
		            <result name="oldsearch" type="redirect">/dopeopledirectorysearch.action?searchQueryBean.queryString=${oldSearchString}&amp;showOnlyPersonal=${showOnlyPersonal}&amp;startIndex=${oldStartIndex}</result>
		            <result name="browsepeople" type="redirect">/browsepeople.action?startIndex=${oldStartIndex}</result>
		            <result name="error" type="velocity">/notpermitted.vm</result>
	        </action>
        </package>
    </xwork>
</atlassian-plugin>

Can any one point out where I am going wrong?

It just seems to go on an endless loop when I click on People breadcrumb on top after I install this plugin.

Thanks,

The problem is, you're defining the action twice - both in the conveyor-config.xml and the atlassian-plugin.xml. The idea with conveyor is that it is used instead of the standard XWork definitions in atlassian-plugin.xml. So, my suggestion would be to remove the <xwork> section from your atlassian-plugin.xml file and see if that improves the situation.

I removed the xwork element from my atlassian-plugin.xml still I get the same endless loop.

Possibly the problem is the inherit='true' value on the people directory. It's hard to say exactly without seeing the rest of your code - it could just be a logic bug somewehere...

If you need further assistance, it's probably best to email me directly, perhaps with some code, and I'll see what we can figure out.

I was able to solve this issue and completely override the people directory functionality that confluence offers.

My custom plugin works seamlessly now using this conveyor library.

Thanks David.

Copyright(c) CustomWare Asia Pacific Pty Ltd
Powered by Atlassian Confluence 2.7.3, the Enterprise Wiki. Bug/feature request - Atlassian news - Contact administrators