You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UsingDeclarativeServices.asciidoc 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. ---
  2. title: Using Declarative Services
  3. order: 74
  4. layout: page
  5. ---
  6. [[using-declarative-services]]
  7. Using declarative services
  8. --------------------------
  9. Declarative Services (DS) are very common to define OSGi services. The
  10. DS bundle scans all bundles (extender pattern), parses the component
  11. definition xml-file and provides services based on that information. DS
  12. may also be used to define references to other services. For instance
  13. service A may require 0:n services of type B. The DS runtime will
  14. ensure, that they are properly injected into the service A. References
  15. to other services also influence the lifecycle of a service. For
  16. instance service A requires 1:1 of service C. Thus service A will not be
  17. activated before service C is injected properly. This short overview of
  18. OSGi-DS is enough to understand the example defined below.
  19. [[setup-example]]
  20. Setup example
  21. ~~~~~~~~~~~~~
  22. To follow my explanation
  23. * clone repository from
  24. https://github.com/lunifera/lunifera-Vaadin-examples.git
  25. * use Import -> "Existing Maven Projects" in Eclipse IDE (Make sure that
  26. m2e is installed)
  27. * expand `org.lunifera.example.Vaadin.osgi.bootstrap.ds/setup` and set
  28. `targetDS.target`
  29. * `open targetDS.target`
  30. ** wait until resolved
  31. ** if error, then select all repository in target and press update
  32. button on the right side
  33. ** wait until resolved
  34. ** press "set as target platform"
  35. * Now there should be no problems.
  36. * To build the project use `mvn clean verify`
  37. You will recognize that the bundle does not contain an `Activator`. Thats
  38. not necessary since we use OSGi services managed by OSGi-DS. The
  39. component runtime of DS manages the lifecycle of the services. Instead
  40. of an activator we are using the class `ServiceComponent`. It contains all
  41. logic to wire things together properly.
  42. [[servicecomponent]]
  43. ServiceComponent
  44. ~~~~~~~~~~~~~~~~
  45. The service component will become instantiated by OSGi DS and DS
  46. controls its lifecycle. If the bundle containing the class is stopped,
  47. the service will be deactivated by invoking `deactivate()`. If mandatory
  48. references can be resolved, the service will be activated automatically. The `bindService` and `unbindService` are invoked by DS,
  49. if a http service becomes available or unavailable. We do not need to
  50. use a `ServiceTracker` anymore to get notified about the
  51. `HttpService`-lifecycle. All that stuff is handled by OSGi-DS.
  52. [source,java]
  53. ....
  54. package org.lunifera.example.Vaadin.osgi.bootstrap.ds;
  55. import javax.servlet.ServletException;
  56. import org.osgi.framework.Bundle;
  57. import org.osgi.framework.BundleEvent;
  58. import org.osgi.framework.BundleListener;
  59. import org.osgi.service.component.ComponentContext;
  60. import org.osgi.service.http.HttpService;
  61. import org.osgi.service.http.NamespaceException;
  62. /**
  63. * The service will look for the HttpService and registers the Vaadin servlet at
  64. * it.
  65. */
  66. public class ServiceComponent implements BundleListener {
  67. private HttpService httpService;
  68. private ResourceProvider resourceProvider;
  69. /**
  70. * Called by OSGi DS if the component is activated.
  71. *
  72. * @param context
  73. */
  74. protected void activate(ComponentContext context) {
  75. handleStartedBundles(context);
  76. context.getBundleContext().addBundleListener(this);
  77. }
  78. /**
  79. * Called by OSGi DS if the component is deactivated.
  80. *
  81. * @param context
  82. */
  83. protected void deactivate(ComponentContext context) {
  84. context.getBundleContext().removeBundleListener(this);
  85. resourceProvider = null;
  86. }
  87. /**
  88. * Binds the http service to this component. Called by OSGi-DS.
  89. *
  90. * @param service
  91. */
  92. protected void bindHttpService(HttpService service) {
  93. httpService = service;
  94. try {
  95. // register the servlet at the http service
  96. httpService.registerServlet("/", new SimpleVaadinServlet(), null,
  97. getResourceProvider());
  98. } catch (ServletException e) {
  99. e.printStackTrace();
  100. } catch (NamespaceException e) {
  101. e.printStackTrace();
  102. }
  103. }
  104. /**
  105. * Unbinds the http service from this component. Called by OSGi-DS.
  106. *
  107. * @param service
  108. */
  109. protected void unbindHttpService(HttpService service) {
  110. // unregister the servlet from the http service
  111. httpService.unregister("/");
  112. }
  113. ....
  114. If a http service is available, it becomes injected and will be used to
  115. register the Vaadin servlet at it. If it becomes unbound (bundle
  116. containing the http service stopped), the servlet will be unregistered.
  117. [[usecase-study]]
  118. Usecase study
  119. ~~~~~~~~~~~~~
  120. Imagine the following usecase. There are 2 bundle providing http
  121. services.
  122. * `org.abc.http.jetty`
  123. * `org.abc.http.tomcat` (can be achieved using virgo for instance)
  124. [[what-you-may-do...]]
  125. What you may do...
  126. ^^^^^^^^^^^^^^^^^^
  127. * Start the jetty bundle → then jetty-httpService will be bound to our
  128. service component and Vaadin is running on a jetty
  129. * Start the tomcat bundle → nothing will happen so far (service
  130. component requires 0:1 http services - see below)
  131. * Stop the jetty bundle → The jetty-httpService will become unbound and
  132. Vaadin stops
  133. * Some milliseconds later the tomcat-httpService will be bound
  134. automatically → Vaadin will become installed to the tomcat
  135. * Update the jetty bundle in the running OSGi environment (new bundle
  136. with latest version is installed and old uninstalled)
  137. * Start the jetty bundle (with the new version) again
  138. * Stop tomcat bundle → The tomcat-httpService will become unbound and
  139. Vaadin stops
  140. * Some milliseconds later the jetty-httpService will be bound
  141. automatically → Vaadin will become available at jetty
  142. That’s real modularity... Give it a try and play around. Indeed, you
  143. won't write your own http services. But there are a lot of other use
  144. cases too. I will blog about them later when I am talking about "Content
  145. Provider by OSGi DS".
  146. [[servicecomponent-definition]]
  147. ServiceComponent-Definition
  148. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  149. The service component definition is the description about the service.
  150. It defines the implementation class, the provided services and the
  151. referenced (required) services. Eclipse PDE comes with an editor to
  152. define them. Expand the `OSGI-INF` folder in the bundle and double click
  153. `VaadinComponent.xml`. Now you see the definition of the service
  154. component.
  155. [source,xml]
  156. ....
  157. <?xml version="1.0" encoding="UTF-8"?>
  158. <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.lunifera.example.Vaadin.osgi.bootstrap.ds">
  159. <implementation class="org.lunifera.example.Vaadin.osgi.bootstrap.ds.ServiceComponent"/>
  160. <reference bind="bindHttpService" cardinality="0..1" interface="org.osgi.service.http.HttpService"
  161. name="HttpService" policy="dynamic" unbind="unbindHttpService"/>
  162. </scr:component>
  163. ....
  164. * Line 2 defines the name of the service. Feel free to insert a unique
  165. name
  166. * Line 3 defines the class name of the service class that needs to
  167. become instantiated
  168. * Line 4 defines a reference to a required service - the HttpService
  169. * *bind* means the method that is called to bind the HttpService
  170. instance to the service instance
  171. * *unbind* means the method that is called to unbind the HttpService
  172. instance from the service instance
  173. * *cardinality* defines how many services may / must be bound - 0..1,
  174. 1..1, 0..n, 1..n
  175. * *interface* is the name of the service that should be bound
  176. A *very important* issue is an entry in the `MANIFEST.mf`. Using the
  177. manifest header `Service-Component: OSGI-INF/*.xml` all xml files from
  178. OSGI-INF are registered as component definitions to the DS runtime. If
  179. you miss to add this statement, DS will never resolve your service!
  180. [[run-example]]
  181. Run example
  182. ~~~~~~~~~~~
  183. To run the example, we need to prepare an OSGi-launch-configuration. The
  184. following bundles are required to run the example properly. In
  185. difference to part 1, the `org.eclipse.equinox.ds` and
  186. `org.eclipse.equinox.util` bundles are required. Otherwise OSGi-DS will
  187. not become started.
  188. [cols=",,",options="header",]
  189. |============================================================
  190. |bundle |start level |autostart
  191. |org.lunifera.example.Vaadin.osgi.bootstrap.ds |default |true
  192. |com.Vaadin.client-compiled |default |false
  193. |com.Vaadin.server |default |false
  194. |com.Vaadin.shared |default |false
  195. |com.Vaadin.shared.deps |default |false
  196. |com.Vaadin.themes |default |false
  197. |javax.annotation |default |false
  198. |javax.servlet |default |false
  199. |org.apache.felix.gogo.command |default |false
  200. |org.apache.felix.gogo.runtime |default |false
  201. |org.apache.felix.gogo.shell |default |false
  202. |org.eclipse.equinox.console |default |false
  203. |org.eclipse.equinox.ds |1 |false
  204. |org.eclipse.equinox.http.jetty |default |false
  205. |org.eclipse.equinox.http.servlet |default |false
  206. |org.eclipse.equinox.util |default |false
  207. |org.eclipse.jetty.continuation |default |false
  208. |org.eclipse.jetty.http |default |false
  209. |org.eclipse.jetty.io |default |false
  210. |org.eclipse.jetty.security |default |false
  211. |org.eclipse.jetty.server |default |false
  212. |org.eclipse.jetty.servlet |default |false
  213. |org.eclipse.jetty.util |default |false
  214. |org.eclipse.osgi |default |false
  215. |org.eclipse.osgi.services |default |false
  216. |org.json |default |false
  217. |org.jsoup |default |false
  218. |============================================================
  219. To start a jetty server on a proper port, use the VM argument:
  220. `-Dorg.osgi.service.http.port=8082` in your launch configuration. Now
  221. you can access the Vaadin page under http://localhost:8082. Have fun!
  222. By http://de.gravatar.com/florianpi[Florian Pirchner] - based on
  223. lunifera.org - OSGi components for business applications