|
There are three main persistence APIs which are used in Confluence:
Because Bandana is the primary persistence API used by plugin developers, it will be covered in more detail below. HibernateConfluence uses the open source persistence framework Hibernate. Confluence 2.2.x uses Hibernate version 2.1.8. Each object to be persisted has a *.hbm.xml file which sits in the same directory as the associated class in the Confluence web application. For example, Label.class has an associated Label.hbm.xml which describes how label objects will be persisted. The particular details vary from class to class, but typically include:
All this data is expressed in the standard Hibernate mapping format. In some cases, there is a single mapping file for all subclasses of a particular class. For example, ContentEntityObject.hbm.xml includes mappings for pages, news, mail and space descriptions. The Hibernate mapping files are listed in mappingResources bean in applicationContext.xml. Although it might be possible to extend Confluence's database through Hibernate, this is not recommended. There are a few downfalls with extending our Hibernate configuration:
Avoid using Confluence's database to store custom data – use content properties or Bandana instead. BandanaBandana is an Atlassian framework for persistence which uses XStream to convert arbitrary Java objects into XML for storage. The concepts used in Bandana are very simple:
Based on this design, the BandanaManager has methods for storing and retrieving values from a context by key:
For plugins, it is recommended to use a key for your Bandana values that includes the full package name of your plugin. For example, a theme plugin might use a key like org.acme.confluence.mytheme.importantPreference. Prior to Confluence 2.3, this XML was written to the filesystem in the Confluence home directory. The file config/confluence-global.bandana.xml stores the global context, and there is a file config/spaceKey/confluence-space.bandana.xml with the configuration for each space. In Confluence 2.3 and above, Bandana data is written to the BANDANA table in the database, with three columns for context, key and an XML-serialized value. To get access to the BandanaManager from your plugin code, normally you only need to include a private BandanaManager field with an associated setter method. Spring will automatically call the setter method before the first time your plugin is called. public class MyMacro extends BaseMacro { private BandanaManager bandanaManager; // setter called by Spring public void setBandanaManager(BandanaManager bandanaManager) { this.bandanaManager = bandanaManager; } // main method of macro public String execute(...) { // do stuff with bandanaManager return "..."; } } Content propertiesAnother form of persistence, content properties are key-value pairs associated with a ContentEntityObject and stored in the database. |

Comments (10)
Aug 14, 2006
David Peterson says:
There is another issue for plugins, specifically if they have been installed by ...There is another issue for plugins, specifically if they have been installed by being uploaded (or more recently, via the Plugin Repository). If you try to store an object which is defined in the plugin, it will fail when you try to retrieve it because the BandanaManager was created by a ClassLoader which has no knowledge of the plugin's classes.
The solution/workaround is to convert your object to an XML string via XStream before you stick it in Bandana. Something like this:
The key is to set the class loader to the plugin's class loader. You'll also want to add a null-check on any getValue response...
Aug 14, 2006
Matt Ryall says:
Is this the same issue as CONF6655@JIRA? I think someone was looking at it a wh...Is this the same issue as CONF-6655?
I think someone was looking at it a while back. I'll check on the status, and update the issue if it has changed.
Aug 15, 2006
David Peterson says:
Yep, same problem. Actually, it's deserialisation that's the problem, not the in...Yep, same problem. Actually, it's deserialisation that's the problem, not the initial storing of the object. I don't think this will be resolved any time soon - there was a large debate about plugin classloaders which resulted in the current system.
Aug 15, 2006
Dan Hardiker says:
Mike and I have both recently looked into the problem, and came to the same conc...Mike and I have both recently looked into the problem, and came to the same conclusion. Essentially that XStream can't be configured enough to solve this problem without forking XStream.
XStream (as far as I can tell) needs to be modified use the classloader of the calling class, so if a plugin is deserializing then that plugin's classloader needs to be used. A temporary solution is to store as JDK classes (or at least classes which are on the webapp's classpath).
Dec 18, 2006
Chris Cohen says:
In David Peterson's example code, the method name is toXML() (upper case XML) an...In David Peterson's example code, the method name is toXML() (upper case XML) and not toXml()! This stumped me for about 15 minutes until I realised that. (The same goes for the fromXML() method later on.)
Dec 18, 2006
David Peterson says:
Sorry about that must have been coding from memory :)Sorry about that - must have been coding from memory
Aug 14, 2006
Dan Hardiker says:
Prior to Confluence 2.3, this XML was written to the filesystem in the Confluenc...Does this mean that the space scope is now lost, so that the key a.b.c when looked up from a global BandanaContext is the same as when looked up from a space BandanaContext? (... or do you prefix the key with the space key / a unique global key and a separator ...)
Aug 14, 2006
Matt Ryall says:
No, internally it will work exactly as before, only the storage format has chang...No, internally it will work exactly as before, only the storage format has changed.
A space or global scope is represented by the context column. For a space scope, the context value will be the space key; for a global scope, the context value will be SQL NULL.
Sep 06, 2007
Alexander Finn says:
I have a question regarding hibernate as we want to integrate our own persistent...I have a question regarding hibernate as we want to integrate our own persistent objects with Confluence and we don't want to use a separate instance of hibernate's configuration.
The question is do I have any possibility to add my own mapping except for applicationContext.xml modification? I was trying to add it by calling
but this didn't help.
Sep 09, 2007
Choy Li Tham says:
Hi Alexander, Due to the nature of your question, I would suggest you to direct...Hi Alexander,
Due to the nature of your question, I would suggest you to direct your questions to our forum pertaining to the problem you are having as there might be developers/users should be able to share their idea with you.
Also, you may want to raise your queries at our mailing list as listed in the following link:
Hope the information does help.
Regards,
Choy Li
Add Comment