Resolving an OSGi service instance from a static method

osgi declarative services annotations
osgi multiple service implementations
osgi service example
osgi reference target
osgi service factory
osgi services in aem
osgi service ranking example
osgi tutorial pdf

I have a legacy Java enterprise application which registers a bunch of services as Spring beans and registers them with JNDI. I'd like to convert this to use Spring with OSGi instead.

Previously, the service class was just included in the classpath of any other class that needed it, and had a static method looking something like this:

public class SomeService {
    // private fields...

    public static SomeService getInstance() {
        SomeService svc = null;
        try {
            InitialContext ctx = new InitialContext();
            svc = (SomeService)ctx.lookup("java:/SomeService");
        } catch (NamingException ex) {
            logger.info("Exception in getNamedObject", ex);
        }
        return svc;
    }

    // Setters and getters, some of which are filled-in with Spring beans

    // Other methods etc...
}

Wherever the service is used, we have code like this:

SomeService svc = SomeService.getInstance();
// or even
SomeObject results = SomeService.getInstance().getSomeObject();

Now, I realize the "correct" way to convert this would be to remove getInstance() completely and force all users of the interface to have their own reference to the implementation, supplied by Spring and configured in the xml files in META-INF. However, this change would be too big to make all at once, as the system is already in production).

Is there any way to fetch an instance of an OSGi service analogous to the JNDI approach above?

Update: some clarification Just to be extra clear on my goals here - I know that this is not a good approach in general. This is, however, a large enterprise application which is in production, and changing the entire thing in one go to adjust to the "ideal" OSGi structure is simply too large a change to do all at once.

What I'm trying to accomplish here is to break out a small part of the application and make it ready to be served as a separate OSGi bundle. But since the rest of the application - the "client code", if you will - is not ready for this change yet, I must have an intermediate step which lets me use this code both in the old way, and as an OSGi service. Over time, the rest of the appilcation will also be modularized and OSGi-ified, and eventually these static factory methods will be removed entirely.

Until then, however, remarks that "this is the wrong way to do OSGi" aren't very helpful to me - I know it isn't, but this isn't even my final form...

You are trying to push the square peg through a round hole. Every developers learns in computer science 101 that global variables are bad, so I would say the quotes around "correct" are very misplaced since statics are prime global variables.

Because OSGi never relied on global variables (statics in java) you can run OSGi in OSGi in OSGi inside a WAR file on a App server running on top of OSGi. Statics are evil (first spoken by Anselm Baird, the author of ServiceSpace, the predecessor of OSGi). The service model was developed to address the problem you run into; any service implementation can reference another service by its interface and/or properties from anywhere:

 @Reference
 void setSomeService(SomeService s) {
     this.s = s;
     ...
 }

In a modular system, a central God XML is an anathema.

There is no solution to your problem since you will inevitably run in ordering problems. In OSGi, a service is not guaranteed to be available (One of its most powerful and misunderstood features). Your service provider is free to come and go at any time. Because your static model does not handle dependencies it will spuriously fail because it assumes implicit ordering. Now lots of people do these static solutions because it tends to work most of the time; I think "most of the time" should however not be good enough for computer software. Don't think we would do this if we would be liable for our products ...

Assuming that you work with Eclipse or another IDE with refactoring, then I have a hard time understanding why it would be hard to change the code base to inject this service?

OSGi is not a temporary diet nor a magic sauce like most Java libraries, it is a mature modularity system that requires your app to become truly modular, i.e. it is a lifestyle change. Trying to use a framework but then go against its flow is a strategy that leads to much grief in my experience.

112 Declarative Services Specification, This complexity negatively influences the adoption of the OSGi service model as well A component instance never sees any of the dynamics of the static reference. The method returns a Promise that will be resolved when the actions that  The effectiveness of a requirement is defined by the Resolve Context, a Resolver service must call the isEffective(Requirement) method to establish if a requirement is effective for a given resolve operation. A Resolver must never create a wire from a requirement that is not effective.

In any case you want to publish you service as OSGi service. The question is only how to access it with minimal impact on your client code.

One aproach might be to use:

FrameworkUtil.getBundle(YourClass).getBundleContext(); This allows to access the bundle context in static methods. From there you can access the service.

Another aproach could be to use aries jndi. It allows you to retrieve OSGi services using jndi. So this should also help.

Of course like stated by Peter this should only be a temporary solution.

Control OSGi DS Component Instances, If you think about multi-threading or context dependent services, you may need This implementation will count the number of instances in a static field and and specifies how the service reference should be resolved. The Resolver is triggered by activity in the OSGi framework. Calling certain methods on a bundle when a bundle is in the INSTALLED state will cause the framework to begin a resolve operation in order to resolve the bundle.

I had to overcome a similar Problem, i.e. a published static Interface which delivers Services used by users, so I couldn't force them to go full OSGI. The following annotated code worked well for me, so maybe someone else can benefit too.

@Component(immediate=true, service=ServiceProvider.class, scope=ServiceScope.SINGLETON)
public class ServiceProvider {

    private static FooService fooService;

    @Reference(cardinality=ReferenceCardinality.MANDATORY)
    public void setFooService(FooService fooService) {
        ServiceProvider.fooService = fooService;
    }

    /**
     * This is the existing Method which should return
     * a FooService Object.
     * @return The 'static' FooService
     */
    public static FooService getFooService() {
        return fooService;
    }
}

In Eclipse (4.8 Photon) with Plug-in Development -> DS Annotations for 1.3 enabled, this generates the file

OSGI-INF/your.package.name.ServiceProvider.xml

containing the following OSGI Service declarations

<scr:component ...>
    <service scope="singleton">
        <provide interface="your.package.name.ServiceProvider"/>
    </service>
    <reference bind="setFooService" cardinality="1..1" interface="foo.service.package.FooService" name="FooService"/>
    <implementation class="your.package.name.ServiceProvider"/>
</scr:component>

and the following entry in the MANIFEST.MF

Service-Component: OSGI-INF/your.package.name.ServiceProvider.xml

At runtime, the

setFooService(...)

method is called first and the FooService object is injected as expected, so an external call to

ServiceProvider.getFooService();

will also work as it did before.

Mine of Information - OSGi Services, An OSGi service is simply an object instance. where a static method is used to obtain “the instance” of some helper object (ie is coupled After an OSGi bundle has been loaded and “resolved”, it can optionally be started  Implementing an OSGi service is a two-step process, first we must define the interface of the service and then we must define an implementation of the service interface. In this particular example, we will create a dictionary service that we can use to check if a word exists, which indicates if the word is spelled correctly or not.

I think I've found a way to do this - I'm working on testing it, but from the documentation this approach seems promising.

I created a resolver class, which is responsible for actually fetching the service from OSGi, and which does it by means of implementing BundleContextAware. That way, I'm hoping a BundleContext will be injected from which I can grab a service instance:

public class SomeServiceResolver implements BundleContextAware {
    private BundleContext _cxt;

    @Override
    public void setBundleContext(BundleContext context) {
        _cxt = context;
    }

    public SomeService resolveService() {
        // TODO: Add error handling if service isn't available
        ServiceReference<SomeService> svcref = _ctx.getServiceReference(SomeService.class);
        SomeService svc = _ctx.getService(svcref);
        return svc;
    }
}

Then the static getInstance() method becomes simply

public static SomeService getInstance() {
    return new SomeServiceResolver().resolveService();
}

As I said, I haven't tested this yet, so we'll see if it actually works.

[PDF] A Practical Approach for Finding Stale References in a Dynamic , stale references detailing them and presents techniques based on Aspect. Oriented The OSGi service platform [1] is a framework targeting the Java platform, providing We found that a static analysis approach may impose several retrieve the service instance that corresponds to that ServiceReference object. This method is called by the framework each time a resolve process begins to obtain a resolver hook instance. Bundle - Interface in org.osgi.framework An installed bundle in the Framework.

Solved: Sharing class with static methods between plugins?, We put a jar file in web-inf\lib that contained some utility classes with static methods and our. need an interface and the methods can't be static - I'll need to get an instance (if not Spring), but this assumes that you declare the dependency in OSGI For v2 plugins I can either bundle the jar into each plugin or create a v2  ADD - Static variable in class org.osgi.service.dmt.security. DmtPermission Holders of DmtPermission with the Add action present can create new nodes in the DMT, that is they are authorized to execute the createInteriorNode() and createLeafNode() methods of the DmtSession.

ComponentAccessor (Atlassian JIRA 7.2.4 API), Provides static methods for accessing JIRA's managed components — that is, the components in as one of them must be resolved first without the other dependency available for injection yet Retrieves and returns the issue service instance Retrieves and returns a public component from OSGi land via its class name. async(Method, Object[]) - Method in interface org.osgi.service.async.delegate. AsyncDelegate Invoke the specified method as an asynchronous task with the specified arguments.

Index (AEM Mocks JUnit 5 3.0.1-SNAPSHOT API), MockOsgi. Simulate activation of service instance. activate(Object Static method in class org.apache.sling.testing.mock.osgi.MockOsgi. Simulate activation of  A public static method on the required type called valueOf that returns an instance of the given type and takes a single String argument. A public constructor taking a single String argument. If one of these methods is available then the Framework must construct a temporary object by passing the value as the String argument.

Comments
  • Eventually we will migrate all the code to inject the service, but at the moment this is not an option - not because it would be hard to re-write the code, but because it would be impossible to deploy the code into production within an overseable future, as doing so requires restart of systems that cannot be shut down at will. If I can find an intermediate solution where the service is exported as an osgi service while still allowing for the old way of accessing it, we can re-write this part of the system, deploy the service bundle, and make changes in other places when possible.
  • Also, regarding statics: there is no actual requirement that getInstance() returns the same instance every time - just that the API for getting a service instance is unchanged.
  • But can you handle the fact that there is NO instance. About the -1, you can be annoyed that the world does not work like you think it should, but shooting the messenger is kind of counter productive.
  • So if somebody tells you with extensive experience that it cannot be done, with its rationale, then this is not a useful answer? Sigh.
  • I am saying it cannot be done reliably in OSGi ... However, there is massive evidence that people ignore this good advice in production and open source code and just go to the service registry through FrameworkUtil, which allows you to get the BundleContext so you can get a service ...
  • Aries JNDI definitely sounds like a nice way to go. I'll have to look into that...
  • So you get the services but never unget them?
  • @NeilBartlett: No, at the moment I don't - and given the current state of this application, I'm not sure there is any way I can, since I don't know when the client code is done with the service instance. I'll look into it though, when I have the getting part working.
  • Not sure if this can work. You are initializing your SomeServiceResolver using new. In this case spring will not have the chance to inject the bundle context into it.