How do I call OSGI service from outside OSGI? - osgi-bundle

I am considering writing the OSGI bundle and will expose this as a OSGI service. Now, I wanted to call this OSGI service from another java module,assuming both OSGI bundle and java module running in same JVM.
Is that possible to call OSGI exposed service from outside OSGI ?
Thanks in advance!

BundleContext is required to obtain a ServiceReference which is required to get a Service.
Assuming that the MyService is in your classpath and that there is only one implementing service in the OSGi container:
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
[...]
BundleContext bundleContext = FrameworkUtil.getBundle(MyService.class).getBundleContext();
ServiceReference<MyService> serviceReference = bundleContext.getServiceReference(MyService.class, null);
try {
MyService myService = bundleContext.getService(serviceReference);
// do something with myService
} finaly {
bundleContext.ungetService(serviceReference);
}
Variations
The MyService is not available in your classpath. That is not a problem as you can use any class which is deployed to the OSGi container for the FrameworkUtil.getBundle() method and you can pass a String (FQCN) to the BundleContext#getServiceReference() method.
There are multiple implementations of the MyService. Use an LDAP filter for the second parameter of the BundleContext#getServiceReference() or call the BundleContext#getServiceReferences() method which will return an array or use the same code and rely on the ServiceRanking.

Related

#Reference("(service.label=TESTCALL)") Felix SCR annotation error

am trying to implement an OSGI service which can serve me as ConfigurationFactory the service implementation has just two properties as shown below.
#Property(value="this is service variable property value")
static final String MY_SERVICE_VARIABLE = "service.variable";
#Property(description="Label for this MyService")
private static final String MY_SERVICE_LABEL = "service.label";
and am retrieving this service configuration data from an OSGI servlet where i am trying to call this service by below code which compiles fine and retrieves data randomly from the multiple service configuration.
#Reference
MyService myservice;
But when i wanted to get each configuration data by using the service.label and am calling the service by using below code snippet in my OSGI servlet, while compiling am facing the below Error.
#Reference("(service.label=TESTCALL)")
MyService myservice;
cannot find symbol [ERROR] symbol: method value() [ERROR] location:
#interface org.apache.felix.scr.annotations.Reference.
use #Reference(target = "(service.label=TESTCALL)") for AEM 6.x versions, it should compile. I have uploaded the sample POC that i have used earlier at my gourivar github and the same POC example you can find at my aemvardhan.wordpress.com
Your service is most likely missing the Service Factory annotation. Something like:
#Service
#Component(
metatype=true,label="my service",
description="sample my service implementation",
configurationFactory=true)
public class MyServiceImpl implements MyService {
}
Note the configurationFactory=true attribute. This enables the service to have multiple configurations.

Accessing BundleContext with Felix dependency manager

I am using Apache Felix dependency manager in my project. In the service activation method
#org.apache.felix.dm.annotation.api.Start
public void activate() {
// Need BundleContext here
}
I need an access to BundleContext or Bundle. How can I achieve this?
You can make a volatile BundleContext field in your class and the dependency manager will inject it.

Can Blueprint beans have #Reference services auto injected?

Can instances created by the Blueprint <bean> tag be auto injected with service references specified using the OSGi Declarative Services mechanism?
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
#Component(service={})
public class DatabaseThing{
#Reference
public void setDataSource(DataSource ds){
...
}
If I instantiate via immediate=true in the #Component then my DataSource OSGi service is injected. If I create the instance via blueprint <bean class="DatabaseThing"> then no auto-injection occurs.
I've had a look at the Aries source, and it seems that the service injection is specific to org.apache.aries.blueprint.container.ServiceRecipe and isn't part of ...BeanRecipe which is used for <bean> style instantiation.
That does not work. The DS annotations are processed by bnd and result in a DS xml file that will then be evaluated by felix scr at runtime. In this case the full lifecycle of the object is controller by scr.
If you additionally declare a blueprint bean for the same class then it will be a separate instance. Blueprint can the inject services and beans into this instance but it is completely disconnected from DS.
If your main concern is to use annoations for blueprint injections then I recommend the blueprint-maven-plugin. It allows to use CDI and Java EE annotations in your code. These are translated to a blueprint.xml at build time. So the result is similar to DS but powered by blueprint.

What is the difference when a service is registered as a normal service vs ServiceFactory in OSGi container?

What is the difference between registering a service as a normal service vs making it a ServiceFactory?
For example :
I have a normal osgi-component which I am making a service using service scr annotation
#Component
#Service
class Service1 implements Service1Interface {
...
...
...
}
Now, I have another osgi-component which I will be registering as service with ServiceFactory flag as true
#Component
#Service(serviceFactory=true )
class Service1 implements Service1Interface {
...
...
...
}
What exactly is the difference between these two? Is there any difference when they are registered in the container and in what scenario's should we go for a ServiceFactory?
In the former, there will be one instance of the component that will be used for all bundles that get the service. In the latter case, a new instance of the component will be created for each bundle that gets the service.
A service factory is useful if you need to track resources on a per using bundle basis.

How to expose the spring couchbase template as OSGI service

Had one more question regarding the Spring-data-couchbase and OSGI.
I want to have different persistence bundles based on the functionality but I would like to have a common bundle while provides me the connection to couchbase.
If I want to scan for the repositories from a different bundle, I have to pass the template-ref object to it.
<couchbase:repositories base-package="xyz.abc.model"
couchbase-template-ref="cb-template-first">
</couchbase:repositories>
The template is created in the way as shown below as per the examples
<couchbase:template id="cb-template-first"
client-ref="cb-first" />
Basically, I wanted to know is there a way to expose the template as an OSGI Service, so that this service can be referenced in my other bundle.
If you use just "OSGi" as mentioned in your comment, you have a bundle activator class which initializes your context.
In this case your activator would look like this:
public class Activator implements BundleActivator
{
#Override
public void start( BundleContext context ) throws Exception
{
// start spring application context
// template-interface = application context get bean
context.registerService( template-interface.class.getName(), template-interface, null );
}
}
But if you want to build an OSGi application based on spring i would recommend to use gemini blueprint to remove boilerplate code. Gemini Blueprint is an extensions which scans all started bundles for context-files inside of META-INF/spring and starts them automatically. Due to namespace-support of gemini blueprint, you can publish or fetch a service within your context:
<osgi:service id="simpleServiceOsgi" ref="simpleService" interface="org.xyz.MyService" />
<osgi:reference id="messageService" interface="com.xyz.MessageService"/>

Resources