Note that there are some explanatory texts on larger screens.

plurals
  1. POOSGi services architecture: creation of service at request of consumer
    primarykey
    data
    text
    <p>I am developing an application in Eclipse RCP. I need help with a design decision concerning the design of a service.</p> <p>I have some bundles which are used to provide an <code>REngine</code> object to other modules. The <code>REngine</code> is an interface to a calculation engine, which can be implemented in multiple ways. The bundles provide instances of REngine by connecting to a remote server or starting a local calculation thread. Some bundles require configuration by the GUI (but also need to be available on a headless platform). A client Bundle may request multiple <code>REngine</code> objects for parallel calculations.</p> <p>I currently register these modules to provide an <code>REngine</code> service. The service is created by a ServiceFactory, which either launches a local calculation instance or a remote (server) instance. The client is responsible for trying out all Service registrations of the <code>REngine</code> class and selecting the right one.</p> <p>The code to do this can be summarised as follows:</p> <pre><code>class API.REngine { ... } class REngineProvider.Activator { public void start(BundleContext ctx) { ctx.registerService(REngine.class.getName(), new REngineFactory(), null); } } class REngineProvider.REngineFactory implements ServiceFactory { public Object getService(Bundle bundle, ServiceReference reference) { return new MyREngineImplementation(); } public void ungetService(REngine service) { service.releaseAssociatedResources(); } } class RConsumer.Class { REngine getREngine() { ServiceReference[] references = bundleContext.getAllServiceReferences(REngine.class.getName(), null); for(ServiceReference ref: references) { try { return bundleContext.getService(ref); } catch (Exception e) {} // too bad, try the next one } } } </code></pre> <p>I would like to keep this model. It is nice that the OSGi service spec matches my business requirement that REngine objects are living objects which should be released when they are not needed anymore.</p> <p>However, a registered service can only provide one service instance per bundle. The second time the service is requested, a cached instance is returned (instead of creating a new one). This does not match my requirement; a bundle should be able to get multiple REngine objects from the same provider.</p> <p>I have already looked at other OSGi framework classes, but nothing seems to help. The alternative is the whiteboard model, but it seems strange to register an REngineRequestService that is used by the REngineProvider bundle to give out a live REngine.</p> <p>How do I implement this in OSGi? As a reminder, here is my list of requirements:</p> <ol> <li>Easy enabling and disabling of <code>REngineProvider</code> bundles. Client code will just use another provider instead.</li> <li>Configuration of REngineProvider bundles.</li> <li>Multiple <code>REngine</code> instances per client bundle.</li> <li>Explicit release of <code>REngine</code> instances</li> <li><code>REngine</code> creation can fail. The client module should be able to know the reason why.</li> </ol> <hr> <p>Just to add the solution I have chosen as future reference. It seems the OSGi Services platform is not made for "requesting a service". It is the provider bundle that creates a service, and the client bundle that can find and use the services. It is not possible to provide an automatic "Factory" for services per user request.</p> <p>The solution chosen involves the <a href="http://www.knopflerfish.org/osgi_service_tutorial.html#white" rel="nofollow">OSGi whiteboard model</a>. On first sight, this may seem very difficult to manage, but <code>Blueprint</code> can help a lot!</p> <p>Provider blueprint.xml file:</p> <pre><code>&lt;reference-list interface="org.application.REngineRequest" availability="optional"&gt; &lt;reference-listener bind-method="bind" unbind-method="unbind"&gt; &lt;bean class="org.provider.REngineProvider"/&gt; &lt;/reference-listener&gt; </code></pre> <p></p> <p>The class <code>REngineRequest</code> is a shared API class allowing the provider to input his REngine object, or set an Exception explaining why the creation did not work.</p> <p>For the client, using an REngine is now as easy as doing:</p> <pre><code>REngineRequest req = new REngineRequest(); ServiceRegistration reg = bundleContext.registerService(req, REngineRequest.class.getName(), engineCreationProperties); req.getEngine().doSomeStuff(); reg.unregister(); </code></pre> <p>We make the assumption that the provider will never stop while the client is using the REngine. If it does, the <code>REngine</code> becomes invalid.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload