Bamboo Persistence using Bandana

Bandana is only available in Bamboo 2.3 or later.

Bandana 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:

  • Bandana stores data in contexts. In Bamboo, there is one global context, and one context per plan.
  • Each context stores key-value pairs. The key is a String and the value can be any Object (it should typically implement Serializable).
    (info) We recommend that you make your objects as simple as possible. Bandana will attempt to persist the entire object and you may have issues changing package names, field names, etc, if you implement complex objects. You can mark fields as 'transient' to prevent them from being persisted. Read more about this in the XStream FAQs.

If you are defining your own type within a plugin, please provide a no argument constructor to avoid class loading issues.

Based on this design, the BandanaManager has methods for storing and retrieving values from a context by key:

  • void setValue(BandanaContext context, String key, Object value) — store a value against a key in the Bandana context.
  • Object getValue(BandanaContext context, String key) — get a key's value from the Bandana context. Returns null if no matching context and key exists.
  • Object getValue(BandanaContext context, String key, boolean lookUp) — same as above, except if lookUp is true and the context is a space context, this method will also check the global context if no matching key is found in the space context.

For plugins, it is recommended to use a key for your Bandana values that includes the full package name of your plugin. For example, an auto-favourites plugin might use a key like org.acme.bamboo.autofavourites.importantPreference.

This XML is written to the BANDANA table in the database.

To get access to the BandanaManager from your plugin code, normally you only need to include a private BandanaManager field. A setter method will be called the first time your plugin is called.

public class DefaultBandanaManagerTest extends TestCase
{
 	   public void testBandanaManagerSample() throws Exception
 	   {
 	       // setup
 	       BandanaManager bandanaManager = new DefaultBandanaManager(new MemoryBandanaPersister());
 	       Build mockPlan = EasyMock.createMock(Build.class);
 	       // expectations
 	       Map<String, Number> config = new HashMap<String, Number>();
 	       config.put("testvalue", 200);
 	
 	       EasyMock.replay(mockPlan);
 	
 	       // execute
 	       bandanaManager.setValue(PlanAwareBandanaContext.GLOBAL_CONTEXT, "system.bamboo.repository.Hello:mykey", config);
 	
 	       final Map<String, Number> returnValue = (Map<String, Number>)bandanaManager.getValue(new PlanAwareBandanaContext(mockPlan),
 	                                                                                            "system.bamboo.repository.Hello:mykey");
 	       // Return value should cascade up to the global context
 	       assertEquals(1 , returnValue.size());
 	       assertEquals(200 , returnValue.get("testvalue"));
 	       assertEquals(returnValue, bandanaManager.getValue(PlanAwareBandanaContext.GLOBAL_CONTEXT, "system.bamboo.repository.Hello:mykey"));
 	       assertNull(bandanaManager.getValue(new PlanAwareBandanaContext(mockPlan),
 	                                          "system.bamboo.repository.Hello:mykey",
 	                                          false));
 	       Map<String, Number> perProjectConfig = new HashMap<String, Number>();
 	       perProjectConfig.put("testvalue", 100);
 	       bandanaManager.setValue(new PlanAwareBandanaContext(mockPlan), "system.bamboo.repository.Hello:mykey", perProjectConfig);
 		
 	       final Map<String, Number> returnValue2 = (Map<String, Number>) bandanaManager.getValue(new PlanAwareBandanaContext(mockPlan),
 	                                                                                              "system.bamboo.repository.Hello:mykey");
 	
	       // Now that the return value has a specific value for the plan, it should just display that info
 	       assertEquals(1, returnValue2.size());
 	       assertEquals(100, returnValue2.get("testvalue"));
 	
 	       EasyMock.verify(mockPlan);
 	   }
}
Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport