Search code examples
javaosgifelix-dependency-manager

OSGi AspectService get Service Properties of the Aspected Service


Given a service Sender with properties, and an aspect service LogSender, how does LogSender get the service properties of the current Sender? I'd like to add a property to optionally log the data that a specific Sender is sending.

component.getServiceProperties(); seems to return the LogSender's service properties instead of Sender's properties.

I've looked at ConfigAdmin but I don't see a way to associate the Sender that LogSender aspected, with the specific configuration used.

I'm using Apache Felix as my OSGi container if that's relevant.

Here's the Activator's init method after adding ConfigurationAdmin to the dependency list.

public void init(BundleContext context, DependencyManager manager) throws Exception {
     manager.add(createAspectService(Sender.class, null, 10).setImplementation(LogSender.class)
            .add(createServiceDependency().setService(ConfigurationAdmin.class)
                    .setRequired(true)));
            .add(createServiceDependency().setService(LogService.class).setRequired(true)));
}

Solution

  • To inject the service properties of the original Sender into the LogSender aspect, you can use the signature in DependencyActivatorBase (or DependencyManager), which allows to specify "add/change/remove" LogSender aspect callback methods:

    DependencyActivatorBase.createAspectService(
        Class<?> serviceInterface,
        String serviceFilter,
        int ranking,
        String add,
        String change,
        String remove);
    

    Then the LogSenderAspect callbacks method signature can take as arguments the Sender service, as well as the Sender service properties Map.

    Now, the second (simpler) solution is to specify a service filter for your aspect, and in this case; no need to specify any callbacks.

    let's take a look at the first solution with callbacks, where the LogSender aspect defines a "setSender(Sender, Map)" method, and the aspect will then only log the "send" method of Sender services having "foo=bar" service properties (here, we ignore service change/removed callbacks):

    public class Activator extends DependencyActivatorBase{
        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
            Component logSender = createAspectService(Sender.class, null, 10, "setSender", null, null)
                    .setImplementation(LogSender.class)    
                    .add(createServiceDependency().setService(LogService.class).setRequired(true));
            dm.add(logSender);         
        }
    }
    
    class LogSender implements Sender {     
        volatile Sender sender;
        volatile Map<String, Object> senderProperties;
        volatile LogService log;
    
        void setSender(Sender sender, Map<String, Object> senderProperties) {
            this.sender = sender;
            this.senderProperties = senderProperties;
        }
    
        @Override
        public void send() {
            if ("bar".equals(senderProperties.get("foo"))) {
                log.log(LogService.LOG_DEBUG, "calling method send called on Sender service having properties foo=bar");
            }
            this.sender.send();         
        }       
    }
    

    Now, a simpler solution consists in using a service filter "(foo=bar)" when defining your aspect, and in this case, no need to use callback:

    public class Activator extends DependencyActivatorBase{
        public void init(BundleContext ctx, DependencyManager dm) throws Exception {
            Component logSender = createAspectService(Sender.class, "(foo=bar)", 10)
                    .setImplementation(LogSender.class)    
                    .add(createServiceDependency().setService(LogService.class).setRequired(true));
            dm.add(logSender);         
        }
    }
    
    class LogSender implements Sender {     
        volatile Sender sender;
    
        @Override
        public void send() {
            log.log(LogService.LOG_DEBUG, "calling method send called on Sender service having properties foo=bar");
            this.sender.send();
        }       
    }
    

    does this help ? /Pierre