OSGi Declarative services filter references at runtime

自古美人都是妖i 提交于 2019-12-06 07:50:51

I realise that this is now a very late answer to this question, but both answers miss the obvious built-in support for filtering in Declarative Services.

A target filter can be defined for a DS reference using the @Reference annotation:

@Component
public class ExampleComponent {
    @Reference(target="(foo=bar)")
    MyService myService;
}

This target filter can also be added (or overriden) using configuration. For the component:

@Component(configurationPid="fizz.buzz")
public class ExampleComponent {
    @Reference
    MyService myService;
}

A configuration dictionary for the pid fizz.buzz can then set a new filter using the key myService.target.

This is a much better option than jumping down to the raw OSGi API, and has been available for several specification releases.

I revoke my answer, because the acceppted answer is correct. When I answered that question I missed this little, but very important detail in the spec.

There is a nice way given by OSGi called service tracker. You can use inside a declarative service. In this example there is a config which holds the filter for the service you want to use. If the filter configuration changes, the whole component reactivating, so the tracking mechanism is restarting.

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

@Component(immediate = true, metatype = true)
@Properties(value = {
        @Property(name = "filterCriteria", value = "(objectClass=*)")
})
public class CustomTracker {

    private CustomServiceTracker customServiceTracker;

    @Activate
    protected void activate(ComponentContext componentContext) throws InvalidSyntaxException {
        String filterCriteria = (String) componentContext.getProperties().get("filterCriteria");
        customServiceTracker = new CustomServiceTracker(componentContext.getBundleContext(), filterCriteria);
        customServiceTracker.open(true);
    }

    @Deactivate
    protected void deactivate() {
        customServiceTracker.close();
    }

    /**
     * OSGi framework service tracker implementation. It is able to listen all serivces available in the system.
     */
    class CustomServiceTracker extends ServiceTracker {

        CustomServiceTracker(BundleContext bundleContext, String filterCriteria) throws InvalidSyntaxException {
            super(bundleContext, bundleContext.createFilter(filterCriteria), (ServiceTrackerCustomizer) null);
        }

        @SuppressWarnings("checkstyle:illegalcatch")
        @Override
        public Object addingService(ServiceReference serviceReference) {
            try {
                Object instance = super.addingService(serviceReference);
                // TODO: Whatever you need
                return instance;
            } catch (Exception e) {
                LOGGER.error("Error adding service", e);
            }
            return null;
        }

        @Override
        public void removedService(ServiceReference serviceReference, Object service) {
            // TODO: Whatever you need
            super.removedService(serviceReference, service);
        }

        @Override
        public void modifiedService(ServiceReference serviceReference,
                                    Object service) {
            super.modifiedService(serviceReference, service);
        }
    }
}

The only option I see for this use case is to use the OSGi API directly. It sounds like you have to do the service lookups each time you get an address to process. Thus you will have to get the appropriate service implementation (based on a filter) each time you are going to process an address.

Declarative approaches like DS and Blueprint will not enable you to do this, as the filters cannot be altered at runtime.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!