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.2KB

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