felix-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Clement Escoffier <clement.escoff...@gmail.com>
Subject Re: iPOJO and dynamic requires
Date Thu, 03 Oct 2013 07:09:01 GMT
Hi,

On 3 oct. 2013, at 08:33, Bengt Rodehav <bengt@rodehav.com> wrote:

> A question related to my workaround Clement.
> 
> To make sure that my lifecycle controller's value is up to date I need to
> recalculate it every time the array of required services change. My code
> for this looks as follows:
> 
>  @Requires(optional = true, id = "processors")
>  private IOrchestrationProcessor[] mProcessors;
> 
>  @Bind(id = "processors")
>  public void bindProcessors() {
>    updateAggregateValid();
>  }
> 
>  @Unbind(id = "processors")
>  public void unbindProcessors() {
>    updateAggregateValid();
>  }
> 
>  @Modified(id = "processors")
>  public void modifiedProcessors() {
>    updateAggregateValid();
>  }
> 
> The function updateAggregateValid() checks if all my configurable
> requirements are met and then sets the controller value to true, otherwise
> to false. I'm not sure when the @Modified method is called. At first it
> seemed like @Modified would be the only callback I needed but it does not
> seem to be called on "unbind". Now I suspect that it is enough with @Bind
> and @Unbind - @Modified seems unnecessary.
> 
> What callbacks do I need to handle in order to react on all changes to the
> list of required services?
> 

Bind and Unbind are covering your case. The modified callbacks mean that one service has been
updated (its service properties have changed) but it still matches the filter. In your case,
it's not relevant.

Clement

PS: `still matches the filter` means, from the interceptor perspective, has been accepted
by all tracking interceptors, including the filter, managing the dependency.


> /Bengt
> 
> 
> 
> 
> 2013/10/2 Bengt Rodehav <bengt@rodehav.com>
> 
>> Thanks for your detailed response Clement!
>> 
>> Sounds very interesting indeed although the fact that I can't change the
>> optionality sounds like a show stopper to me. In my case the list of
>> services to require can be >= 0. If, using config admin, I specify an empty
>> list then the service dependency must be optional. If the list is non-empty
>> then it must not be optional. I can't see how I can solve this using the
>> interceptors (although I haven't read the documentation yet :-)).
>> 
>> /Bengt
>> 
>> 
>> 2013/10/2 clement escoffier <clement.escoffier@gmail.com>
>> 
>>> Sent from my iPhone
>>> 
>>>> On 2 oct. 2013, at 20:32, Bengt Rodehav <bengt@rodehav.com> wrote:
>>>> 
>>>> Interesting. Do you think it would also be possible to do an
>>> all-or-nothing
>>>> approach? E g if I want to require A and B, I could check if both A and
>>> B
>>>> are available. If not, I would make the list empty thus making my
>>> instance
>>>> invalid? Or can I just say that the dependency is unresolved without
>>> having
>>>> to change the list?
>>> 
>>> Yes you can to that. I would say that the easiest way is to implement
>>> a ranking interceptor that returns an empty array until both services
>>> are there. When both are there, it returns both.
>>> 
>>> Notice that returning an empty array invalidates the dependency. For
>>> the instance it would just means : no services.
>>> 
>>>> 
>>>> BTW I did experiment a little with dynamically changing the "optionable"
>>>> property of the requires dependency using the dependency manager. I
>>> never
>>>> did get that to work. It always stayed at the same value it got through
>>> the
>>>> Requires annotation. Is that as designed or a bug?
>>>> 
>>> 
>>> Optionality cannot be changed, however the filter can. I can't
>>> remember the exact reason for that.
>>> 
>>>> I currently did a workaround using the life cycle controller as adviced
>>> by
>>>> Richard. Whenever anything changes that could affect the validity of the
>>>> instance I recalculate the life cycle controller value to reflect that.
>>> For
>>>> instance if the list of dependencies change I recalculate and check if
>>> all
>>>> my required services are in the list. If not I set the controller value
>>> to
>>>> false.
>>>> It works but the code is not very nice and easy to understand. It'll
>>> have
>>>> to do for now.
>>>> 
>>> 
>>> I did like this several times and was never happy of the result,
>>> especially it may mix, in your component code, business logic with
>>> higher-level rules and data. Very hard to maintain on the long term,
>>> unclear ad likely spaghetti-like. That's one of the reason we came up
>>> with the interceptors.
>>> 
>>> 
>>>> Clement, is the 1.10.x version released? I'm on a pretty old version and
>>>> should probably upgrade. Also, is there any documentation regarding the
>>>> interceptors you mentioned?
>>> 
>>> The 1.10.1 was released in june. A 1.11 is under preparation (feature
>>> complete, bug-fix complete, lacks some tests and documentation). We
>>> plan to release it next week.
>>> 
>>> The good news is that it includes the interceptor documentation.
>>> 
>>> Clement
>>> 
>>> 
>>>> /Bengt
>>>> 
>>>> 
>>>> 2013/10/2 Clement Escoffier <clement.escoffier@gmail.com>
>>>> 
>>>>> Hi,
>>>>> 
>>>>> Not sure it would meet your requirements, but in the 1.10.x, we added
>>>>> service dependency interceptors. Interceptors are external entities
>>>>> involved in the service resolution. We have 3 types on interceptors:
>>>>> 
>>>>> - tracking interceptors allow hiding services, or selecting the set of
>>>>> services seen by the service dependency (the LDAP filter is a tracking
>>>>> interceptor)
>>>>> - ranking interceptors can change the order of the services (the
>>>>> comparator is a ranking interceptor)
>>>>> - binding interceptors can change the injected service objects (to be
>>> used
>>>>> with caution ;-))
>>>>> 
>>>>> You can, without too much effort, write an interceptor that will shape
>>> the
>>>>> processor list as you want.
>>>>> 
>>>>> As said above, interceptors are external entities. Actually, they are
>>>>> services with a special 'target' property indicating in which
>>> dependencies
>>>>> they want to be involved. So, an interceptor can select one very
>>> specific
>>>>> dependency, all dependencies of an instance, all dependencies
>>> targeting a
>>>>> specific interface…
>>>>> 
>>>>> Unfortunately, there is a long overdue issue about interceptors:
>>>>> FELIX-4136 Document service dependency interceptors.
>>>>> 
>>>>> Best regards,
>>>>> 
>>>>> Clement
>>>>> 
>>>>> 
>>>>>> On 2 oct. 2013, at 15:57, Bengt Rodehav <bengt@rodehav.com>
wrote:
>>>>>> 
>>>>>> Thanks for your reply Richard.
>>>>>> 
>>>>>> I am using a lifecycle controller already to make it possible to
>>>>>> enable/disable my services via a GUI. I'll see if I can use it for
>>> this
>>>>>> purpose.
>>>>>> 
>>>>>> I've also tried the following approach: Keep track of all possible
>>>>> services
>>>>>> that expose the interface I'm intererested in as follows:
>>>>>> 
>>>>>> @Requires(optional = true)
>>>>>> private IOrchestrationProcessor[] mProcessors;
>>>>>> 
>>>>>> In runtime, when my service is being activated (prior to creating
the
>>>>> camel
>>>>>> route) I check to see if all required processors exist, if not I
>>> throw an
>>>>>> exception. Unfortunately I have no control of in what order the
>>> services
>>>>>> will be activated so its hard to ever get the camel route created
this
>>>>> way.
>>>>>> A lot of the time a "required" services is activated a bit later.
>>>>>> 
>>>>>> /Bengt
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 2013/10/2 Richard S. Hall <heavy@ungoverned.org>
>>>>>> 
>>>>>>> 
>>>>>>>> On 10/2/13 08:42 , Bengt Rodehav wrote:
>>>>>>>> 
>>>>>>>> I'm creating a dynamic processing component using iPOJO and
Camel.
>>> The
>>>>>>>> idea
>>>>>>>> is to dynamically specify (via config admin) a number of
processor
>>>>> id's.
>>>>>>>> In
>>>>>>>> runtime I want to find the matching processors (the processors
are
>>>>> Camel
>>>>>>>> processors published as OSGi services) with the correct id.
>>>>>>>> 
>>>>>>>> E g if I specify a list of services to {A,B} (FileInstall
recognizes
>>>>> this
>>>>>>>> as a list). I want to require those services in order for
my iPojo
>>>>>>>> instance
>>>>>>>> to become valid. It was much harder than I thought.
>>>>>>>> 
>>>>>>>> I've tried something like:
>>>>>>>> 
>>>>>>>> @Property(name = "processors", mandatory = false, value =
"")
>>>>>>>> public void setProcessors(String[] theProcessorIds) {
>>>>>>>>   mProcessorIds = theProcessorIds;
>>>>>>>>   updateProcessorFilter();
>>>>>>>> }
>>>>>>>> 
>>>>>>>> @Requires
>>>>>>>> private Processor[] mProcessors;
>>>>>>>> 
>>>>>>>> The idea is that whenever the configuration property "processors"
is
>>>>>>>> updated, I dynamically update the ldap filter on the dependency
>>>>>>>> mProcessors. I've used this approach before and it has worked
when
>>>>> using a
>>>>>>>> single dependency (not an array).
>>>>>>>> 
>>>>>>>> The problem is that I want to specifically require each specified
>>>>>>>> processor. In the example above, I require one processor
with id=A
>>> AND
>>>>> one
>>>>>>>> processor with id=B. It's not enough with anyone of them
since I
>>> want
>>>>> to
>>>>>>>> invoke them one after another.
>>>>>>>> 
>>>>>>>> Can I use a filter for this? I've been thinking of something
like
>>> this:
>>>>>>>> 
>>>>>>>> (|(processorId=A)(processorId=**B))
>>>>>>>> 
>>>>>>>> This would match both my processors but if one of them were
missing
>>> my
>>>>>>>> instance would still become valid which I don't want.
>>>>>>> 
>>>>>>> I don't think there is anyway to do what you want. This is
>>> essentially
>>>>> an
>>>>>>> "N cardinality" requirement, where you want to say that you require
>>>>>>> specifically N of something. Such requirements had been discussed
>>> over
>>>>> the
>>>>>>> years for Service Binder, Declarative Services, etc., but we
could
>>> never
>>>>>>> agree on their usefulness or how to do them, so we just left
it as
>>> it is
>>>>>>> now (i.e., optional, at least one...).
>>>>>>> 
>>>>>>> Other than adding some sort of threshold to service dependencies,
I
>>>>> don't
>>>>>>> see this happening. You could potentially create an iPOJO lifecycle
>>>>>>> controller that would keep your component invalid until it matched
>>> the
>>>>>>> required number of services (if you can get this information
in the
>>>>>>> handler)...or perhaps write/extend the service dependency handler.
>>>>>>> 
>>>>>>> -> richard
>>>>>>> 
>>>>>>> 
>>>>>>>> /Bengt
>>>>> 
>>> ------------------------------**------------------------------**---------
>>>>>>> To unsubscribe, e-mail: users-unsubscribe@felix.**apache.org<
>>>>> users-unsubscribe@felix.apache.org>
>>>>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>> 
>>>>> 
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>> 
>>>>> 
>>> 
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>> For additional commands, e-mail: users-help@felix.apache.org
>>> 
>>> 
>> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Mime
View raw message