Storing plugin settings with the abstract factory pattern

Work smarter, better, and faster with weekly tips and how-tos.

Part of the new Plugins 2 framework that we are working on is the Shared Access Layer (SAL), which gives an API for performing tasks useful to plugins in a cross-product way. Plugins 2 and thus SAL is currently available in released versions of Confluence, Crowd, Crucible, and Fisheye.

One feature provided by SAL is storage of plugin settings. PluginSettings objects are created with a PluginSettingsFactory like this:PluginSettings pluginSettings = pluginSettingsFactory.createGlobalSettings();PluginSettingsFactory is an interface which includes the createGlobalSettings() method that returns PluginSettings objects. Behind the scenes, settings are stored in a product-specific way. In a Confluence plugin, the pluginSettingsFactory will be a ConfluencePluginSettingsFactory and createGlobalSettings() will return a ConfluencePluginSettings object. The ConfluencePluginSettings object uses Bandana internally to store the plugin settings. For a Jira plugin, the JiraPluginSettingsFactory will return JiraPluginSettings objects that use PropertySets to store the settings.

Here is a diagram of SAL’s plugin settings objects:

The PluginSettingsFactory uses the abstract factory pattern: it “provide[s] an interface for creating families of related or dependent objects without specifying their concrete classes” (p. 87 in Design Patterns by Gamma et al). The PluginSettingsFactory allows us to create specific PluginSettings objects for Confluence, Jira, and other products depending on what type of PluginSettingsFactory (e.g. ConfluencePluginSettingsFactory) is in use, which depends on what product a plugin is for.

Plugin developers benefit from the use of the abstract factory pattern here in several ways. No matter what the target product for a plugin, one syntax can be used to interact with plugin settings. So it is not necessary for developers to learn and remember multiple, distinct settings storage syntaxes for different products. And a particular plugin could potentially have multiple target products without special handling, at least as far as plugin settings are concerned. If we create a new Atlassian product, existing plugin settings code will just work against it too. These are benefits often seen when using factories for object creation: users of the object are insulated from the specific objects used and their implementations, and maintenance changes only need to occur in one location rather than in each client.