Declarative Services and bnd
I really like declarative services because it satisfies one of my main instincts: less is more. You can get services to work in a very easy way. However, the XML is still, well, ehh, XML. Obviously, the unnecessary verboseness of XML still offends my instincts. XML is useful in machine to machine communications because it is well standardized but it should have no place in human-machine interaction.
I therefore, a long time ago, added a facility in bnd to create the declarative services from a manifest header. For simplicity, I like the static 1:1 policy/cardinality so that was the default.
Service-Component: aQute.shell.osgi.OSGiShell;\ provides:=aQute.command.CommandProcessor; \ threadio=aQute.threadio.ThreadIO
This creates the following XML:
<?xml version='1.0' encoding='utf-8'?> <component name='aQute.shell.osgi.OSGiShell'> <implementation class='aQute.shell.osgi.OSGiShell'/> <service> <provide interface='aQute.command.CommandProcessor'/> </service> <reference name='threadio' interface='aQute.threadio.ThreadIO' bind='setThreadio' unbind='unsetThreadio'/> </component>
As the Ruby guys would say: convention over configuration. However, not all services are 1:1 static and the syntax for specifying other cardinalities is kind of ugly. You need to list the reference names in special directives for policy:, multiple:, and optional: :
Service-Component: aQute.shell.osgi.OSGiShell;\ provides:=aQute.command.CommandProcessor; \ threadio=aQute.threadio.ThreadIO; \ dynamic:=threadio; \ multiple:=threadio; \ dynamic:=threadio
Now it is not true that all combinations of dynamic, multiple, and dynamic are used with the same frequency. Static is very popular with 1:1 but all other combinations are usually dynamic. What is the idea of having multiple services but you can not handle changes in the set? This case is often used to track services used with the whiteboard pattern. So one day, when being affronted by my own syntax, I figured out that we have these really nice regular expression symbols for the cardinality.
* 0:n + 1:n ? 0:1
Hmm, the most concise syntax would be to just append one of those characters at the end of the referenced name with the simple rule that 1:1 is static and all others are dynamic. So now it looks like:
Service-Component: aQute.shell.osgi.OSGiShell;\ provides:=aQute.command.CommandProcessor; \ threadio=aQute.threadio.ThreadIO?
This will create a dynamic 0:1 (single optional) reference to the ThreadIO service. I also added ~, which reflects a static 0:1 reference.
More cruft removed in my continuous quest for conciseness!
P.S. Please be sure to use the latest bnd version Download.