Skip to main content
  1. My Blog posts/

Dependency resolution

·521 words·3 mins·
medium osgi
Víctor (Bit-Man) Rodríguez
Author
Víctor (Bit-Man) Rodríguez
Algorithm Junkie, Data Structures lover, Open Source enthusiast

Dependency resolution #

The purpose of this post is to be able to reproduce different dependency resolution scenarios and experience how they affect object behaviour. It is located inside folder chapter02/dependency-resolution (look at repository commit ea2e00026c1eb44f4dd37518a94a0e6ce97f1a2f)

Simple scenario is fine #

Let’s start with an already known scenario, named simple, where there is one producer and two consumers : Client and Client0

  • Client0 : access our sayHello() friend, a deprecated method and imports org.foo.hello version 1.0

  • Client : access only sayHello() and imports org.foo.hello version 1.0 to 3.0 included

When executed this first scenario (cd chapter02/dependency-resolution && ./run simple) can be seen that Client and Client0 access all the previously named methods flawlessly

org.foo.hello.client.Client : Trying to access new provider
org.foo.hello.client.Client : * does it shows ‘DEBUG messages’ ?
Hello, dependency-resolution!
org.foo.hello.client.Client0 : Trying to access provider
Hello, client0!
I’m deprecated, poor of me :-(  

As a side note take a look at Client0 pom.xml on how it was implemented the new2 import package scenario

Let’s mess things up #

For the next scenario, named new, a new provider is introduced that implements our old Greeting friend but exporting it as version 2.0 and no implementation for method deprecated().

Running this new scenario (cd chapter02/dependency-resolution && ./run new) produces the next output :

Exception in thread “main” java.lang.NoSuchMethodError: org.foo.hello.Greeting.deprecated()V
at org.foo.hello.client.Client0.bornToCrash(Client0.java:27)


    at org.foo.hello.client.Client0.(Client0.java:17)  
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)


    at java.lang.Class.newInstance(Class.java:374)  
    at org.foo.hello.main.Main.main(Main.java:51)  

This happens because the deprecated() method is not implemented and the version for Client0 was specified as version=”1.0" which means “use version 1.0 onwards” then the new provider was accepted when it shouldn’t. To fix it specifying only version 1.0 for Client0 the import package version directive should look like this : version=”[1.0,1.0]” This is a common error and can be seen in “OSGi in Action” book :

no alternate text for image

If you want to specify a precise version range, you must use a version range like

Run it with new2 and everything will be fine.

Make it a bit more dynamic #

Ia the dynamic scenario the previous ones were put together and can be seen how the things are messed during execution, meaning that in a first phase the simple scenario is used and in a second phase the new scenario is run but with a very permissive version numbering.

Seems to be a silly test because is a combination of previous scenarios but in this new one I wanted not to probe the version conflict resolution but the flexibility of OSGi framework for being able to manage different bundle versioning on the fly. Let’s take a look at the code that manages this :

// Both consumers consume the only available provider
provider = context.installBundle(“file:bundles/provider-1.0.jar”);
consumer = context.installBundle(“file:bundles/consumer-1.0.jar”);
consumer0 = context.installBundle(“file:bundles/consumer0–1.0.jar”);


    // Irrelevant code  
    m_framework.start();  
    // Uses dynamic loading to show behavior change  
consumer.loadClass(“org.foo.hello.client.Client”).newInstance();
consumer0.loadClass(“org.foo.hello.client.Client0”).newInstance();
// Installs new provider and updates both consumers
// Must update consumers and start new bundle because the framework has already been started
newProvider = context.installBundle(“file:bundles/newProvider-1.1.jar”);


newProvider.start();  
consumer.update();  
consumer0.update();  
// Some more irrelevant code  
m_framework.stop();  

Hope you enjoyed this post and hope you became a fan of this OSGi series!!