As people have suggested so far, there are quite a few solutions to this 
problem. The closest to what you have been doing so far is to use DS with a 
dynamic multiple requirement:


private final ConcurrentMap<String, List<XMLService>> services = new 
ConcurrentHashMap<>();

@Reference( cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = 
ReferencePolicy.DYNAMIC )
void addXMLService(XMLService service, Map<String, Object> props) {
        String key = props.get(XMLService.XML_VERSION).toString();
        services.computeIfAbsent(key, k -> new 
CopyOnWriteArrayList<XMLService>())
                .add(service);
}

void removeXMLService(XMLService service, Map<String, Object> props) {
        String key = props.get(XMLService.XML_VERSION).toString();
        services.compute(key, (k, v) -> v.remove(service));
}


As Peter describes, the Device Access Specification is probably worth looking 
at. Another option would be to add the XML providing method to a service 
representing the device, or to decorate an existing service representing the 
device with this method. This way you avoid having a “double lookup”, instead 
you look up the relevant device service and immediately have access to it and 
to the relevant XML.

Decorating can easily be performed by A1.0, A2.0 etc. They simply listen for 
all services that match their version and register a wrapper for each of them:

private final ConcurrentMap<DeviceService, 
ServiceRegistration<DecoratedService>> services = new ConcurrentHashMap<>();

private volatile BundleContext ctx;

@Activate
void start(BundleContext ctx) {
        this.ctx = ctx;
        // Register any services that were bound before the context was 
available
        services.replaceAll((k,v) -> (v == null) ? 
registerDecoratedService(ctx, k) : v);
}

@Reference( cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = 
ReferencePolicy.DYNAMIC, 
        //This filter would be different in each version of the bundle
        target = “(version=1.0.0)“ )
void addDeviceService(DeviceService service) {
        // Services may be bound before the start method is called
        services.computeIfAbsent(service, (k) -> ctx == null ? null : 
registerDecoratedService(ctx, k));
}

void removeDeviceService(XMLService service, Map<String, Object> props) {
        ServiceRegistration<DecoratedService> reg = services.remove(service);
        if(reg != null) reg.unregister();
}

Regards,

Tim

On 18 Jun 2014, at 07:41, Peter Kriens <[email protected]> wrote:

> I think there are many possible solutions to your problem:
> 
> 1) Use the BundleTracker which tracks the bundles carrying the versioned 
> resource (it might be in a specific place in the JAR, or via a manifest 
> header) and you pick the one you need (a service just giving a resource is a 
> rather thin imho and not a good use of services)
> 2) Use DS's MULTIPLE cardinality. This will inject you with all the services 
> (where each service MUST have the same version== package version, it is 
> confusing if you talk about the version of a service when it is actually the 
> same service type but just gives you a different XML). You can then pick the 
> right one once you know the device.
> 3) Once you got the device, look through all bundles to see which one carries 
> your resource
> 
> Your problem sounds awfully close to the problem the Device Access 
> specification tries to solve. You might want to look there. In this model you 
> would register a service representing your device. The Device Access manager 
> would then try to find an appropriate driver for this device, which would 
> then register a refined service. In the driver service it should not be that 
> hard to make the connection to the right resource. Or you make an extender 
> that registers a Driver service for each XML resource.
> 
> Kind regards,
> 
>       Peter Kriens
> 
> 
> On 18 jun. 2014, at 01:05, [email protected] wrote:
> 
>> Hi everyone, 
>> I asked this question 
>> http://stackoverflow.com/questions/22459539/get-declarative-service-at-runtime
>>  a couple of months ago where I was trying to find a way using Declarative 
>> Services to be able to decide at runtime which version of a service to use. 
>> One of the answers there was that DS is a build-time model so that I 
>> couldn't change this model at runtime ("inject me now version 1.4 instead of 
>> version 1.8"). This made me go the iPojo route where I finally found a 
>> solution: an aggregate dependency where instead of having a single service 
>> injected, I get all of the ones for that interface injected via a list or 
>> array and then it is up to the consumer to keep that list and decide which 
>> version to use when the moment comes. This seems to work fine; however, 
>> iPojo in eclipse is not working very well with java 8, so i am reconsidering 
>> if DS would be able to do the job. Is there any way to get a list of all the 
>> services implementing an interface, and have that list be updated when a new 
>> provider registers, all using DS and avoiding Service Trackers? 
>> 
>> The real use-case in case there is a completely different way to approach my 
>> problem is this. I have multiple bundle versions (A1.0, A1.2, A2.0, A3.0) 
>> each with a different XML file inside. The bundles expose a service whose 
>> job is just to return that XML resource. The trick is that our system can 
>> have multiple hardware devices connected, and only after a new device is 
>> connected and I query the device for its version, I can know which XML 
>> resource (or more specifically, which service version) I will need to use. 
>> So as you can see, I cannot at startup have a service injected and use that 
>> one for every device. 
>> 
>> Any suggestions are appreciated 
>> 
>> Thank you, 
>> 
>> Alejandro Endo | Software Designer/Concepteur de logiciels 
>> DISCLAIMER: Privileged and/or Confidential information may be contained in 
>> this message. If you are not the addressee of this message, you may not 
>> copy, use or deliver this message to anyone. In such event, you should 
>> destroy the message and kindly notify the sender by reply e-mail. It is 
>> understood that opinions or conclusions that do not relate to the official 
>> business of the company are neither given nor endorsed by the company. Thank 
>> You.
>> 
>> _______________________________________________
>> OSGi Developer Mail List
>> [email protected]
>> https://mail.osgi.org/mailman/listinfo/osgi-dev
> 
> _______________________________________________
> OSGi Developer Mail List
> [email protected]
> https://mail.osgi.org/mailman/listinfo/osgi-dev

_______________________________________________
OSGi Developer Mail List
[email protected]
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to