I have two bundle,X and Y.Both of them were installed and active as bundle on OSGi.Function sayHello in Bundle X and function writeHello in Bundle Y.I need to call sayHello function from Bundle Y and I will write returned string with writeHello function in Bundle Y.
Can you say that it is possible or not?If it is possible how can deploy this logic?
In my mind,I have something for example;
I will add dependency of Bundle X in pom of Bundle Y,but how can I see function sayHello after adding dependency?
Thank you..
There are two ways to access a functionality of another bundle. For both ways you need an Export-Package in the bundle offering the class and an Import-Package for the package of the external classes you want to use.
Create an instance of the class and use it
Use this approach if the class you want to use is simple to setup and you do not need decoupling. This is a typical case for simple libraries.
Publish the functionality as an OSGi service and bind the service
Use this approach if it is difficult to instantiate the class and you do not want the client to be involved with this. The service approach also makes sense if you want to decouple from the implementation. To achieve this you create an interface for the functionality and publish the service with the interface. The client can then bind the service by specifying only the interface.
Related
Suppose a Prism version 8 WPF module has a ViewModel which needs to call on a service.
the service implements IService, but there exists a number of implementations of this service. Each implementation is a file (class library), possibly as a IModule (see below).
The user shall be able to configure which file to use either by configuration or by a folder's content.
Obviously(?) I am thus thinking of Module discovery by creating the right type of ModuleCatalog while "bootstrapping" the application and the service could thus be contained in this module.
If the call is a void call ("fire-and-forget") I guess I could simply use EventAggregator (implementing the service as an observer), however the call returns a value.
What is the best approach solving this?
(I would like to avoid writing my own assembly "discovering/loading" of some kind of a swappable service implementation dll file)
If you can inject IEventAggregator, you can inject IService, can't you?
If no module registered an implementation, you'll get an exception. If more than one module did, the last one wins (with unity as container, at least).
I have two OSGi bundles A and B. Both are created with the API/implementation model. Both the bundles are activated through Blueprint mechanism. Both the API bundles export the interfaces whereas the implementation bundles don't export anything. Only A has dependency on B.
My issue is, I want to pass a resource file name (xml file) that resides in bundle A to Bundle B (after I get hold of B using the BundleContext.getServiceReferences() method) and then load the resource in Bundle B and process it. How can I achieve the same and is it even doable?
I read the following post and Neil Bartlett's answer suggest it should work.
Access resources in another osgi bundle?
However, when I read about getEntry, findEntries, getEntrypath methods, they don't talk about other bundles (or I misunderstood it). They talk only about fragments.
My question is, can I achieve what I am looking for using any of the above three methods? If so, can you please point to some other thread that has the answers or some sample code?
If this is not possible, can I use fragment bundles(containing only resources)? Again Bundle B is more like a provider where it can take any resource file and process it and satisfy clients requests (Bundle A). So even if I want to use bundle fragment approach, I need B to load the fragment bundle (only on needed basis) specified by clients (say they give the fragment bundle symbolic name). Please provide suggestions or other posts related to similar issues or any samples.
The easiest way to access a resource in a bundle is to use the classLoader of the bundle. In bundle A you get service MyService and do:
InputStream is = this.getClass().getResourceAsStream("myresource.xml");
MyService service.doSomething(is);
or if you prefer a URL:
URL url = this.getClass().getResource("myresource.xml");
MyService service.doSomething(url);
This works as we already resolve the resource before making the call. If you want to give the service just a relative path then you additionally need to give it the classLoader to get the resource from.
ClassLoader bundleALoader = this.getClass().getClassLoader();
MyService service.doSomething(bundleALoader, "myresource.xml");
Keep in mind though that this.getResource() will lookup the resource relatively to the package of "this" while classLoder.getResource() will lookup from the top of the name space.
Btw. These concepts also work fine outside of OSGi. The difference is only that in OSGi you have to make sure to use the classLoader that has visibility of a resource while outside there is often only one classLoader that sees all resources.
My application obtains class names from a properties file. Classes represented by these class names could reside in certain OSGI bundles unknown at advance so in order to instantiate them I firstly have to find which bundle these classes belong to. I'm thinking about getting all installed bundles from BundleContext#getBundles, this means I have to obtain reference to BundleContext in AbstractUIPlugin#start. But I'm not sure if holding reference to BundleContext is the right thing to do since it's should be used only in the start method. So I need advice from OSGI experts here about the alternatives to get list of bundles.
Any help would be greatly appreciated.
Regards,
Setya
This is not really how OSGi is intended. If a bundle has something to add to the 'global' context, you should register a service. So each bundle that has something to share can do that in its own start method.
Some other component (DS, ServiceTracker, Blueprint, something like that) can then listen to these events, and act accordingly.
This is really important, if you start manually searching through all bundles you completely lose the advantages of OSGi.
Like written before you should try to use services to achieve what you want. I guess you have an Interface with one or more implementations that should be installable at runtime. So if you control the bundles that implement the interface then simply let them install their implementation as a service by using an Activator or a blueprint context. You can use service properties to describe your implementation.
The bundles that need the implementation can then lookup the services using a service tracker or a service reference in blueprint.
If that is not possible then you can use the bundle context to obtain the running bundles and instantiate the classes but this is not how OSGi should work. You will run into classloading problems as the bundle that tries to instantiate the classes will not have direct access to them.
Your bundle gets control at start up through the bundle activator, or better, through DS. At that time it can register services with the services registry so others can find/use them.
The route your planning to go (properties that name classes) is evil since you undoubtedly will run in class loading hell. Modularity is about hiding your implementation details, the name of your implementation classes are such details.
Exposing implementation classes in properties files is really bad practice and it looses the advantage of modularity. It does not matter if another class refers to your implementation class or a property file, the problem is that the impl. class is exposed.
Unfortunately this model has become so prevalent in our industry that many developers think it is normal :-(
OSGi allows you share instances typed by interfaces in a way that allows the implementation class to only be known inside the module.
I have a class with dependencies which I want to hot deploy without restarting the dependencies. The class has an interface but there's only one concrete implementation.
Initially I created a single bundle with exported the interface and registered the implementation using activator and implementation classes which were not exported. However, if I update the bundle, bundles which use the registered service get restarted after the update when PackageAdmin#refreshPackages is called (this is automatic when using fileinstall).
I have fixed this by creating a separate api bundle.
Is this the best way to achieve this?
Would you ever have a bundle which exports its api and includes the implementation in the same bundle. As far as I can see any give bundle would either export all its classes or no classes. What am I missing?
It is definitely a best practice to separate API bundles from their implementations in OSGi. If you do this, then any bundle that uses the API only needs to import classes from the API bundle, which can allow you to change implementations at runtime without restarting your dependent bundles.
Ideally your implementation bundle would implement the interface and export implementation as a service on the API provided interface. This allows the client bundles to utilize the service without referencing the implementation bundle.
In Apache Sling we do both: major APIs are in their own bundles, but for smaller things like extensions or optional components we often provide the default implementation in the same bundle as the API.
In the latter case, you can still allow for those default services to be replaceable, for example using service ranking values when you want to override them.
A bundle does not have to export all its classes, our bundles which include default services export just the API packages (and the default implementations are in different packages, obviously).
Unless there is a hard requirement to be able to replace implementation at runtime, without restarting client bundles, I would personally advocate keeping the explicit dependency link between API and implementation (either by including impl classes in the API bundle, or by having the API bundle import implementation packages from the impl. bundle).
The pb with the patterns suggested above is that they break the dependency chain. The benefits of dependency management go far beyond simple API compatibility, they also include ensuring predictable, consistent runtime behavior, as well as compatibility with the deployment ecosystem, and all of those require managing the implementation dependencies.
In the end i will perhaps provide a helper so that the activator can import and export services and other types of meta data about the system.
By parameters i mean objects in general, perhaps via a map. it would be great if one bundle when installing another had a mechanism to send parameters to the starting bundle. I suppose i could include a service on the later bundle and use it as a configuration service but that seems a bit unelegant.
If you want to "send" some configuration parameters to a starting bundle you can use standard OSGi services like Configuration Admin Service. If you want to pass around arbitrary objects you should probably use OSGi service registry.
Could you please clarify your question? What you mean by "host" bundle and "embedded" bundle? What kind of "helper" do you want to provide? Most importantly what kind parameters you want to pass from one bundle to another?
To do (pre-) runtime configuration of a bundle, you should use the Configuration Admin Service. For pojos etc you can follow this pattern:
Bundle A installs and starts Bundle B
Bundle B registers a "configuration" service, e.g. with the interface acme.ConfigureB.
Bundle A tracks services with the interface acme.ConfigureB.
Whenever A receives the tracker callback for acme.ConfigureB it does all the necessary configurations.