Exposing multiple implementations of a interface as OSGI service - spring

I have an interface that has two implementations. I want to expose both implementations as OSGi services, but when I am doing that one overrides the other. Please find the configuration that I am doing:
<bean id="formService" class="com.dbt.form.service.FormService"/>
<bean id="formAPIService" class="com.dbt.form.service.FormAPIService"/>
<osgi:service
ref="formAPIService"
interface="com.dbt.form.service.ifc.IFormService"/>
<osgi:service
ref="formService"
interface="com.dbt.form.service.ifc.IFormService" />
Here formService is overriden by formAPIService implementation.
Please help me on how to sort out this issue.

The second service does NOT override the first... both of these services will be published separately, and you can confirm this by typing the inpect cap service command in the OSGi Gogo shell.
What MAY happen is that your consumer code will only choose one of the available service instances. In this case you need to write your consumer to either bind to all instances, or use a combinations of rankings or target filters to determine which particular service you want. You should give more information on how you are using these services since that is where the problem lies (probably).

Read this page...Chapter 8. The Service Registry section 8.2.2.3.
You can use bean-name attribute of osgi reference tag. While importing a service bean-name refers to the id attribute of that service when its exported.

Related

WAS 8.5 - Can a blueprint managed OSGI service have a reference to a declarative services managed OSGI service?

We use WebSphere 8.5 (NON-Liberty Profile… just straight-up WAS) and we have a Spring 3.2 web app that is accessing an OSGI service which is using the blueprint component model via an SCA service bridge. We did this this way because to our understanding, this was the only way to be able to access the OSGI services layer from within our current architecture. If anyone might know of another/better way, I'm also all-ears on this as well.
From within this blueprint managed service, we'd like to have a reference to another service. This other service(and any service references within it) we'd like to have managed by the declarative services component model.
My question is… is this possible? Does anyone know if this mixing of these two component models from within WAS 8.5 is do-able in any way, shape, or form??
And if it is possible, might anyone be able to point me in the right direction on how to approach this?
Edit - Dec 5th
So the approach I decided to take was to first, build a small proof-of-concept application that uses three different OSGI bundles all using blueprint. Then once I have this working, take one of the blueprint managed services, and attempt to convert it to a ds managed service.
Here's what I've got so far:
I have ran through and created the tutorial located here. I currently have the CounterApp OSGI bundle Application containing the following bundles as application content:
CounterServiceBundle
CounterWebBundle
CounterWorldBundle
As is stated in the tutorial, all of the above are tied together using the blueprint component model via the blueprint.xml files.
So it all breaks down as follows:
From within the doGet method of the CounterWebBundle's CounterServlet I have a Greet service being used in the following manner:
Greet greet;
try {
InitialContext ic = new InitialContext();
greet = (Greet) ic.lookup("osgi:service/"+Greet.class.getName());
String greetText = greet.getText();
String output = "greet.getText()="+greetText;
response.getOutputStream().println(output);
} catch (NamingException e) {
e.printStackTrace(System.out);
}
This "greet" service is defined in the blueprint xml as "GreetBeanService". Now, within its implementation class it has references to two other services, "CounterBean" and "WorldRef".
Here is the blueprint.xml file to clarify:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<bean id="CounterBean" class="com.ibm.ws.eba.counter.CounterImpl"
init-method="init"></bean>
<service id="CounterBeanService" ref="CounterBean"
interface="com.ibm.ws.eba.counter.Counter" />
<bean id="GreetBean" class="com.ibm.ws.eba.counter.GreetImpl"
init-method="init">
<property name="counter" ref="CounterBean"/>
<property name="worldBean" ref="WorldRef"/>
</bean>
<service id="GreetBeanService" ref="GreetBean"
interface="com.ibm.ws.eba.counter.Greet" />
<reference id="WorldRef" interface="com.ibm.ws.eba.world.World" />
</blueprint>
So the thing is this:
I'm aiming to convert the "WorldRef" service to a DS managed service with a component.xml file and the following added to the MANIFEST.MF header Service-Component: OSGi-INF/component.xml of the implementation Class, not the API Class if I'm understanding correctly.
Would this be all I would need to do for the conversion? Or do I also need to add an Activator for the Class? Also, would I need to add 'activate' and 'deactivate' methods in the API implementation Class?
Also I'm of the understanding that I have to somehow include the service component runtime, as a separate bundle and include it in the "CounterApp" application, how exactly would I do this? Do I have to create a separate bundle project consisting of the following bundle/jars
org.eclipse.equinox.util
org.eclipse.equinox.ds
org.eclipse.osgi.services
where I would then re-export all of the exported interfaces from all of these jars?
Or do I have to define some sort of service to export that exposes the SCR?
Edit - Dec 6th
I went ahead and created a new DS OSGI bundle/jar containing all of the above mentioned jar files required to provide the equinox DS implementation, then just passed on the exports of each jar in this new bundle. I then added this DS bundle to my CounterApp application and imported each of these DS bundle exports into the bundle containing the WorldRef service.
This is where I appear to be getting hung up:
The OSGI framework is loading the bundle containing the WorldRef service but the service is not being added to the registry, which suggests that the component.xml file defining the service isn't being read, which, intern suggests that the SCR is not running because it is what reads that file to my understanding.
So still stuck on the ability to get the SCR running. I am under a very tight deadline (I know… who isn't, right?

ServiceTracker and DS combined?

Let's imagine a bundle in which exists:
A component is responsible of listen all "Device" service instances in the service registry.
The same component needs an "adaptor factory" in order to create "Adaptors" by using the discovered devices.
The factory is owned by another bundle.
I can solve part of the problem by using a ServiceTracker (Activator + Service Tracker): the activator instantiates the ServiceTraker and it can register all changes in "Device" services.
But i can't inject to this service tracker the DS factory created in other bundle, because it will result in two instances (one created by activator AND without the member /// another created by osgi AND with member variable ok but can't listen the "Device" service changes).
So... how can i solve this scenario? How can i have a Service Tracker (perfect for me) with a DS as a class member?
Use no Activator, instead use a component or service (we will call it A) with a declarative services 'activate(ComponentContext)' method. Within the activate method, you can instantiate your ServiceTracker like normal.
When you instantiate the ServiceTracker within A's activate method, you can also pass in the AdapterFactory into the ServiceTracker. You can get the AdapterFactory by pulling it out of the BundleContext taken from ComponentContext or (even better) use DS and make it a service reference to your A component.
That said: why do you need ServiceTracker for this? Unless I misunderstand, you can use DS bind and unbind to receive events on the availability of a Service.
EDIT: An (OLD) example of Bind/Unbind behavior using multiple cardinality: http://blog.tfd.co.uk/2009/11/12/declarative-optional-multiple-references-flaky-in-osgi/
EDIT: A comparision of the two approaches but doesn't go into bind/unbind so much: http://njbartlett.name/2010/08/05/when-servicetrackers-trump-ds.html
EDIT2: That said: my general policy is to not use an Activator except in super rare cases. Use DS, ipojo, etc and use the components you define with those techs in order get access to the BundleContext to build more low level objects like ServiceTrackers.

Spring - usage of alias vs names

I am confused on the usage of alias. I do understand what alias is and how it is being used but i don't see how it can be any different than using names on a bean definition.
<bean id="xyx" name="abc,def" .. />
<alias name="xyx" alias="pqr"/>
Why the alias when i can use abc or def?
In my mind bean aliasing can be helpful in large system, where you can not manipulate bean names. You have option to create your own name (alias) specific for your part of the system...
from Spring documentation (3.0.x)
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/
...it is sometimes desirable to give a single bean multiple names,
otherwise known as bean aliasing...
therefore creating multiple names or/and aliasing are the same thing.
A use case maybe when you want to customize some beans that are already defined somewhere in a modular application (each module is a spring project for example), the bean maybe defined by a third-party framework/API or even your team. In that case you want that only inside your spring project call the customized version without altering other modules (projects), to do that just add the alias in your spring configuration which is indeed a powerful feature:
<alias alias="globalBeanService" name="customizedBeanService" />
Hence, whenever spring find a call to the globalBeanService, it will inject customizedBeanService for you inside your specific module.
Without this feature, you should go through all classes and modify the bean manually!!
An aliased bean will always have higher priority over a non-aliased one, and in case of having different beans with the same alias then the last one declared will have the priority. In other words, the aliased bean will override the non-aliased beans.
This can be particularly useful when creating big projects or when you are building extensions to your project and don't want to touch the original bean definition.
Alias has a specific using scenario which multiple names don't have:
Imagine multiple config xml files in your project, most of which are authored by your colleagues, and you need to add your own config.xml file. Using you'll be able to refer to a bean defined in another config file with a different name that's maybe more meaningful to your config, without having to touch your colleagues' config files.
I recently found another use case where alias easily solved a problem.
When auto configuration is active, Spring Boot provides the bean serverProperties which can be used to access information about the server currently running the web app.
In integration tests (i.e. when #SpringBootTest annotation is present) the same bean is available under the name org.springframework.boot.autoconfigure.web.ServerProperties.
Of course it is possible to use a different profile for integration testing, but that would require manual change of configuration at multiple places. However, simply by adding
<alias name="serverProperties" alias="org.springframework.boot.autoconfigure.web.ServerProperties"/>
the same configuration files can be used for integration tests and in production.
This might be a bug in Spring Boot, however alias easily solve the problem without waiting for a new release. And most certainly I have no possibility to alter the Boot configuration myself.

Osgi Declarative service conditional binding

I have this scenario, I have three declarative services that provide the same interface (say a reader interface and I have readerimpl1-database- readerimpl2-flat file- readerimpl3-memory). I want to have a consumer that binds only to the database implementation. In the component definition we give it a name so I am pretty sure that the name is in the registry so if I were to add an activate method I can lookup from the component context using the name.
I want to try to it via the bind/unbind though using the service name as the parameter. I am pretty sure that the "target" parameter in the component reference element can be used to do this but I have not found how to use it.
Has anyone else done this?
This would be similar to using
#Reference(mapped-name="foo")
Target is simply an OSGi filter. You can use it to filter by any service property. So, if your services have property named backend with values file or database, you can bind with the following target:
<scr:reference ... target="(backend=database)"/>
And the service with database backend itself will register as:
<scr:component ...>
...
<property name="backend" type="String" value="database"/>
</scr:component>

Services provider and consumer in Spring DM

I have a bundle that should provide and consum a service. My application context is:
<bean id="dbConsumer" class="service.User">
<property name="db" ref="DBservice"></property>
</bean>
<osgi:reference id="DBservice">
<osgi:interfaces>
<value>com.db.manager.DatabaseManager</value>
</osgi:interfaces>
</osgi:reference>
<bean name="ServicioZB" id="zbservice" class="service.ZBService"/>
<osgi:service ref="zbservice">
<osgi:interfaces>
<value>service.IZBService</value>
</osgi:interfaces>
</osgi:service>
The problem is when I deploy. I work on Equinox and if I watch services I can see that the bundle consums DBservice. However, the service is noy exposed. But if I remove the reference tag, my service is exposed. It is to say, I have 3 bundles (A,B,C). B exports a service that is consumed by A. Also, C exports a service which is consumed by B Then, my question is: Can not the tags be together? How could I develop a bundle to consum and provide services?
Thanks in advance!
Regards!
If you are only using publishing one interface, try to use the interface property instead of the interfaces-tag. So replace
<osgi:service ref="zbservice">
<osgi:interfaces>
<value>service.IZBService</value>
</osgi:interfaces>
</osgi:service>
with
<osgi:service ref="zbservice" interface="service.IZBService"/>
I had a similar issue one time and this approach did work for me.

Resources