Skip to content

Latest commit

 

History

History
108 lines (81 loc) · 6.31 KB

WORKSHOP-INSTRUCTIONS-PART-2.md

File metadata and controls

108 lines (81 loc) · 6.31 KB

Part 2 Instructions

Create a service provider and register it with Blueprint

Blueprint is component management container. That probably doesn't mean much to you; it doesn't mean much to me.

Blueprint is used to to create Java objects and publish them to the OSGi service registry. Instead of writing Java code to do this, Blueprint is written in XML. When the OSGi runtime loads a bundle, the Blueprint container looks for the blueprint.xml file and uses that information to construct objects and register them.

Create the service provider
  1. (Step 1 is optional). Read more about Blueprint
  2. In IntelliJ, create a new module named impl
  3. In the new module, create a Java class named GreetingImpl that implements the Greeting interface (Add the api module as a maven dependency so that the class GreetingImpl can see the interface Greeting).
  4. Implement the hello method. Copy it from the source code here
  5. Do not leave the class in the default package. OSGi relies heavily on package names. Use the package directive to make the interface part of a real package. For simplicity, use the package name impl.
  6. Add the maven bundle plugin to the POM. Feel free to copy it from here
  7. Test your work by building the module with mvn install

NOTE: I had two errors in my POM.xml file.

  1. First, I forgot to add <packaging>bundle</packaging> to POM.xml. The results was the the MANIFEST.MF file in the JAR was missing the OSGi headers and the JAR could not be installed in Karaf.
  2. Second, I was missing <extensions>true</extensions> from the maven bundle plugin definition. The result was the maven did not recognize the bundle packaging type. `
Create the blueprint specification file
  1. Locate the resources directory under the impl/src/main/... path.
  2. Create a subdirectory of resources named OSGI-INF. Spelling matters.
  3. Create a subdirectory of OSGI-INF named blueprint. (IntelliJ might annoyingly display the nested directories as OSGI-INF.blueprint)
  4. Now create a file named blueprint.xml in the blueprint directory.
  5. Open the blueprint.xml file and paste in this boilerplate:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
            
</blueprint>

Congratulations! You've succeeded doing busy-work. Gold star for diligence!

Define the GreeterImpl bean and register the service

A bean is just a Java object. But some Java library referred to as a container decides when to create the object, and when to destroy the object. That is all.

Tell the Blueprint container to create (and name) and instance of the GreetingImpl class. Add this XML snippet in the <blueprint> element.

<bean id="greetingImpl" class="impl.GreetingImpl"/>

WARNING: The first time I did this, I messed it up. I copied and pasted class="com.connexta.impl.GreetingImpl", but my package name was impl; I had dropped the com.connexta part in my Java code. This lead to unsatisfied requirements when I tried to start the packager in Karaf. Karaf was looking for com.connexta.impl.GreetingImpl when it should have been looking for impl.Greeting.

Blueprint only needs two pieces of information to register a bean: the ID to use for the bean, and the class. Blueprint is more flexible than this. You can specify constructor arguments, default values, and other information. None of this is necessary for this bean.

To turn the bean into an OSGi service, a single line of XML needs to be added:

<service ref="greetingImpl" interface="api.Greeting"/>

Three things going on there:

  1. The keyword service tells Blueprint to register a service provider
  2. The ref="greetingImpl" tells Blueprint the greetingImpl bean provides (implements) the service.
  3. The interface="com.connexta.api.Greeting" tells Blueprint that the bean is providing the service defined by the interface Greeting.

The big take aways are:

  1. The service is the contract or interface.
  2. The bean is the Java object that implements the interface.
  3. There is no limit to number of classes that can implement the service interface and register themselves as service providers.
  4. When you consume an OSGi service, OSGi will ultimately hand the bean named greetingImpl to the consumer.
  5. Regardless of who asks for the service, the requester will always get the same instance of GreeterImpl; a service consumer has to share the same object with every other service consumer. Be aware this can cause issues for multi-threaded applications.
  6. Services are not uniquely named. A service has its interface type. A service consumer typically tells the OSGi runtime to "give me all the providers that implement service X". In more advanced use, properties are defined when the service is registered, and the OSGi runtime can be be given a filter that looks at a service provider's properties to decide if the service provider should be handed to a consumer.

Exercise

  • Use mvn install to create the bundle

  • Start Karaf and use install or the deploy folder to start the bundle.

  • The bundle should install successfully, but fail to start

  • Read the entire failure message. What does it tell you? (If you could start the bundle successfully, find someone who did get an error message and try to determine why it succeeded for you).

  • Use Karaf console commands list headers to probe the bundle failure. It's much error to read than the debug message on the console.

  • Solve the problem and then start the bundle

  • Probe the bundle(s) with the commands headers and capabilities

ALTERNATE SOLUTION (spoiler alert)

  • When I coded the solution, I didn't bother to turn the api module into a bundle. When I hit the error, I solved it a different way.
  • Instead, I embeded it in the impl bundle. I added the this instruction to the maven bundle plugin configuration fro the impl module: <Embed-Dependency>api</Embed-Dependency>
  • The word embed is a bit clue about what this instructions does. If you have time, try this out. Unzip the impl JAR file and have a look. Can you see what the embed instruction changed inside the JAR.