felix-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Pierre De Rop <pierre.de...@gmail.com>
Subject Re: [ANN] Apache Felix Dependency Manager r8 Released
Date Mon, 07 Mar 2016 18:18:49 GMT
Thanks Renato;

It's difficult to make a comparison with Blueprint and IPojo, which I don't
know well; I only practice DM and DS regularly. Let me try to give a quick
overview, with some elements which could help you to make your own opinion
and compare with the other DI frameworks:

- DM takes its initial roots from the early 2000 years. It was started by
Marcel Offermans and over the years, Marcel and some people from the Apache
community (including your humble servant) added some new features in it.
Like other DI frameworks, DM allows to manage OSGi service components. More
specifically, DM is made for those who like to define components
declaratively by java code, using the DM api (or now using the new lambda
api).
However, there is also support for an annotation based API. For general use
cases, annotations do the work, for other complex use cases, API is
necessary, but It is also actually a matter of personal taste.
You can refer to this blog from Marcel:

http://www.planetmarrs.net/dependency-manager-4/

- DM allows to declare dynamic dependencies at runtime: you can first
declare initial service dependencies from your Activator; and then once all
required dependencies are injected, your component "init" callback is then
invoked. And at this point you can add more dependencies dynamically, and
decide which dependencies you want to add based on the already injected
dependencies. So, once all required dependencies are available (including
dynamic dependencies declared from "init" callback), you component is then
called in its "start" callback and registered.

- Filter indices: DM has a special feature that allows to index filters in
order to speed up service lookups. This feature may be useful for large
application (say 10000/20000 services).

- Thread model:

DependencyManager uses a specific thread model which is described here:


http://felix.staging.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/thread-model.html

Mainly, all component events (dependency events, bundle events) are handled
serially, using a lock-free serial queue, and DM never calls component
lifecycle or dependency callbacks concurrently.
For example, you will never be called concurrently in the "start" callback
and in a dependency callback.
However, take care to use thread safe datastructure, when storing
dependencies in class fields, in case such dependencies may be accessed by
any threads.

Optionally, you can configure DM to handle and start components
concurrently, this can considerably speed up the activation of the
framework (especially if you also use filter indices and when you have
(say 10000/20000 micro services). And the nice thing is that even if
components are handle concurrently, each component remains "single
threaded": callbacks are still called serially but multiple component can
be activated concurrently.

- Configuration types: when a component depends on a configuration, you can
specify a configuration interface. DM will inject a proxy that converts
method calls from your configuration-type to lookups in the actual map or
dictionary. The results of these lookups are then converted to the expected
return type of the invoked configuration method. As proxies are injected,
no implementations of the desired configuration-type are necessary.

See
http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/dependency-configuration.html

- DM supports a feature that allows you to define a chain of aspect
services (or service interceptor) if you prefer. Aspects are factories that
create another service on top of the service that they're an aspect for;
they are orderly chained (using an aspect rank) and can "sit between" a
service provider and a service consumer. The service consumer will see the
top of the chain, while the actual service provider will be place in the
bottom of the chain.

- DM allows to create adapter services when a given type of adapted service
is found in the OSGI registry.
Some time ago, Marcel gave an interesting overview about aspects and
adapters here:
http://www.mail-archive.com/dev%40felix.apache.org/msg31197.html
I invite you to take a look at it.

Here is the same example from Marcel, adapted to the new lambda api. So, in
the example, we have a TaskExecutor component which executes all Tasks
published in the OSGi registry:

interface Task {
     void run();
}

public class TaskExecutor {
    // required, injected in class field.
    volatile ExecutorService executor;

    void start() {
        // our component is activated
    }

    public void add(Task task) {
        // store our task for later execution
    }

    public void remove(Task task) {
       // remove our task from the internal list
    }
}


Here is how to define the TaskExecutor component, which depends on a
required ExecutorService and on some optional Task services.
The required  ExecutorService is injected by reflection on compatible class
fields, while the Task dependency is more type safe and declared using
method references:

component(comp -> comp.impl(TaskExecutor.class)
    .withSvc(ExecutorService.class, true)
    .withSvc(Task.class, svc ->
svc.optional().add(Scheduler::add).remove(Scheduler::remove)));

Assume now we have a TaskCounter aspect used to count the number of
executed Tasks and to also make a log each time a task is executed.
Here, a TaskCounter will be created for each published Task service:

class TaskCounter implements Task {
   volatile task; // injected, it may be the actual wrapped task, or the
next task aspect in the chain
   volatile LogService logService; // injected
   final AtomicLong counter = new AtomicLong();

   void run() {
      task.run();
      long count = counter.incrementAndGet();
      logService.log(LogService.LOG_DEBUG, "Invoked " + task + " " + count
+ " times.");
   }
}

Now, let's define the aspect service, having a required dependency on a
LogService:

aspect(Task.class aspect ->
aspect.impl(TaskCounter.class).rank(10).withSvc(LogService.class, true));

DM automatically injects the original Task service in the TaskCounter
aspect, and in this case, the aspect is created with a service ranking of
10. You can create multiple aspects and create a whole chain if you want.
The order is determined by the ranking you supply. DM also takes care that
the TaskExecutor will now see only the aspects on top of the original tasks
(in other words, it will always only see the top
of the chain).

Now, let's also add an adapter. Adapters also bind to services, but don't
create a "chain" like aspects do. Assume we would like to create a servlet
for each task so we can trigger it with an HTTP GET call to that servlet:

public class TaskServlet extends HttpServlet {
    private volatile HttpService m_service; // injected
    private volatile Task m_task;  // injected

    public void start() {
        // register as a servlet here and invoke the task.getCount() from
its HTTP GET method
    }
}

Going back to the activator we declare our adapter, making sure it also has
a service dependency on the HttpService:

adapter(Task.class, adapter ->
adapter.impl(TaskServlet.class).withSvc(HttpService.class, true));

What happens now is that we will end up with an instance of TaskServlet
that is linked to the Task (or to the Task aspect) and that also has
HttpService injected. So in that implementation, the start() method
(which is one of the life cycle methods that will be invoked on a
component, if present) can just register the servlet ...

- DM not only supports OSGi service dependencies. In fact, you can write
your own dependency, like the one available from the "customdep" DM sample
code. in the sample code , a custom dependency is defined in order to track
any files created in "/tmp/". Each created file will then be added to the
PathTracker ...
(see
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/customdep/
)

- As an other example, in the new DM-lambda library, you can also make your
component waiting on the result of an asynchronous task that is wrapped
behind a CompletableFuture jdk tool. This allows (as an example) to block
the activation of
your component until an asynchronous event takes place. Take a look at the
end of the dm lambda documentation (see "CompletableFuture dependency"
section):
http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.html

- Like in blueprint, you can define timed service dependency: for stateless
required service dependencies, you can specify a timeout, and in this case
a proxy is injected and will block for the specified timeout in case the
dependency temporarily disappears.

- composition: you can define a single a set of dependencies, and when they
are satisfied then instantiate a *set* of objects together, and inject the
dependencies into the objects composition.
see:

http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/dm/lambda/samples/compositefactory/
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/composite/
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/compositefactory/

- I would end with some words about the DM shell, which provides excellent
tools when trying to make diagnostics in case some services don't come up.



sincerly;
/Pierre


On Sun, Mar 6, 2016 at 10:52 PM, Paulo Renato de Athaydes <
renatoathaydes@hotmail.com> wrote:

> Hi,
> This looks nice!
> I am interested to know how this compares to Declarative Services and OSGi
> Blueprint (and even IPojo, aren't these all a little similar?)... I know
> these well, but never heard of Dependency Manager before...
> Regards,
> Renato

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message