Activators are not "Qi4j complete"

14 views
Skip to first unread message

Niclas Hedhman

unread,
Dec 8, 2013, 12:51:15 AM12/8/13
to qi4j...@googlegroups.com

Now, when I start using 2.0 more extensively, I notice that the @Activators construct is not "Qi4j complete". Injection doesn't work on these, and neither any other type Qi4j feature.

I think this needs to take priority in 2.1 work.

I will try to help out by creating proper tests for this.

Meanwhile, the good-old org.qi4j.api.activation.Activation way of doing it will fill my needs... (assuming it still works)


Cheers
--
Niclas Hedhman, Software Developer
河南南路555弄15号1901室。
http://www.qi4j.org - New Energy for Java

I live here; http://tinyurl.com/3xugrbk
I work here; http://tinyurl.com/6a2pl4j
I relax here; http://tinyurl.com/2cgsug

Paul Merlin

unread,
Dec 9, 2013, 8:20:11 AM12/9/13
to qi4j...@googlegroups.com
Niclas,

Niclas Hedhman a écrit :
Now, when I start using 2.0 more extensively, I notice that the @Activators construct is not "Qi4j complete". Injection doesn't work on these, and neither any other type Qi4j feature.

I think this needs to take priority in 2.1 work.

I will try to help out by creating proper tests for this.
Activators are POJOs for now.
I think that adding, for example, injection to them would be both
powerful and dangerous. I can see chicken and eggs coming.


Meanwhile, the good-old org.qi4j.api.activation.Activation way of doing it will fill my needs... (assuming it still works)
The activation listeners api from 1.x still works.

Cheers

/Paul

Niclas Hedhman

unread,
Dec 9, 2013, 8:28:57 AM12/9/13
to Paul Merlin, qi4j...@googlegroups.com

Yes, with their regular "problems" to kick in, which is why I assume that the Activators were created.

Chicken-egg problem... Well, depends on how we define the semantics around the Activators. The beforeActivation and afterPassivation are the dangerous ones, and perhaps a concern.

I don't think the Activator should be Composite, but a Fragment of the composite being activated. I think that would ensure (assuming no beforeActivation/afterPassivation) that no race conditions occur. 
@This referencing the Composite being activated. @Service no problem. @Structure no problems.

Another thing which I don't know at the moment; Are Activators allowed on Entity, Values and Transients and what is the semantics in that case, since passivation() is definitely not defined for Values and Transients, and only vaguely imaginable for Entities.


As usual, it is probably a quite large topic to flesh out in detail, just like the good old days...


Niclas


--
You received this message because you are subscribed to the Google Groups "qi4j-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to qi4j-dev+u...@googlegroups.com.
To post to this group, send email to qi4j...@googlegroups.com.
Visit this group at http://groups.google.com/group/qi4j-dev.
For more options, visit https://groups.google.com/groups/opt_out.

Paul Merlin

unread,
Dec 23, 2013, 8:45:34 AM12/23/13
to qi4j...@googlegroups.com
Gang,

Before going further
on the Activators, I cleaned up the code
a bit to make it easier to grasp. Activation events handling
(from 1.x) is now merged into 2.x ActivationDelegate. This
allowed to remove duplicated code throughout the Structure.

I also added tests that ensure that PassivationException stack
traces contains every encountered error (from ActivationEvent
listeners, Activators, the Activatee and its children).


I feel that the high level activation execution model should be
settled before we discuss the "Activator as fragments" route.

The Activation acts on Structure and Services (ServiceReferences).
Both Structure elements (Application, Layer, Module) and Services
support event listeners *and* Activators.

On Application activation: Structure is eagerly activated ;
Services are lazily activated ; except if they are
instantiatedOnStartup(). Passivation occurs in reverse order.


Here is the actual execution and error handling model. I'm sure
this will raise comments.


Activation
Fail-fast execution order is:
  • Fire ACTIVATING ActivationEvent
  • Call beforeActivation() on each Activator
  • Call activate() on children
  • Call afterActivation on each Activator
  • Fire ACTIVATED ActivationEvent
If an Exception is thrown, already activated nodes are passivated.
@throws ActivationException with first Exception of activation
plus the PassivationException if any


Passivation
Fail safe execution order is:
  • Fire PASSIVATING ActivationEvent
  • Call beforePassivation() on each Activator
  • Call passivate() on children
  • Call afterPassivation() on each Activator
  • Fire PASSIVATED ActivationEvent
@throws PassivationException after passivation with all Exceptions
of passivation if any


IOW, Passivation continue regardless of Exceptions and raise a
PassivationException that has every errors in its stacktrace
(thanks to Java 7 suppressed exceptions).

This is far from ideal since errors during Passivation can lead to
invalid state. Here is an example: given an Activator that do some
work on passivation and a PASSIVATING event listener, when
passivating, the event listener is called first, then, what if the
Activator depends on something done in the listener?

At this point I still don't know how to ensure application
developers can't create such a situation while providing
understandable and solid passivation. Any idea?


Finally, if we enhance Activators to become composite fragments,
we would have to remove their support on Structure elements as
they aren't composites.


Cheers

/Paul

Paul Merlin

unread,
Jan 5, 2014, 7:15:46 AM1/5/14
to qi4j...@googlegroups.com
Niclas,

Thanks for your response!

Niclas Hedhman a écrit :
I think you raise 2 issues in the same mail;

 a. How to ensure Passivation robustness?
 b. How to reconcile Activators as Fragments?
Yep.

For a., Passivation, or its equivalent, in any application today is more often than not a pure coincidence if it happens to work. Few Java applications (and probably most libraries) are capable of managed shutdown. 
Qi4j had an early ambition to make passivation part of the scope, and I think the general solution is relatively nice and you are now pushing the envelope, or the gold standard if you like, to a new level, where not only should the application shutdown neatly, but even serious problems during shutdown should do the right thing.

My take on this; Introduce 2 PassivationException types. The normal one, which simply reporting problems that may or may not be expected, such as "can't read a file" or "no connection with...". The second one is when an internal application inconsistency has been detected. This would simply terminate any further "child passivations" but "sibling passivations" would continue.
Further, java.lang.Error should probably be treated in that same fashion.
I'll leave the implementation as it is for now. I need to
contemplate this a bit more.

For b., your starting point is incorrect. I never argued that @Activators implementations should be fragments of the composite, but that injections should work. So, the activators would have more in common with Object than Composite, in that @This and @Invocation is simply not available. And possibly, the entire Object model runtime could be used for the implementation, since instantiation from class names are default. @Uses could have the object of activation passed to it, and hence would allow me to get a reference to that instance. I haven't spent much analysis on whether this makes a lot of sense, but at least it is a starting point.
Ok, I'll try to come up with a proposal in the coming weeks.

Cheers

/Paul

Paul Merlin

unread,
Jan 7, 2014, 4:39:07 AM1/7/14
to qi4j...@googlegroups.com
Gang,

I just pushed a commit that brings injection support for
Activators (a56f06b3fe44a5c4813c33af02efb57723d96f71).



Activators can be assembled on Structure (Application, Layers,
Modules) and Services (composites or imported).

Activators assembled on Structure are NOT injectables
(InjectionContext needs a ModuleInstance) and are instanciated
directly (clazz.newInstance()).

Activators assembled on Services support @Structure, @Service
and @Uses injection points and are instanciated using the same
mechanism as Objects. @This is not supported.

I did not change the Activator API, the "activatee" is still
passed as before/after[Activation|Passivation] method
parameter.

Injection is tested in:
org.qi4j.runtime.injection.ActivatorInjectionTest


Moreover, Activators are now part of the ApplicationDescriptor
visitable hierarchy. Dependencies are bound at Application
creation.


Changes in core are relatively small. Most of the changes,
code-wise, are in tools/model-details that is
enhanced to
provide Activators details, including injection points.
Envisage should be updated to show theses details.


Niclas, WDYT?

Once we're good I'll update the documentation accordingly.


Cheers

/Paul

Paul Merlin

unread,
Jan 13, 2014, 7:28:17 AM1/13/14
to qi4j...@googlegroups.com
Niclas,

Niclas Hedhman a écrit :
> Sounds and Looks good.
> I browsed that particular commit, and I can't say that I have done
> proper review, but nothing stands out in any negative way, although I
> skipped tools/ altogether.
Good.

> I came to think about one thing; ATM the activated service is passed
> into the method as an argument, but @This annotation is actually much
> more 'natural'. Does that make more sense?
@This support is pretty tied to Composite handling. Activators are not
part of the composite they activate, they are POJOs.
Supporting @This injection in Activators would mean much more changes
and I'm not sure it is worth it.

> Also, does the code check that the ActiveeType of an Activator is
> compatible with the type the Activator is assigned to?
Not sure if it is ensured during bootstrap, will check that later.
Anyway, if types do mismatch, it will fail on activation.

> We probably need to discuss "tools" quite a bit, since I am working on
> something along those lines as well. Ie. I want the application model
> to be available as a JSON object, and then re-create Envisage as
> renderer in Javascript with D3. And it feels like some support that
> may now be in tools/ should actually sit in SPI.
Yeah, we talked about d3js, can't wait to see the result.

All data shown in Envisage comes from the tools/model-detail module.
I was thinking about a JSON representation of ApplicationDetailDescriptor.

Cheers

/Paul

Paul Merlin

unread,
Jan 20, 2014, 12:22:17 PM1/20/14
to qi4j...@googlegroups.com
Niclas,

Paul Merlin a écrit :

Also, does the code check that the ActiveeType of an Activator is compatible with the type the Activator is assigned to?
Not sure if it is ensured during bootstrap, will check that later.
Anyway, if types do mismatch, it will fail on activation.
There's no check prior activation for now.
Created QI-385 to keep track of it.



We probably need to discuss "tools" quite a bit, since I am working on something along those lines as well. Ie. I want the application model to be available as a JSON object, and then re-create Envisage as renderer in Javascript with D3. And it feels like some support that may now be in tools/ should actually sit in SPI.
Yeah, we talked about d3js, can't wait to see the result.

All data shown in Envisage comes from the tools/model-detail module.
I was thinking about a JSON representation of ApplicationDetailDescriptor.
To continue about "tools", I'm wondering :

Should we reuse model-detail and find a place for it in spi (refactored as
needed) or do you have something else in mind / on disk ?

Cheers

/Paul

Reply all
Reply to author
Forward
0 new messages