This sample illustrates the usage of the new DependencyManager annotations. Sample description: ================== This sample shows a basic "SpellChecker" application which provides a Felix "spellcheck" GOGO shell command. The GOGO "spellcheck" command accepts a string as parameter, which is checked for proper existence. The SpellChecker class has a required/multiple (1..N) dependency over every available "DictionaryService" services, which are internally used by the SpellChecker command, when checking word existence. A DictionaryService is defined using a FactoryConfigurationAdapterService annotation, allowing to instantiate many "DictionaryService" instances from webconsole. This annotation actually registers a ManagedServiceFactory into the Registry, and you can specify some meta type informations in the annotation, allowing to configure the DictionaryService words and language from WebConsole. Each time you instantiate a factory configuration whose factory pid equals "DictionaryImplFactoryPid", in the webconsole "Dictionary Services" configuration section, then a corresponding "DictionaryImpl" component is instantiated and is then injected into the SpellChecker service. So, before testing, you first have to go to webconsole Configuration panel, and specify some dictionaries (see the "Dictionary Services" section). Then, go to the felix GOGO shell, and you will then see the "spellcheck" command (when typing "help"). Notice that in the sample, you will also find a DictionaryAspect Service (DictionaryAspect.java), which decorates the EnglishDictionary service, by adding some additional words to it. How to test: =========== 1) Install the following bundles (with same or higher version): org.apache.felix.configadmin-1.2.8.jar org.apache.felix.metatype-1.0.4.jar org.apache.felix.http.jetty-2.2.0.jar org.apache.felix.webconsole-3.1.8.jar org.apache.felix.shell-1.4.2.jar org.apache.felix.dependencymanager-3.0.0.jar org.apache.felix.dependencymanager.shell-3.0.0.jar org.apache.felix.dependencymanager.runtime-3.0.0.jar org.apache.felix.log-1.0.1.jar (optional) 2) compile dependency manager sample.annotation from trunk: svn checkout http://svn.apache.org/repos/asf/felix/trunk/dependencymanager dependencymanager cd dependencymanager/sample.annotation mvn clean install Then install ./target/org.apache.felix.dependencymanager.samples.annotation-3.0.0-SNAPSHOT.jar into felix. 3) Start felix At this point, you should have the following running bundles: g! lb START LEVEL 1 ID|State |Level|Name 0|Active | 0|System Bundle (3.2.1) 1|Active | 1|Apache Felix Bundle Repository (1.6.2) 2|Active | 1|Apache Felix Configuration Admin Service (1.2.8) 3|Active | 1|Apache Felix Dependency Manager (3.0.0) 4|Active | 1|Apache Felix Dependency Manager Runtime (3.0.0) 5|Active | 1|Apache Felix Dependency Manager Annotation Sample (3.0.0.SNAPSHOT) 6|Active | 1|Apache Felix Dependency Manager Shell (3.0.0) 7|Active | 1|Apache Felix Gogo Command (0.8.0) 8|Active | 1|Apache Felix Gogo Runtime (0.8.0) 9|Active | 1|Apache Felix Gogo Shell (0.8.0) 10|Active | 1|Apache Felix Http Jetty (2.2.0) 11|Active | 1|Apache Felix Log Service (1.0.1) 12|Active | 1|Apache Felix Metatype Service (1.0.4) 13|Active | 1|Apache Felix Shell Service (1.4.2) 14|Active | 1|Apache Felix Web Management Console (3.1.8) 4) Inspect Dependency Manager components from gogo shell: type "dm 5" for browsing the components for the bundle id 5 [5] org.apache.felix.dependencymanager.samples.annotation org.osgi.service.cm.ManagedServiceFactory(service.pid=DictionaryImplFactoryPid) registered org.osgi.service.log.LogService service optional available org.apache.felix.dm.samples.annotation.SpellChecker(osgi.command.function={spellcheck},osgi.command.scope=dmsample.annotation) unregistered org.apache.felix.dm.samples.annotation.DictionaryService service required unavailable org.osgi.service.log.LogService service optional unavailable org.apache.felix.dm.impl.AspectServiceImpl$AspectImpl@4d76b4 unregistered org.apache.felix.dm.samples.annotation.DictionaryService (&(!(org.apache.felix.dependencymanager.aspect=*))(lang=en)) service optional unavailable DictionaryAspectPID configuration required unavailable org.osgi.service.log.LogService service optional unavailable Here, the bundle [5] corresponds to our annotation.sample bundle. In this bundle, we have three components: * org.osgi.service.cm.ManagedServiceFactory: this is the service DM has internally registered in order to be able to instantiate some of our "DictionaryImpl" component instances from config admin (using the factory pid "DictionaryImplFactoryPid"). See DictionaryImpl.java and especially the @FactoryConfigurationAdapterService annotation. The component depends on the log service because our "DictionaryImpl" component also depends on the log service. The ManagedServiceFactory is actually depending on all dependencies defined in our "DictionaryImpl" component, and those dependencies will be applied on each instantiated DictionaryImpl component instances. * org.apache.felix.dm.samples.annotation.SpellChecker: This is our "SpellChecker" component exposing two services properties: "osgi.command.function" (the gogo shell method name), and "osgi.command.scope" (the gogo command scope). It also has two dependencies: "org.apache.felix.dm.samples.annotation.DictionaryService", and "org.osgi.service.log.LogService". * org.apache.felix.dm.impl.AspectServiceImpl$AspectImpl: this is also an internal service registered by dependency manager, in order to instantiate our "DictionaryAspect" interceptor service. See DictionaryAspect.java. The aspect impl depends on the three dependencies (which are initially defined in DictionaryAspect.java): - org.apache.felix.dm.samples.annotation.DictionaryService: this is the service our DictionaryAspect is intercepting. The AspectServiceImpl$AspectImpl will create a DictionaryAspect instance for every DictionaryService found from the OSGi registry (that is, for every DictionaryService you create from web console "Dictionary Services" configuraton section). - DictionaryAspectPID configuration: this is the config pid our DictionaryAspect is depending on (see @ConfigurationDependency in DictionaryAspect.java). - org.osgi.service.log.LogService: the DictionaryAspect is optionally depending on the log service (a null object is used if there is no one). So, when a DictionaryService will come up, the AspectServiceImpl component will instantiate a corresponding "DictionaryAspect" instance, with all the dependencies defined in DictionaryAspect. 5) Create a DictionaryService from web console: Go to web console: in the Configuration panel, edit the "Dictionary Services" Configuration, and add some dictionaries. By default, an English dictionary is displayed. Just click on "save", *then click on your refresh web browser*: you will see a new dictionary service instance. At this point, a "DictionaryImpl" component instance will be create (with the service property "lang=en"), and the SpellCheck component will be injected with it (the DictionaryImpl implements DictionaryService). Then you should see the "spellcheck" command, when typing "help" on the gogo shell. 6) test the spellchecker under gogo shell: Just type "spellcheck hello", and the command should reply a fantastic message, like "word hello is correct". 7) Inspect again DependencyManager components from the shell: Type again "dm 5", for browsing the components coming from our bundle id 5: [5] org.apache.felix.dependencymanager.samples.annotation org.osgi.service.cm.ManagedServiceFactory(service.pid=DictionaryImplFactoryPid) registered org.osgi.service.log.LogService service optional available org.apache.felix.dm.samples.annotation.SpellChecker(osgi.command.function={spellcheck},osgi.command.scope=dmsample.annotation) registered org.apache.felix.dm.samples.annotation.DictionaryService service required available org.osgi.service.log.LogService service optional available org.apache.felix.dm.impl.AspectServiceImpl$AspectImpl@128edf2 unregistered org.apache.felix.dm.samples.annotation.DictionaryService (&(!(org.apache.felix.dependencymanager.aspect=*))(lang=en)) service optional unavailable DictionaryAspectPID configuration required unavailable org.osgi.service.log.LogService service optional unavailable org.apache.felix.dm.samples.annotation.DictionaryService(service.pid=DictionaryImplFactoryPid.e01b70ff-d2b5-4305-9e86-84c68a2fddbb,service.factoryPid=DictionaryImplFactoryPid,lang=en) registered org.osgi.service.log.LogService service optional available Here, you can see the following: * the org.osgi.service.cm.ManagedServiceFactory with factory pid "DictionaryImplFactoryPid" is now registered, because we have created a dictionary from config admin (in the Dictionary Services" webconsole configuration section). * the SpellChecker is now "registered" because it has been injected with the DictionaryImpl we have created from webconsole. * the AspectServiceImpl$AspectImpl is not yet registered because we still have to instantiate a configuration from webconsole for the "DictionaryAspectPID" PID: this configuration is required to instance our DictionaryAspect component (see the @ConfigurationDependency annotation in DictionaryAspect.java). * One instance of the DictionaryService component is now registered (this instance corresponds to what we just configured from webconsole, in the "Dictionary Services" section). 8) Finally, activate the "Aspect Dictionary" component: To do so, you can click on the "Aspect Dictionary" button, from web console Configuration section, in order to decorate the english dictionary with some custom words. By default, the "aspect" word is pre configured, but you can click on the "+" button in order to add more words. Then click on Save. At this point, the English DictionaryService will be decorated with the aspect service. So, now, if you type "spellcheck aspect", then the message: "word aspect is correct" should be displayed. What is going on is that the original DictionaryService will be replaced by the DictionaryAspect, using a higher service.ranking (ranking 10, see DictionaryAspect.java). So the spell checker will be transparently re-injected with the DictionayAspect, which is from his side depending on the originial DictionaryService. So, if you type "dm 5", you will know see two DictionaryService instances: org.apache.felix.dm.samples.annotation.DictionaryService(service.pid=DictionaryImplFactoryPid.8390ad56-b2de-4414-9123-29c65c42e5b9,service.factoryPid=DictionaryImplFactoryPid,lang=en) registered org.osgi.service.log.LogService service optional available org.apache.felix.dm.samples.annotation.DictionaryService(service.pid=DictionaryImplFactoryPid.8390ad56-b2de-4414-9123-29c65c42e5b9,service.ranking=10,service.factoryPid=DictionaryImplFactoryPid,org.apache.felix.dependencymanager.aspect=57,lang=en) registered org.apache.felix.dm.samples.annotation.DictionaryService (&(|(!(service.ranking=*))(service.ranking<=9))(|(service.id=57)(org.apache.felix.dependencymanager.aspect=57))) service required available DictionaryAspectPID configuration required available org.osgi.service.log.LogService service optional available The first one is the original DictionaryService we have created using the factory pid "DictionaryImplFactoryPid" from web console. By default, the ranking of this service is 0. Next, you see the new DictionaryService which corresponds to our DictionaryAspect service. It has the following properties: * it has inherited from all service properties found from the original intercepted DictionarService. * it has a higher service ranking than the original one (see service.ranking=10). This ranking is actually defined in DictionaryAspect.java, in the @Aspect annotation. * it has a dependency over the original DictionaryService (using an appropriate filter). * it also inherits from all dependencies originally defined in the DictionaryImpl component