xconspirisist
xconspirisist

Reputation: 1461

Getting started with bundle DI in an OSGi environment

I have been developing an application with Apache Felix as my OSGi runtime for a while and up until now progress has been great. However, I want to now adopt dependancy injection and the "default" mechanism with Apache Felix seems to be iPOJOs.

However, I've found that the documentation and tutorials around about Apache felix are too weak and I've not managed to get anywhere. So I am prepared to change, but first of all I'd better explain the (very simple) think I'm trying to do.

Given two bundles;

Consumer bundle

package bundles.consumer;

class Consumer implements BundleActivator{
    @Inject
    private Producer producer;

    public void bundleActivated(BundleContext con) {
        this.producer.getNextItem();
    }
}

Producer Bundle

package bundles.producer;

@Singleton
class Producer {
    public String getNextItem() {
        return "item x"; 
    }
}

I want the OSGi runtime to start up the Consumer bundle, realize that it needs a Producer to work, the framework then starts the Producer bundle and injects and instance into the Consumer. Simples. iPOJOs suggest that this is possible using annotations only (@Singleton, @Inject) or similar, but I simply can't get it to work. OSGi apparently has declarative services, but that means writing a lot of XML, which I really want to avoid.

Anywoo, I'm prepared to adapt JBoss, Equinox or alternative OSGi runtime and an alternative dependancy injection mechanism, be that Peaberry, Spring DM or something completly difference. I'm already using Maven.

What I'm asking, is can somebody create a Hello World using the Producer and Consumer idea to help me get started? I've really spent a tonne of time reading up and find the learning curve insurmountable!


edit, my attempt using SCR: http://tydus.net/codeExamples/mvnScr.tar

Upvotes: 0

Views: 2038

Answers (3)

earcam
earcam

Reputation: 6682

There are two things to bear in mind; 1) your bundle will probably need some extra metadata for the dependency injection framework and 2) you'll need to deploy the DI framework's runtime.

Dependency injection is not part of core OSGi (i.e. the Felix framework) so you must first deploy the iPOJO bundle(s) before deploying your own. Additionally you'll need to add the metadata required by IPOJO, google "maven-ipojo-plugin" for more info.

If you're looking for a container that is less bare-bones than Felix on it's own, then try Karaf (it comes with lots of enterprise extras).

Personally, I like Declarative Services (so +1 Dmytro) as it's very simple and merely removes the boiler plate code from OSGi (remember to deploy it as well and provide component.xml in your bundle see maven-scr-plugin for more info).


EDIT

(In answer to comment and link to tarball below)

I moved the @Service annotation from Producer to ProducerImpl.

The generated SCR component.xml wasn't quite correct for the Consumer, by adding an unbind() method and changing the @Reference the following works:

//...
import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY;
import static org.apache.felix.scr.annotations.ReferencePolicy.DYNAMIC;

//...
@Component
public class Consumer
{
    @Reference(policy = DYNAMIC, cardinality = MANDATORY_UNARY)
    private Producer producer;

    public void unbindProducer() {
        System.out.println("Producer unbound.");
        this.producer = null;
    }
//...
}

Deploying Maven

As you're using maven, install Pax Url for maven, this way you can easily install bundles from local and remote repositories.

First get maven to download a version for you (pax-url-mvn version 1.3.5 is available) then install the file (or copy to Felix bundle dir)

-> install file:/YOUR_PATH_TO_MAVEN_REPO/.m2/repository/org/ops4j/pax/url/pax-url-mvn/1.3.5/pax-url-mvn-1.3.5.jar
Bundle ID: 7
-> start 7
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=javax.net.ssl) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=javax.xml.parsers) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework)(version>=1.0.0)(!(version>=2.0.0))) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.service.cm)(version>=1.0.0)(!(version>=2.0.0))) -> [2.0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.service.url)(version>=1.0.0)(!(version>=2.0.0))) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=org.w3c.dom) -> [0]
DEBUG: WIRE: [7.0] osgi.wiring.package; (osgi.wiring.package=org.xml.sax) -> [0]
-> 

You can now install your own bundles from your local repository with the mvn URL handler:

-> install mvn:com.examples/producer/1.0.1
Bundle ID: 10
-> start 10
-> install mvn:com.examples/consumer/1.0.1     
Bundle ID: 11
-> start 11
DEBUG: WIRE: [11.0] osgi.wiring.package; (&(osgi.wiring.package=com.examples.producer)(version>=1.0.0)(!(version>=2.0.0))) -> [10.0]
Producer bound.
Consumer activate
Aloha.
-> 

Upvotes: 1

Tassos Bassoukos
Tassos Bassoukos

Reputation: 16142

I've written a fragment for the Equinox Declarative Services bundle that allows you to mark up your classes with annoations that correspond to DS servicce XML elements; yes, it's a hack with its own limitations, but it's working good so far in projects with 90+ bundles. I could probably manage to clean it up, document and publish it this week if you are interested.

Upvotes: 0

Dmytro Pishchukhin
Dmytro Pishchukhin

Reputation: 2369

It's better to use Declarative Service because it's a OSGi Standard.

You can use Java Annotations to describe DS dependencies, services and components with Maven SCR plugin

Regards, Dmytro

Upvotes: 2

Related Questions