Pierre De Rop | 804f4be | 2010-04-25 22:57:56 +0000 | [diff] [blame] | 1 | This sample illustrates the usage of the new DependencyManager annotations. |
| 2 | |
| 3 | Sample description: |
Pierre De Rop | 1e7ffb5 | 2011-05-07 10:21:55 +0000 | [diff] [blame^] | 4 | ================== |
Pierre De Rop | 804f4be | 2010-04-25 22:57:56 +0000 | [diff] [blame] | 5 | |
Pierre De Rop | 1e7ffb5 | 2011-05-07 10:21:55 +0000 | [diff] [blame^] | 6 | This sample shows a basic "SpellChecker" application which provides a Felix "spellcheck" GOGO shell |
| 7 | command. The GOGO "spellcheck" command accepts a string as parameter, which is checked for proper |
| 8 | existence. The SpellChecker class has a required/multiple (1..N) dependency over every available |
| 9 | "DictionaryService" services, which are internally used by the SpellChecker command, when checking |
| 10 | word existence. |
| 11 | |
| 12 | A DictionaryService is defined using a FactoryConfigurationAdapterService annotation, allowing to |
| 13 | instantiate many "DictionaryService" instances from webconsole. This annotation actually registers a |
| 14 | ManagedServiceFactory into the Registry, and you can specify some meta type informations in the |
| 15 | annotation, allowing to configure the DictionaryService words and language from WebConsole. Each |
| 16 | time you instantiate a factory configuration whose factory pid equals "DictionaryImplFactoryPid", |
| 17 | in the webconsole "Dictionary Services" configuration section, then a corresponding "DictionaryImpl" |
| 18 | component is instantiated and is then injected into the SpellChecker service. So, before testing, |
| 19 | you first have to go to webconsole Configuration panel, and specify some dictionaries (see the |
| 20 | "Dictionary Services" section). Then, go to the felix GOGO shell, and you will then see the |
| 21 | "spellcheck" command (when typing "help"). |
| 22 | |
| 23 | Notice that in the sample, you will also find a DictionaryAspect Service (DictionaryAspect.java), |
| 24 | which decorates the EnglishDictionary service, by adding some additional words to it. |
| 25 | |
Pierre De Rop | 804f4be | 2010-04-25 22:57:56 +0000 | [diff] [blame] | 26 | How to test: |
Pierre De Rop | 1e7ffb5 | 2011-05-07 10:21:55 +0000 | [diff] [blame^] | 27 | =========== |
Pierre De Rop | 804f4be | 2010-04-25 22:57:56 +0000 | [diff] [blame] | 28 | |
Pierre De Rop | 1e7ffb5 | 2011-05-07 10:21:55 +0000 | [diff] [blame^] | 29 | 1) Install the following bundles (with same or higher version): |
Pierre De Rop | 804f4be | 2010-04-25 22:57:56 +0000 | [diff] [blame] | 30 | |
Pierre De Rop | 1e7ffb5 | 2011-05-07 10:21:55 +0000 | [diff] [blame^] | 31 | org.apache.felix.configadmin-1.2.8.jar |
| 32 | org.apache.felix.metatype-1.0.4.jar |
| 33 | org.apache.felix.http.jetty-2.2.0.jar |
| 34 | org.apache.felix.webconsole-3.1.8.jar |
| 35 | org.apache.felix.shell-1.4.2.jar |
| 36 | org.apache.felix.dependencymanager-3.0.0.jar |
| 37 | org.apache.felix.dependencymanager.shell-3.0.0.jar |
| 38 | org.apache.felix.dependencymanager.runtime-3.0.0.jar |
| 39 | org.apache.felix.log-1.0.1.jar (optional) |
Pierre De Rop | 804f4be | 2010-04-25 22:57:56 +0000 | [diff] [blame] | 40 | |
Pierre De Rop | 1e7ffb5 | 2011-05-07 10:21:55 +0000 | [diff] [blame^] | 41 | 2) compile dependency manager sample.annotation from trunk: |
Pierre De Rop | 804f4be | 2010-04-25 22:57:56 +0000 | [diff] [blame] | 42 | |
Pierre De Rop | 1e7ffb5 | 2011-05-07 10:21:55 +0000 | [diff] [blame^] | 43 | svn checkout http://svn.apache.org/repos/asf/felix/trunk/dependencymanager dependencymanager |
| 44 | cd dependencymanager/sample.annotation |
| 45 | mvn clean install |
| 46 | |
| 47 | Then install ./target/org.apache.felix.dependencymanager.samples.annotation-3.0.0-SNAPSHOT.jar into |
| 48 | felix. |
| 49 | |
| 50 | 3) Start felix |
| 51 | |
| 52 | At this point, you should have the following running bundles: |
| 53 | |
| 54 | g! lb |
| 55 | START LEVEL 1 |
| 56 | ID|State |Level|Name |
| 57 | 0|Active | 0|System Bundle (3.2.1) |
| 58 | 1|Active | 1|Apache Felix Bundle Repository (1.6.2) |
| 59 | 2|Active | 1|Apache Felix Configuration Admin Service (1.2.8) |
| 60 | 3|Active | 1|Apache Felix Dependency Manager (3.0.0) |
| 61 | 4|Active | 1|Apache Felix Dependency Manager Runtime (3.0.0) |
| 62 | 5|Active | 1|Apache Felix Dependency Manager Annotation Sample (3.0.0.SNAPSHOT) |
| 63 | 6|Active | 1|Apache Felix Dependency Manager Shell (3.0.0) |
| 64 | 7|Active | 1|Apache Felix Gogo Command (0.8.0) |
| 65 | 8|Active | 1|Apache Felix Gogo Runtime (0.8.0) |
| 66 | 9|Active | 1|Apache Felix Gogo Shell (0.8.0) |
| 67 | 10|Active | 1|Apache Felix Http Jetty (2.2.0) |
| 68 | 11|Active | 1|Apache Felix Log Service (1.0.1) |
| 69 | 12|Active | 1|Apache Felix Metatype Service (1.0.4) |
| 70 | 13|Active | 1|Apache Felix Shell Service (1.4.2) |
| 71 | 14|Active | 1|Apache Felix Web Management Console (3.1.8) |
| 72 | |
| 73 | 4) Inspect Dependency Manager components from gogo shell: |
| 74 | |
| 75 | type "dm 5" for browsing the components for the bundle id 5 |
| 76 | |
| 77 | [5] org.apache.felix.dependencymanager.samples.annotation |
| 78 | org.osgi.service.cm.ManagedServiceFactory(service.pid=DictionaryImplFactoryPid) registered |
| 79 | org.osgi.service.log.LogService service optional available |
| 80 | org.apache.felix.dm.samples.annotation.SpellChecker(osgi.command.function={spellcheck},osgi.command.scope=dmsample.annotation) unregistered |
| 81 | org.apache.felix.dm.samples.annotation.DictionaryService service required unavailable |
| 82 | org.osgi.service.log.LogService service optional unavailable |
| 83 | org.apache.felix.dm.impl.AspectServiceImpl$AspectImpl@4d76b4 unregistered |
| 84 | org.apache.felix.dm.samples.annotation.DictionaryService (&(!(org.apache.felix.dependencymanager.aspect=*))(lang=en)) service optional unavailable |
| 85 | DictionaryAspectPID configuration required unavailable |
| 86 | org.osgi.service.log.LogService service optional unavailable |
| 87 | |
| 88 | Here, the bundle [5] corresponds to our annotation.sample bundle. In this bundle, we have three |
| 89 | components: |
| 90 | |
| 91 | * org.osgi.service.cm.ManagedServiceFactory: this is the service DM has internally registered in |
| 92 | order to be able to instantiate some of our "DictionaryImpl" component instances from config |
| 93 | admin (using the factory pid "DictionaryImplFactoryPid"). See DictionaryImpl.java and especially |
| 94 | the @FactoryConfigurationAdapterService annotation. The component depends on the log service |
| 95 | because our "DictionaryImpl" component also depends on the log service. The ManagedServiceFactory |
| 96 | is actually depending on all dependencies defined in our "DictionaryImpl" component, and those |
| 97 | dependencies will be applied on each instantiated DictionaryImpl component instances. |
| 98 | |
| 99 | * org.apache.felix.dm.samples.annotation.SpellChecker: This is our "SpellChecker" component exposing |
| 100 | two services properties: "osgi.command.function" (the gogo shell method name), and |
| 101 | "osgi.command.scope" (the gogo command scope). |
| 102 | It also has two dependencies: "org.apache.felix.dm.samples.annotation.DictionaryService", and |
| 103 | "org.osgi.service.log.LogService". |
| 104 | |
| 105 | * org.apache.felix.dm.impl.AspectServiceImpl$AspectImpl: this is also an internal service registered |
| 106 | by dependency manager, in order to instantiate our "DictionaryAspect" interceptor service. See |
| 107 | DictionaryAspect.java. The aspect impl depends on the three dependencies (which are initially |
| 108 | defined in DictionaryAspect.java): |
| 109 | |
| 110 | - org.apache.felix.dm.samples.annotation.DictionaryService: this is the service our DictionaryAspect |
| 111 | is intercepting. The AspectServiceImpl$AspectImpl will create a DictionaryAspect instance for |
| 112 | every DictionaryService found from the OSGi registry (that is, for every DictionaryService you |
| 113 | create from web console "Dictionary Services" configuraton section). |
| 114 | |
| 115 | - DictionaryAspectPID configuration: this is the config pid our DictionaryAspect is depending on (see |
| 116 | @ConfigurationDependency in DictionaryAspect.java). |
| 117 | |
| 118 | - org.osgi.service.log.LogService: the DictionaryAspect is optionally depending on the log service |
| 119 | (a null object is used if there is no one). |
| 120 | |
| 121 | So, when a DictionaryService will come up, the AspectServiceImpl component will instantiate a |
| 122 | corresponding "DictionaryAspect" instance, with all the dependencies defined in DictionaryAspect. |
| 123 | |
| 124 | 5) Create a DictionaryService from web console: |
| 125 | |
| 126 | Go to web console: in the Configuration panel, edit the "Dictionary Services" Configuration, and add |
| 127 | some dictionaries. By default, an English dictionary is displayed. Just click on "save", *then click |
| 128 | on your refresh web browser*: you will see a new dictionary service instance. At this point, a |
| 129 | "DictionaryImpl" component instance will be create (with the service property "lang=en"), and the |
| 130 | SpellCheck component will be injected with it (the DictionaryImpl implements |
| 131 | DictionaryService). Then you should see the "spellcheck" command, when typing "help" on the gogo |
| 132 | shell. |
| 133 | |
| 134 | 6) test the spellchecker under gogo shell: |
| 135 | |
| 136 | Just type "spellcheck hello", and the command should reply a fantastic message, like "word hello is |
| 137 | correct". |
| 138 | |
| 139 | 7) Inspect again DependencyManager components from the shell: |
| 140 | |
| 141 | Type again "dm 5", for browsing the components coming from our bundle id 5: |
| 142 | |
| 143 | [5] org.apache.felix.dependencymanager.samples.annotation |
| 144 | org.osgi.service.cm.ManagedServiceFactory(service.pid=DictionaryImplFactoryPid) registered |
| 145 | org.osgi.service.log.LogService service optional available |
| 146 | org.apache.felix.dm.samples.annotation.SpellChecker(osgi.command.function={spellcheck},osgi.command.scope=dmsample.annotation) registered |
| 147 | org.apache.felix.dm.samples.annotation.DictionaryService service required available |
| 148 | org.osgi.service.log.LogService service optional available |
| 149 | org.apache.felix.dm.impl.AspectServiceImpl$AspectImpl@128edf2 unregistered |
| 150 | org.apache.felix.dm.samples.annotation.DictionaryService (&(!(org.apache.felix.dependencymanager.aspect=*))(lang=en)) service optional unavailable |
| 151 | DictionaryAspectPID configuration required unavailable |
| 152 | org.osgi.service.log.LogService service optional unavailable |
| 153 | org.apache.felix.dm.samples.annotation.DictionaryService(service.pid=DictionaryImplFactoryPid.e01b70ff-d2b5-4305-9e86-84c68a2fddbb,service.factoryPid=DictionaryImplFactoryPid,lang=en) registered |
| 154 | org.osgi.service.log.LogService service optional available |
| 155 | |
| 156 | Here, you can see the following: |
| 157 | |
| 158 | * the org.osgi.service.cm.ManagedServiceFactory with factory pid "DictionaryImplFactoryPid" is now |
| 159 | registered, because we have created a dictionary from config admin (in the Dictionary Services" |
| 160 | webconsole configuration section). |
| 161 | |
| 162 | * the SpellChecker is now "registered" because it has been injected with the DictionaryImpl we have |
| 163 | created from webconsole. |
| 164 | |
| 165 | * the AspectServiceImpl$AspectImpl is not yet registered because we still have to instantiate a |
| 166 | configuration from webconsole for the "DictionaryAspectPID" PID: this configuration is required to |
| 167 | instance our DictionaryAspect component (see the @ConfigurationDependency annotation in |
| 168 | DictionaryAspect.java). |
| 169 | |
| 170 | * One instance of the DictionaryService component is now registered (this instance corresponds to |
| 171 | what we just configured from webconsole, in the "Dictionary Services" section). |
| 172 | |
| 173 | 8) Finally, activate the "Aspect Dictionary" component: |
| 174 | |
| 175 | To do so, you can click on the "Aspect Dictionary" button, from web console Configuration section, |
| 176 | in order to decorate the english dictionary with some custom words. By default, the "aspect" word is |
| 177 | pre configured, but you can click on the "+" button in order to add more words. Then click on |
| 178 | Save. At this point, the English DictionaryService will be decorated with the aspect service. So, |
| 179 | now, if you type "spellcheck aspect", then the message: "word aspect is correct" should be |
| 180 | displayed. What is going on is that the original DictionaryService will be replaced by the |
| 181 | DictionaryAspect, using a higher service.ranking (ranking 10, see DictionaryAspect.java). So the |
| 182 | spell checker will be transparently re-injected with the DictionayAspect, which is from his side |
| 183 | depending on the originial DictionaryService. |
| 184 | |
| 185 | So, if you type "dm 5", you will know see two DictionaryService instances: |
| 186 | |
| 187 | org.apache.felix.dm.samples.annotation.DictionaryService(service.pid=DictionaryImplFactoryPid.8390ad56-b2de-4414-9123-29c65c42e5b9,service.factoryPid=DictionaryImplFactoryPid,lang=en) registered |
| 188 | org.osgi.service.log.LogService service optional available |
| 189 | |
| 190 | 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 |
| 191 | org.apache.felix.dm.samples.annotation.DictionaryService (&(|(!(service.ranking=*))(service.ranking<=9))(|(service.id=57)(org.apache.felix.dependencymanager.aspect=57))) service required available |
| 192 | DictionaryAspectPID configuration required available |
| 193 | org.osgi.service.log.LogService service optional available |
| 194 | |
| 195 | The first one is the original DictionaryService we have created using the factory pid |
| 196 | "DictionaryImplFactoryPid" from web console. By default, the ranking of this service is 0. |
| 197 | |
| 198 | Next, you see the new DictionaryService which corresponds to our DictionaryAspect service. It has |
| 199 | the following properties: |
| 200 | |
| 201 | * it has inherited from all service properties found from the original intercepted DictionarService. |
| 202 | * it has a higher service ranking than the original one (see service.ranking=10). This ranking is |
| 203 | actually defined in DictionaryAspect.java, in the @Aspect annotation. |
| 204 | * it has a dependency over the original DictionaryService (using an appropriate filter). |
| 205 | * it also inherits from all dependencies originally defined in the DictionaryImpl component |
| 206 | |
| 207 | |
| 208 | |
| 209 | |