Apache
Home » Documentation » Apache Felix Subproject Documentation » Apache Felix Dependency Manager

This section describes some enhancements and API modification which have been performed in the dependency manager r13 release. Mainly,

API enhancements

Some enhancements have been done in the dm API:

Aspect/Adapters API enhancements

So far, aspects or adapters were defined using many methods from DependencyManager or DependencyActivatorBase classes:

For example, in DependencyManager.java, we have many signatures

public class DependencyManager {
    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter) {...}
    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String autoConfig) {...}
    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String add, String change, String remove) {...}
    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String add, String change, String remove, String swap) {...}
    public Component createAdapterService(Class<?> serviceInterface, String serviceFilter, String autoConfig, Object callbackInstance, String add, String change, String remove, String swap, boolean propagate) {...}

    public Component createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate) {...}
    public Component createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate, Object callbackInstance) {...}
    public Component createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate, Class<?> configType) {...}
    public Component createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate, Object callbackInstance, Class<?> configType) {...}
    public Component createAdapterFactoryConfigurationService(String factoryPid, String update, boolean propagate,String heading, String desc, String localization, PropertyMetaData[] propertiesMetaData) {...}

    public Component createBundleAdapterService(int bundleStateMask, String bundleFilter, boolean propagate) {...}
    public Component createBundleAdapterService(int bundleStateMask, String bundleFilter, boolean propagate, Object callbackInstance, String add, String change, String remove) {...}

    public Component createResourceAdapterService(String resourceFilter, boolean propagate, Object callbackInstance, String callbackChanged) {...}
    public Component createResourceAdapterService(String resourceFilter, boolean propagate, Object callbackInstance, String callbackSet, String callbackChanged)
    public Component createResourceAdapterService(String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod, Object callbackInstance, String callbackChanged) {...}
    public Component createResourceAdapterService(String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod, Object callbackInstance, String callbackSet, String callbackChanged) {...}

    public Component createAspectService(Class<?> serviceInterface, String serviceFilter, int ranking, String autoConfig) {...}
    public Component createAspectService(Class<?> serviceInterface, String serviceFilter, int ranking) {...}
    public Component createAspectService(Class<?> serviceInterface, String serviceFilter, int ranking, String add, String change, String remove) {...}
    public Component createAspectService(Class<?> serviceInterface, String serviceFilter, int ranking, String add, String change, String remove, String swap) {...}
    public Component createAspectService(Class<?> serviceInterface, String serviceFilter, int ranking, Object callbackInstance, String add, String change, String remove, String swap) {...}

So, in this new release, we have simplified the usage of the aspect/adapters like this: instead of having to use some of the many methods from the DependencyManager or DependencyActivatorBase, we have added some new interfaces for the aspect and adapters, and these interfaces are extending the Component interface. All other existing methods have been moved to DependencyManagerCompat/DependencyActivatorBaseCompat classes and the DependencyManager/DependencyActovatorBase classes are now extending the compat classes: this allows to simplify the reading of the javadocs for DependencyManager/DependencyActovatorBase.

For example, let's first show how an factory pid component was declared so far (a factory pid component is one which can be instantated multiple times using a "factory configuration" created using standard "configuration admin" service):

public class Activator extends DependencyActivatorBase {
    @Override
    public void init(BundleContext context, DependencyManager dm) throws Exception {
        dm.add(createFactoryConfigurationAdapterService("my.factory.pid", "updated", true, MyConfig.class)
            .setInterface(MyService.class.getName(), null)
            .setImplementation(MyServiceImpl.class)
            .add(createServiceDependency().setService(LogService.class))); // NullObject 
    }
}

So, now, there is a new FactoryComponent interface which extends the Component interface and it contains all the various parameters used when declaring a factory pid component. So the example above becomes:

public class Activator extends DependencyActivatorBase {
    @Override
    public void init(BundleContext context, DependencyManager dm) throws Exception {
        dm.add(createFactoryComponent()
            .setFactoryPid("my.factory.pid")
            .setPropagate(true)
            .setConfigType(MyConfig.class)
            .setInterface(MyService.class.getName(), null)
            .setImplementation(MyServiceImpl.class)
            .add(createServiceDependency().setService(LogService.class))); // NullObject 
    }
}

now, we explain what the new interfaces look like: Indeed as you can imagine, there is an issue when you extend the Component interface, because the various Component setter methods return a Component type. So, what we would like is to be able to introduce a generic type in the Component interface , and such generic type can then be used to allow the Component setter methods to return not the Component type, but instead return the aspect/adapter sub classes. This is what we have done, let's show a pseudo code, so you can understand how it works:

First, the Component annotation have been reworked like this:

public interface Component<T extends Component<T>> {
    T setInterface(String service, Dictionary properties)
    T setImplementation(Object ob);
    ...
}

As you can see the Component annotation is now using a recursive generic type which extends the Component interface. And now we have for example the following AdapterComponent interface which is defined like this:

public interface AdapterComponent extends Component<AdapterComponent> {
    AdapterComponent setAdaptee(Class<?> service, String filter);
    AdapterComponent setAdapteeCallbacks(String add, String change, String remove, String swap);
    ...
}

So, now, an adapter component can be defined like this:

Component adapter = createAdapterComponent()
   .setAdaptee(Adaptee.class, "(foo=bar)")
   .setAdapteeCallbacks("setAdaptee", "changeAdaptee", null, null)
   .setImplementation(AdapterImpl.class)
   .setInterface(AdapterService.class, null)
   .add(createServiceDependency().setService(LogService.class));

Support for multiple configuration types in callbacks

The ConfigurationDependency and Factory components can now support updated callbacks with multiple configuration types, for example, the following Activator defines a factory component (using the enhanced api) and multiple configuration types can now be provided:

public class Activator extends DependencyActivatorBase {
    @Override
    public void init(BundleContext context, DependencyManager dm) throws Exception {
        Component factoryComponent = createFactoryComponent()
            .setFactoryPid(pid).
            .setConfigType(MyConfig1.class, MyConfig2.class)
            .setImplementation(MyComponent.class);
        dm.add(factoryComponent);
    }
}

public class MyComponent {
    void updated(MyConfig1 cnf1, MyConfig2 cnf2) { ... }
}

Moreover, you can define a Dictionary parameter as the first argument in the updated callback, because sometimes, it's useful to be injected with the raw dictionary configuration, as well as with the configuration types. Example:

public class MyComponent {
    void updated(Dictionary<String, Object> rawConfig, MyConfig1 cnf1, MyConfig2 cnf2) { ... }
}

so, the new signatures for the updated callbacks are now the following (for both ConfigurationDependency and Factory Component):

updated(Dictionary cnf)
updated(Component comp, Dictionary cnf)
updated(Component comp, Property interfaces ...)
updated(Property interfaces ...)
updated(Dictionary cnf, Property interfaces ...)
updated(Component comp, Dictionary cnf, Property interfaces ...)

Annotations enhancements and changes

Essentially, the following enhancements and modifications have been done regarding annotations:

Please check new dependency manager annotations doc

Not backward compatible annotation changes

The following has been removed in the annotation api:

Usage of Java 9/10/11

When using Java 9 / 10 / 11, then you can't use fluent service properties anymore with dm-lambda, because in these new jdk versions, the "-parameters" option does not generate lambda parameters metadata anymore. So, the following example won't work using jdk 9/10/11 (but still works using Java 8):

component(comp -> comp.impl(Foo.class).provides(FooService.class, property -> "service property value"));

With Java 9/10/11, use this instead:

component(comp -> comp.impl(Foo.class).provides(FooService.class, "property", "service property value"));

The fluent service properties using lambda expression maybe removed in future DM version if a solution is not found to make it working with Java 9/10/11

Rev. 1844602 by pderop on Mon, 22 Oct 2018 21:51:30 +0000
Apache Felix, Felix, Apache, the Apache feather logo, and the Apache Felix project logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.