Getting a specific implementation from Felix - java

I've spent a long time on learning OSGi, but I still feel as though a crucial piece of the puzzle is missing.
This is my use case:
I am using JAX-RS (Grizzly) to create a REST API. I have an interface that has many various implementations. My solution should be able to add new implementations at any time.
Based on some form of input, I have to get a hold of one these specific instances. For example, lets say I register two interface implementations with Felix Interface A and Interface B. A user should be able to ask for Implementation B
By using the command line we get from running felix.jar(Apache Felix Gogo ) I have been able to install and start my own bundles. The problem I now face is how I from one of my controllers is supposed to retrieve any of these implementation.
Here is the code for the activator of one of my implementations.
public class MyClassActivator implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
System.out.println("Starting ImplementationA");
Hashtable<String, String> props = new Hashtable<>();
props.put("Identifier", "ImplementationA");
context.registerService(MyInterface.class.getName(), new MyClassA(), props);
}
#Override
public void stop(BundleContext context) throws Exception {
System.out.println("Stopping ImplementationA");
}
private class ImplementationA implements MyInterface {
/*my implementation*/
}
}
From one of my JAX-RS classes, I want to, somehow, do this:
MyInterface myclassA = getBundle("ImplementationA");
The String ImplementationA is the same string I placed in the props map.
What I have tried so far is
BundleContext bc = FrameworkUtil.getBundle(MyInterface.class).getBundleContext();
This however just returns null, it doesn't seem to actually be "talking" to my felix instance.
So my questions are how do I get an interface from Felix? And is what I want to do even possible with OSGi?

Your question is confusing since you mix terms for services and bundles. A bundle is an installable unit which contains code. That code can register and consume services. Services are object which, typically, implement some interface which is shared between the bundle providing the service and the bundles consuming the services.
So the first order of business is to make sure the service interface's package is exported by some bundle and imported by all the bundles which plan to participate in providing and consuming the service. This is necessary to ensure type safety. That is, the consuming bundles can safely cast the service object to the expected type of the service.
Once that is done, as you observer, there can be multiple providers of a service. When a provider registers a service, they can specify some metadata about the service in the form of key/value properties. Your example shows this in the Identifier property. When a consumer looks up a service, a filter string can be specified which can specify information to be checked against a service' metadata to select from among multiple provided services.
public class MyServiceConsumer implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
System.out.println("Looking for ImplementationA");
ServiceReference<MyInterface>[] refs =
context.getServiceReferences(MyInterface.class, "(Identifier=ImplementationA)");
MyInterface service = context.getService(refs[0]);
}
}
The above is terrible code; don't actually use it. It does not handle there being no service when the consumer bundle is activated (refs == null), nor does is it prepared for the service to go away. I strongly recommend you use OSGi Declarative Services when writing bundles. It makes service use and dealing with the dynamic super simple.
#Component
public class MyServiceConsumer {
MyInterface service;
#Reference(target="(Identifier=ImplementationA)")
private void bindService(MyInterface s) {
service = s;
}
#Activate
private activate() {
// do work
}
#Deactivate
private deactivate() {
// do work
}
}
This is a component which will only be instantiated when a matching service is present. It will be called at bindService to inject the service instance, the activate will be called to enable to component to do it work. If the injected service goes away, the component will be called at deactivate and then discarded. If later another matching service comes along, a new instance of the component will be activated.
See http://enroute.osgi.org/ for a tutorial on OSGi app dev.

Related

Pass runtime parameters to service in OSGi felix scr annotations

I am working on a OSGi application(with felix scr annotations) which exposes a service. The Service registers with external api's by passing String values.
listener.addSchemaChangeListener(new ChangeListener()
{
#Override
public void schemaChange(ChangeEvent changeEvent)
{
String schemaName = changeEvent.getSchemaName();
if (null != myBuilder && schemaList.contains(schemaName))
{
initVariables();
}
}
}, "SCHEMA1");
Service uses the above piece of code to register the listeners for mulitple values "SCHEMA1", "SCHEMA1", "SCHEMA3" ...
I am planning to reuse this service in various bundles. But i want to listen only for SCHEMA1 changes instead of all.
#Reference (name = "ServiceListener"", policy =
ReferencePolicy.DYNAMIC, cardinality =
ReferenceCardinality.MANDATORY_UNARY, bind = "bind", unbind =
"unbind", referenceInterface = ServiceListener.class)
private AtomicReference myServiceListener = new AtomicReference<>();
If i try to use it in another service with #Reference then there is no provision to pass values to service to listen only for particular schema changes so that
the service can be resued across my bundle by only passing the list of schema to listen instead of all. Because activate method will be called once the service is binded properly in the usage class(component).
Is there any provision in OSGi to acheive this functionality ?
You have included very little description of how your application is actually working, which makes this question challenging to answer.
From the code that you have shared it looks as though you are following quite a bad pattern. The Listener pattern is a source of many synchronisation problems and memory leaks, and the whiteboard pattern should be preferred when you are in OSGi.
The whiteboard pattern is pretty simple. Rather than having each listener look up a service and register with it, you invert the model. The source of events (in this case schema changes) looks for listener services that are registered in the OSGi service registry. That way the listeners are simple to write and filter, and there is no messy and error-prone add/remove listener logic to code.
A better model would use service properties to select particular schemas and look something like this (using the standard OSGi annotations).
Listener 1 (listens to changes for SCHEMA1)
#Component(
property="schemaName=SCHEMA1")
public class MyListener implements ChangeListener {
// Your implementation in here
}
Listener 2 (listens to changes for SCHEMA1, SCHEMA2, and SCHEMA3)
#Component(
property={"schemaName=SCHEMA1",
"schemaName=SCHEMA2",
"schemaName=SCHEMA3"})
public class MyListener implements ChangeListener {
// Your implementation in here
}
Example Source of events for Schema1:
#Component
public class MyListener implements ChangeListener {
#Reference(policy=DYNAMIC, target="(schemaName=SCHEMA1)")
private final List<ChangeListener> listeners = new CopyOnWriteArrayList<>();
private void onSchemaChange(ChangeEvent event) {
listeners.forEach(l -> l.schemaChange(event);
}
// Rest of your implementation in here
}
One way is to create one service for each schema. You can do this by supplying the schema name as a config value and using several configs. Each such service will then also hav this config parameter as a service property. So the clients then can filter for the schema property.
If you do not want to use these configs then you could create one service that offers a factory. Each client then would bind the factory and create an instance by supplying the schema name in the create method of the factory.

Jersey 2.x dynamic binding

Is there any way to provide a dynamic binding at runtime? AbstractBinder allows you to bind a factory but the class type has to be known at compile time.
Something to the effect of:
public class MyDynamicBinder implements DynamicBinder {
#Override
public boolean canBind(Class<?> someContract) {
return iCanBindThis(someContract);
}
#Override
public Object bind(Class<?> someContract) {
return getMyInstance(someContract);
}
}
hk2 is an extremely dynamic injection container. Unlike guice and CDI it can add services to its ServiceLocator at any time (if you have appropriate privilege). With the ServiceLocator (which is a service available anywhere you have any other hk2 service) then you can use the methods in ServiceLocatorUtilities like addClasses or addOneDescriptor in order to add whatever services you need at any time at all. You can also remove services at any time, but few people ever do that (unless you are writing a dynamic container of your own)

OSGI: do declarative services become available after bundle start

The question is simple, but I can't find answer - Can I state that all declarative services in bundle A become available after bundle A start? For example,
bundle=context.installBundle("file:bundleA-1.0.0.jar");
bundle.start();
//In this point are declarative services of bundle A 100% available?
P.S. I use apache felix, but I think it must be defined in Specs but not in implementation.
EDIT:
I assume that DS runtime is running, config is present and all mandatory references are present.
The answer to your question is a very simple: NO. There are NO guarantees about availability in OSGi ever based on neither timing nor ordering. The only guarantees are specified in the service events.
It is one of the greatest causes of complexity to make timing/ordering assumptions in your code because they are always violated in the most obscure way.
DS makes it trivial to write code that correctly reacts to the service dependencies as they come and go. Making sure that you get those guarantees associated with services is incredibly complex and you destroy all that value if you start to make assumptions that something should be available after you call a method.
In your example, just rely on a service that you need. If that service is available, then you are sure all initialization is done.
If you stick to service dependencies life in OSGi is fairly easy and very robust.
UPDATED with example after questions
One the non-OSGi side:
systemBundleContext = ... create framework
systemBundleContext.registerService(
BundleActivator.class,
new BundleActivator() {
public void start(BundleContext c) {
// start non-OSGi code
}
public void stop(BundleContext c) {
// stop non-OSGi code
}
},
null );
DS Component:
#Component
public class Initiator {
#Reference
BundleActivator ba;
#Referenc
MyService myService;
#Activate void activate(BundleContext context) throws Exception {
ba.start(context);
}
#Deactivate void deactivate(BundleContext context) throws Exception {
ba.stop(context);
}
}
You can not assume that all DS Components are available as services after bundle start. The first thing is that the DS runtime must also be running. Then DS components by default are lazily activated. This means they are active only when some other bundle requires such a service and last but not least components only are activated once all their mandatory references are present.
Well ... and before I forget it it you can also define that a component is only activated if a config is present for it.

Dynamic OSGi service replacement as development aid

We are using Apache Felix annotations to handle all the OSGi stuff in our application. I have a provider class that talks to a server. I have a consumer class that does stuff with data from the server. What I want is to create another provider instance (new class implementing interface) that is for debug purposes only that returns canned responses to requests by the consumer. Ideally I would like the consumer to be unaware of this handoff. It's provider service reference would simply be replaced.
The use case: When the developer is running on a machine without access to the actual server, he presses a button in our running app to switch from the real provider instance to our debug provider instance.
What is the recommended way to accomplish this?
Example code:
public interface IProvider{
public String getDataFromServer();
}
#Component
#Service(value=IProvider.class)
public class RealProvider implements IProvider{
#Override
public String getDataFromServer(){
...
}
}
#Component
#Service(value=IProvider.class)
public class DebugProvider implements IProvider{
#Override
public String getDataFromServer(){
return "Hello World";
}
}
#Component
public class Consumer{
private #Reference IProvider provider;
public void doSomething(){
provider.getDataFromServer();
}
}
If the two providers are in separate bundles, you can stop Bundle A and start Bundle B to switch between implementations of the service.
If the two providers are in the same bundle, you'd need to either drop down to the OSGI API and register/unregister the services manually, or create a proxy version of IProvider that has a debugMode flag and delegates to the specific implementation.

How do I provide my own web service implementation instance?

I have a web service (JAX-RPC) that runs on application server (Websphere Application Server 7.0).
Normally the development process looks like this:
I write a class with web service implementation (e.g. MyService.java)
The IDE generates web service endpoint interface (e.g. MyService_SEI.java)
The IDE generates configuration XMLs
When the web service is deployed, MyService_SEI is the declared service interface and the application server instantiates a MyService instance by means of the public no-arg constructor.
But what if I want to do constructor injection (i.e. have MyService class without a no-arg constructor) or if I want to provide a dynamic proxy object which implements MyService_SEI and use that?
Is there a way I can take control of the instantiation procedure (like a filter or interceptor) to achieve this?
You can't do constructor injection as Injection always occur after the default constructor is called. If you try to use an injected reference inside the default constructor it will ALWAYS fail, there's no workaround for this as this is mandate by the specification.
So the first option you mentioned is discarded.
For the second option, using a filter or interceptor, you actually have an option. WebSphere WebServices are build using Axis2 implementation and Axis provide a way of implementing Handlers.
You can add handlers into the JAX-WS runtime environment to perform additional processing of request and response messages.
Here's a handler example, from Axis documentation:
package org.apache.samples.handlersample;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class SampleProtocolHandler implements
javax.xml.ws.handler.soap.SOAPHandler<SOAPMessageContext> {
public void close(MessageContext messagecontext) {
}
public Set<QName> getHeaders() {
return null;
}
public boolean handleFault(SOAPMessageContext messagecontext) {
return true;
}
public boolean handleMessage(SOAPMessageContext messagecontext) {
Boolean outbound = (Boolean) messagecontext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) {
// Include your steps for the outbound flow.
}
return true;
}
}
And than you add a handler.xml file like this:
<?xml version="1.0" encoding="UTF-8"?>
<jws:handler-chain name="MyHandlerChain">
<jws:protocol-bindings>##SOAP11_HTTP ##ANOTHER_BINDING</jws:protocol-bindings>
<jws:port-name-pattern
xmlns:ns1="http://handlersample.samples.apache.org/">ns1:MySampl*</jws:port-name-pattern>
<jws:service-name-pattern
xmlns:ns1="http://handlersample.samples.apache.org/">ns1:*</jws:service-name-pattern>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleLogicalHandler</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleProtocolHandler2</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleLogicalHandler</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleProtocolHandler2</jws:handler-class>
</jws:handler>
</jws:handler-chain>
an easy method would be to make two classes. one your class with all the bells and whistles (constructor injection etc lets call it worker). and the actual service. the service would delegate what it needs to the worker class, who it can get by calling some factory method.
The factory can even look at some common db or other config to decide which run time instance (which class, what config, shared or common) so you have good separation and power
Just cause you are using one framework/ method of injection does not mean you cannot mix to make it more powerful

Categories