This library provides the ability for plugins to share data, both between each other and with Confluence users.
Details
Maven 2
Dependency XML
<dependency>
<groupId>org.randombits.confluence<groupId>
<artifactId>confluence-supplier</artifactId>
<version>3.0.1</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
 | Assumptions
- The project is building with Maven 2.
- The Maven 2 details above have been added to your project's pom.xml file.
|
The Supplier library lets you both supply data to other plugins such as the Reporting Plugin, as well as pulling in data from other plugins. Depending on your plugin, you may wish to do either, or both.
Setting up your plugin to connect with other plugins
The Supplier library makes use of the [Confluence Intercom Library] to enable inter-plugin communications. As such, we need to register our new supplier with the Intercom system via a 'ConnectionBundle' - in this case a 'LocalSupplierBundle'.
Firstly, we need to have an IntercomStartup implementation which will register our connections. There can be multiple {{IntercomStartup}}s, and you can group suppliers together so they can be turned on or off in the Plugin Admin console. The Reporting Plugin does this with the 'debug' suppliers which are generally turned off.
In any case, for our purposes, we need something like this:
import org.randombits.confluence.intercom.ConnectionBundle;
import org.randombits.confluence.intercom.IntercomException;
import org.randombits.confluence.intercom.IntercomStartup;
import org.randombits.confluence.intercom.LocalIntercomListener;
import org.randombits.confluence.supplier.LocalSupplierBundle;
public class FooSupplierStartup extends IntercomStartup {
public FooSupplierStartup() throws IntercomException {
}
@Override protected ConnectionBundle createConnectionBundle() {
return new LocalSupplierBundle( new FooSupplier(), new BarSupplier() );
}
@Override protected LocalIntercomListener createLocalIntercomListener() {
}
}
Then, register your listener by putting it into the 'atlassian-plugin.xml' file for your plugin:
<listener name='Foo Supplier Startup' class='my.package.FooSupplierStartup'
key='fooSupplierStartup'>
<description>Sets up the Foo Suppliers.</description>
</listener>
Supplying information to other plugins
You will need to create a class which implements the org.randombits.confluence.supplier.Supplier interface. It has three methods:
public boolean supportsPrefix(String prefix)
This method returns true if the supplier supports the specified prefix. Each supplier should have a prefix which users can provide to specify which supplier should be used. Some suppliers will require a prefix, others can make it optional, in which case the supportsContext method is the sole determinant for whether or not a supplier is considered to be the supplier for a given key.
For example, a user may provide the following key value: 'foo:bar'. In this case 'foo' is the prefix and 'bar' is the key which will be passed to the getValue macro.
Let's say our new FooSupplier wants to make the prefix optional. The supplier's prefix is 'foo'. Your code should look something like this:
public boolean supportsPrefix(String prefix) {
return prefix == null || "foo".equals(prefix);
}
To make the prefix required, simply drop the 'null' test:
public boolean supportsPrefix(String prefix) {
return "foo".equals(prefix);
}
You could also support multiple prefixes if you wished, although this is not recommended except for linguistic or deprecation reasons.
public boolean supportsContext(Object context)
The second method used to determine if a supplier supports a given prefix/object combination is the supportsContext method. The context is the current object being processed. The method simply returns true if the object provided is supported by the supplier. For example, if our FooSupplier only supports Foo objects, the method would look like this:
public boolean supportsContext(Object context) {
return context instanceof Foo;
}
public Object getValue(Object context, String key)
This method does the actual work. The context is the same object which was passed to supportsContext - the current object. The key is the second part of the key value, the part after the prefix. For example, if the key value is 'foo:bar', the key will be 'bar'.
This method can do anything it wants with key values, but a typical structure will be something like this:
public Object getValue(Object context, String key) throws UnsupportedContextException, SupplierException {
if (context instance of Foo) {
Foo foo = (Foo)context;
if ("bar".equals(key))
return foo.getBar();
return null;
}
throw new UnsupportedContextException( context );
}
That's basically it for suppliers. Add more keys to the getValue method to provide more access to your object's information.
Pulling data from other plugins
Of course, your plugin may want to actually retrieve data from suppliers; your own or those provided by other plugins. In that case, you still need to have the 'confluence-supplier' library dependency provided above.
Basically, the SupplierAssistant support class has two method you will use: findValue and processValues.
findValue
Below is an example of using findValue.
import org.randombits.confluence.supplier.SupplierAssistant;
...
Object value = SupplierAssistant.getInstance().findValue(context, key);
Bar bar = (Bar)SupplierAssistant.getInstance().findValue(myFoo, "foo:bar");
Long barId = (Long)SupplierAssistant.getInstance().findValue(myFoo, "foo:bar > bar:id");
findValue requires the root object and the keychain to access. Often that keychain will be provided by a Confluence user via a macro parameter, so the first example will be quite common, however you can pass in hard-coded keychains, such as the last two examples. The third example is a true keychain, with two pairs of prefix:key values chained together. Essentially, the SupplierAssistant will parse key chain as follows:
- Get the first prefix/key pair ('foo:bar').
- Find the supplier for the 'foo' prefix and context object (FooSupplier).
- Pass it the current context (myFoo) and the key ('bar').
- If the value returned isn't null, get the next prefix/key pair ('bar:id').
- Find the supplier for the 'bar' prefix and context object (BarSupplier).
- Pass it the current context (the 'Bar' value returned from the FooSupplier).
- Return the value from the BarSupplier.
processValues
processValues is similar to findValue, except that it allows multiple key chain values to be embedded in a single chain. For example:
import org.randombits.confluence.supplier.SupplierAssistant;
...
String text = SupplierAssistant.getInstance().processValues(myFoo, "The %foo:bar% has an id of %foo:bar > bar:id%");
This will embed the values of 'foo:bar' and the 'bar:id' number into the surrounding text. This is quite useful for inserting supplier data into macro parameters, such as the 'name' parameter in link-page.
Conclusion
Hopefully that provides some basic information for getting started with the Confluence Supplier Library. Feel free to comment/ask questions/etc.