Last updated Mar 13, 2024

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).

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.

1
2
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);
       }
}

Rate this page: