I'm getting a little lost when dealing with embedding OSGi into an application/library, loading a bundle at runtime and then using that bundle in the host application/library.
This is code to load the bundle from my host:
// framework is the embedded OSGi framework
Bundle b = framework.getBundleContext().installBundle( "file:/project_dir/bundle/MyBundle.jar" );
b.start();
And the bundle consists of something really simple:
public class Activator implements BundleActivator
{
@Override
public void start( BundleContext context )
{
}
@Override
public void stop( BundleContext context )
{
}
public String shout()
{
return "let it all out";
}
}
How would I access the shout() method from the host application?
In short:
More detailed solution:
Alternatively, if you do not have the interface in the application/library, you can still get the OSGi service and call the function using reflection.
Here are some details about the code to use following the previous answer:
The interface containing your method.
public interface MyInterface { String shout(); }
You can notice that it's a good approach to have two bundles for your library: one for the interface, and another for the implementation. It will prevent from having "refresh packages" issues when the implementation bundle went and come again.
The implementation of the previous interface:
public class MyImpl implements MyInterface { public String shout() { return "let it all out"; } }
The package of the implementation doesn't need to be exported by the bundle. The class MyImpl
won't be use directly by service consumers.
The new code of the activator:
public class Activator implements BundleActivator { private ServiceRegistration serviceRegistration; @Override public void start( BundleContext context ) { this.serviceRegistration = context.registerService( MyInterface.class, new MyImpl(), new HashMap<String,String>()); } @Override public void stop( BundleContext context ) { if (serviceRegistration!=null) { serviceRegistration.unregister(); } } }
The bundle containing the activator and the implementation needs to import the package of the interface in its file MANIFEST.MF
. Neither the package of the activator or the implementation needs to be exported within this file. They must remain internal to the bundle.
The class that consumes the service from another bundle
public void callService() { ServiceReference<MyInterface> reference = bundleContext.getServiceReference(MyInterface.class); MyInterface foo = bundleContext.getService(reference); try { //use service String msg = service.shout(); } finally { bundleContext.ungetService( reference ); } }
You can notice that the consumers only requires to import the package of the interface (not the implementation one). Moreover you need to be careful to handle dynamics of OSGi. The service could have gone between two calls!
Hope it helps you, Thierry
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.