On 3 mars 2014, at 16:09, Bengt Rodehav <[email protected]> wrote:
> I now added logging to the following methods:
>
> - onServiceArrival
> - onServiceDeparture
> - onServiceModified
>
> I tried starting both with a clean start and then without clean. I got the
> following results:
>
> *bin\karaf.bat clean*
> accept: intercepted
> onServiceArrival: 1 matching references
> getServiceReferences
> accept: intercepted
>
> *bin\karaf.bat*
> accept: intercepted
> configurationChanged invalidating...
> Invalidating matching...
> accept: intercepted
> Invalidating selected...
> Done invalidating
> Validated
> getServiceReferences
> Invalidated
>
> As you can see the instance never becomes valid on a clean start. Then
> again, no configuration changes are detected on a clean start. It seems to
> be when I detect a configuration change and manually invalidate the
> dependencies that the problem appears.
>
> Does this give you any clue?
Which method are you calling ? invalidateMatchingServices, or
invalidateSelectedServices(), anyway it narrows the location of the bug to a
small amount of code:
public void invalidateMatchingServices() {
ChangeSet changeset;
try {
m_dependency.acquireWriteLockIfNotHeld();
m_matchingReferences.clear();
changeset = computeChangesInMatchingServices();
} finally {
m_dependency.releaseWriteLockIfHeld();
}
m_dependency.onChange(changeset);
}
public void invalidateSelectedServices() {
ChangeSet changeset;
try {
m_dependency.acquireWriteLockIfNotHeld();
ServiceReference oldBest = getFirstService();
List<ServiceReference> beforeRanking = getSelectedServices();
m_selectedReferences.clear();
final List<ServiceReference> allServices = getMatchingServices();
List<ServiceReference> references = Collections.emptyList();
if (!allServices.isEmpty()) {
references =
m_rankingInterceptor.getServiceReferences(m_dependency, allServices);
}
RankingResult result = computeDifferences(beforeRanking,
references);
m_selectedReferences = result.selected;
changeset = new ChangeSet(getSelectedServices(), result.departures,
result.arrivals, oldBest,
getFirstService(), null, null);
} finally {
m_dependency.releaseWriteLockIfHeld();
}
m_dependency.onChange(changeset);
}
>
> /Bengt
>
>
>
>
>
>
>
>
>
> 2014-03-03 15:53 GMT+01:00 Bengt Rodehav <[email protected]>:
>
>> OK - I now understand what you mean. It seems that the design is supposed
>> to do what I expected then. We think alike :-)
>>
>> I'll add some more tracing as you suggested and then get back to you.
>>
>> /Bengt
>>
>>
>> 2014-03-03 15:46 GMT+01:00 Clement Escoffier <[email protected]>
>> :
>>
>>
>>> On 3 mars 2014, at 15:18, Bengt Rodehav <[email protected]> wrote:
>>>
>>>> Hi Clement,
>>>>
>>>> Yes, I use the filter to make sure that the instance does not become
>>> valid
>>>> until it has been intercepted - that part seems to work. However, in my
>>>> case, the instance become valid AFTER my accept() method has been called
>>>> but BEFORE my getServiceReferences() method has been called. This is
>>>> causing my problems.
>>>>
>>>> I'm a little curious regarding your wording:
>>>>
>>>> "A (mandatory) dependency becomes valid only if the selected service
>>> set is
>>>> not empty. In other words, all your interceptors should have been called
>>>> before deciding to set the dependency state to valid."
>>>>
>>>> I don't see how the first sentence has anything to do with the second
>>>> sentence.
>>>
>>> This is how iPOJO resolves services. It first considers the services from
>>> the service registry (called base service set). This set is processed by
>>> tracking interceptor (such as LDAP filter...) to get a matching service set.
>>> Then, a ranking interceptor is called to sort the set, and to get the
>>> selected service set. A mandatory service dependency cannot be valid if
>>> this last set is empty (in theory). That means that both accept and
>>> getServiceReferences should have been called to determine whether or not
>>> the dependency is valid. The accept method is called to build the matching
>>> service set, while getServiceReferences is called to retrieve the selected
>>> service set.
>>>
>>>>
>>>> I have a dependency declared as follows:
>>>>
>>>> @Requires(optional = false, id = "extenders", filter =
>>>> "(intercepted=true)")
>>>> private IRouteExtender[] mExtenders;
>>>>
>>>> Thus it is mandatory. Also, there are services of type IRouteExtender
>>>> registered so that part is resolved. But until the accept() method has
>>> been
>>>> called the "(intercepted=true)" part is not satisfied. When my accept()
>>>> method has been called the "(intercepted=true)" part becomes satisfied
>>> and
>>>> my instance becomes valid right away instead of waiting for the result
>>> of
>>>> the getServiceReferences() method. This is the problem because in my
>>>> getServiceReferences() method I evalutate the matching dependencies (by
>>>> looking at a property) and determine that they are not valid. I
>>> therefore
>>>> return an empty set of matching service references and the instance now
>>>> becomes invalid.
>>>>
>>>> I do not think it should be possible to validate an instance "in the
>>> midst
>>>> of intercepting" as is the case for me. I must be completely done
>>>> intercepting first.
>>>
>>> That should not be the case. Definitely a bug.... The dependency state
>>> should not be re-evaluated before having notified the ranking interceptor.
>>>
>>> So far, you are implementing only getServiceReferences, can you implement
>>> and add traces in onServiceArrival ?
>>>
>>> Clement
>>>
>>>
>>>
>>>>
>>>> /Bengt
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> 2014-03-03 13:51 GMT+01:00 Clement Escoffier <
>>> [email protected]>:
>>>>
>>>>> Hi,
>>>>>
>>>>> On 3 mars 2014, at 13:14, Bengt Rodehav <[email protected]> wrote:
>>>>>
>>>>>> Hello again Clement!
>>>>>>
>>>>>> Skiing trip is now over - time to get back to the interceptors...
>>>>>>
>>>>>> Regarding your questions in the last post: Yes, I only add a property
>>> on
>>>>>> the chosen service reference (intercepted is set to true), I do not
>>>>> change
>>>>>> the filter.
>>>>>>
>>>>>> I have tested the theory regarding config admin / file install and it
>>> is
>>>>>> not the problem.
>>>>>>
>>>>>> It seems to me that there is no guarantee that both accept() and the
>>>>>> getServiceReferences() are both called before an instance becomes
>>> valid.
>>>>> I
>>>>>> haven't looked at the source code in detail yet but is the design such
>>>>> that
>>>>>> this is not supposed to be possible or am I requesting a new feature?
>>> In
>>>>>> other words, have I found a bug or not?
>>>>>>
>>>>>> Ideally I think it should work as follows:
>>>>>>
>>>>>> - When in "interceptor mode" the state of the instance should not
>>> change
>>>>>> until all the interceptors (and all callbacks of the interceptors)
>>> have
>>>>>> taken effect.
>>>>>>
>>>>>> - Initially then instance should not become valid until all the
>>>>>> interceptors (and all callbacks of the interceptors) have taken
>>> effect.
>>>>>>
>>>>>> With "interceptor mode" I mean that something has triggered iPojo to
>>>>> begin
>>>>>> calling the registered interceptors.
>>>>>>
>>>>>> Not sure if this is in accordance with your design. How is it
>>> supposed to
>>>>>> work?
>>>>>
>>>>>
>>>>> It might be a bug and a new feature.
>>>>>
>>>>> I designed interceptors to be highly dynamic, so can come and leave at
>>>>> anytime, and without having the components aware of them. That's why
>>>>> service dependencies do not know which interceptors handle them.
>>>>> Unfortunately, this design has some trade-off / drawbacks. If your
>>> instance
>>>>> starts before the interceptors, it might be valid for a little amount
>>> of
>>>>> time, until the interceptors handle the dependency. However in your
>>> case
>>>>> you have a filter on the dependency that should avoid this case.
>>>>>
>>>>> If you still have this filter, it is definitely a bug. A (mandatory)
>>>>> dependency becomes valid only if the selected service set is not
>>> empty. In
>>>>> other words, all your interceptors should have been called before
>>> deciding
>>>>> to set the dependency state to valid.
>>>>>
>>>>> About the feature, I start thinking that the independence between the
>>>>> interceptor and the dependencies may be problematic. For instance, I've
>>>>> another use case where they implement a new handler (an extension of
>>> the
>>>>> dependency handler) to ensure the availability of one specific
>>> interceptor.
>>>>> The dependency is invalid until the interceptor arrives.
>>>>>
>>>>> Clement
>>>>>
>>>>>>
>>>>>> /Bengt
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> 2014-02-24 8:17 GMT+01:00 Clement Escoffier <
>>> [email protected]
>>>>>> :
>>>>>>
>>>>>>>
>>>>>>> On 21 févr. 2014, at 14:15, Bengt Rodehav <[email protected]> wrote:
>>>>>>>
>>>>>>>> Hello Clement,
>>>>>>>>
>>>>>>>> Some comments inline below.
>>>>>>>>
>>>>>>>> /Bengt
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> 2014-02-21 12:53 GMT+01:00 Clement Escoffier <
>>>>>>> [email protected]>:
>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> On 20 févr. 2014, at 13:22, Bengt Rodehav <[email protected]>
>>> wrote:
>>>>>>>>>
>>>>>>>>>> This is a follow up on another discussion I had with Clement on
>>> this
>>>>>>>>>> mailing list:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>
>>> http://apache-felix.18485.x6.nabble.com/Using-iPojo-interceptors-tt5006168.html#a5006276
>>>>>>>>>>
>>>>>>>>>> I'm now trying to get the interceptor solution into production.
>>>>>>>>>>
>>>>>>>>>> Remember that I have to invalidate my instances when their
>>>>>>> configuration
>>>>>>>>> is
>>>>>>>>>> changed. This is because I need to re-evalutate the dependencies
>>> for
>>>>>>> the
>>>>>>>>>> instance.
>>>>>>>>>>
>>>>>>>>>> Originally, I only called the invalidateSelectedServices() method
>>> on
>>>>>>> the
>>>>>>>>>> DependencyModel. This worked mostly but not when starting a fresh
>>>>>>>>> container
>>>>>>>>>> (I use Karaf and start it with "bin\karaf.bat clean"). My instance
>>>>> then
>>>>>>>>>> first becomes valid but then becomes invalid. I think this is
>>> because
>>>>>>> of
>>>>>>>>>> the ordering. The accept() method had not been called prior to
>>>>>>>>>> the getServiceReferences() method. The dependency is therefore not
>>>>> set
>>>>>>> to
>>>>>>>>>> "intercepted=true" which makes it invalid.
>>>>>>>>>
>>>>>>>>> the filter is updated by the interceptor. (just want to be sure I
>>>>>>>>> understand). In that case, if the interceptor arrives after the
>>>>> instance
>>>>>>>>> creation, the filter will be set when the interceptor arrives.
>>>>>>>>>
>>>>>>>>
>>>>>>>> Yes, my interceptor sets intercepted to true on the dependency which
>>>>>>> makes
>>>>>>>> sure that the filter match.
>>>>>>>
>>>>>>> So the filter is not modified by the interceptor, it just add a new
>>>>>>> property on the chosen service reference to match the filter.
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Replacing the call to invalidateSelectedServices() with a call to
>>>>>>>>>> invalidateMatchingServices() seems to do the trick. However,
>>> there is
>>>>>>> one
>>>>>>>>>> small glitch that I would like to fix.
>>>>>>>>>>
>>>>>>>>>> If I have a configuration that should not be valid (e g I
>>> specified
>>>>> an
>>>>>>>>>> extender id that is not present) the instance should never be
>>> valid.
>>>>>>> But,
>>>>>>>>>> when starting Karaf (both with "bin\karaf.bat" and "bin\karaf.bat
>>>>>>>>> clean"),
>>>>>>>>>> the instance becomes valid before it becomes invalid. It does end
>>> up
>>>>> in
>>>>>>>>> the
>>>>>>>>>> right state (invalid in this case) but for a short period of time
>>> it
>>>>> is
>>>>>>>>>> valid which will cause a lot of things to happen in my code that
>>> then
>>>>>>>>> must
>>>>>>>>>> be reversed when it becomes invalid.
>>>>>>>>>>
>>>>>>>>>> I logged the sequence of events and it seems that the accept()
>>> method
>>>>>>> is
>>>>>>>>>> called first. I will then set "intercepted=true". This immediately
>>>>>>> makes
>>>>>>>>>> the instance valid. Shortly thereafter getServiceReferences() is
>>>>>>> called.
>>>>>>>>> I
>>>>>>>>>> will then re-calculate the dependency requirements and when I
>>> later
>>>>>>>>>> invalidate the dependencies the instance will become valid.
>>>>>>>>>>
>>>>>>>>>> So, there is a short time frame where the instance is valid
>>> although
>>>>> it
>>>>>>>>>> shouldn't be. How can I fix that?
>>>>>>>>>
>>>>>>>>> This looks like a bug, as the dependency can be valid only if the
>>> set
>>>>> of
>>>>>>>>> selected services is not empty. From what you say, it looks like
>>> the
>>>>>>>>> dependency is valid because the set of matching services is not
>>> empty.
>>>>>>>>>
>>>>>>>>
>>>>>>>> Is there anything I can do to investigate this? Is it possible for
>>> you
>>>>> to
>>>>>>>> take a look if there is indeed a "gap" where this can happen?
>>>>>>>
>>>>>>> My first guess would be in the ServiceReferenceManager coordinating
>>> the
>>>>>>> interceptors.
>>>>>>>
>>>>>>>>
>>>>>>>> I think that things are a little complicated since I also listen on
>>>>>>>> configuration changes. I need to recalculate the matching services
>>> when
>>>>>>> the
>>>>>>>> configuration of the intercepted instance changes. When starting the
>>>>>>>> container (Karaf), I get more than one configuration change and thus
>>>>> the
>>>>>>>> dependencies are invalidated more than once. What if the sequence
>>> were:
>>>>>>>>
>>>>>>>> 1. Configuration change causing the dependencies to become
>>> invalidated
>>>>>>>> 2. Accept. Will set intercepted to true
>>>>>>>> 3. getServiceReferences which will calculate the required
>>> dependencies
>>>>>>>> 4. Configuration change again causing the dependencies to become
>>>>>>> invalidated
>>>>>>>> 5. Accept. Will set intercepted to true
>>>>>>>> 6. getServiceReferences which will calculate the required
>>> dependencies
>>>>>>>>
>>>>>>>> Not sure if there is any point in which an instance could become
>>> valid
>>>>>>> when
>>>>>>>> it shouldn't.
>>>>>>>>
>>>>>>>> I will also try to see if the problem could be the configuration
>>>>> admin. I
>>>>>>>> use file install for my configuration. I have a feeling that the
>>> first
>>>>>>>> configuration being pushed is a default configuration and not the
>>> one
>>>>>>> from
>>>>>>>> the configuration file. Then that might explain it.
>>>>>>>>
>>>>>>>
>>>>>>> Oh, that's an interesting hint. That's definitely possible.
>>>>>>>
>>>>>>> Enjoy your vacations, mine are over....
>>>>>>>
>>>>>>>
>>>>>>> Regards,
>>>>>>>
>>>>>>> Clement
>>>>>>>
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> From my point of view this is similar to a transaction. I do not
>>> want
>>>>>>> the
>>>>>>>>>> instance to become valid before I have done all my "intercepting"
>>>>> which
>>>>>>>>> is
>>>>>>>>>> after BOTH the accept() method AND the getServiceReferences()
>>> method
>>>>>>> have
>>>>>>>>>> been called.
>>>>>>>>>
>>>>>>>>> In theory, it is how it should work...
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> BTW I also noted that the "dependencies" member in
>>>>>>>>>> the DefaultDependencyInterceptor class (I extend the
>>>>>>>>>> DefaultServiceRankingInterceptor class) seems to contain
>>> duplicates
>>>>> of
>>>>>>> my
>>>>>>>>>> dependency. The same DependencyModel instance occurs twice in the
>>>>> List.
>>>>>>>>>> Seems like a bug to me. Perhaps the List should be a Set?
>>>>>>>>>
>>>>>>>>> Definitely, could you open an issue ?
>>>>>>>>>
>>>>>>>>> Clement
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> /Bengt
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>> ---------------------------------------------------------------------
>>>>>>>>> To unsubscribe, e-mail: [email protected]
>>>>>>>>> For additional commands, e-mail: [email protected]
>>>>>>>
>>>>>>>
>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: [email protected]
>>>>> For additional commands, e-mail: [email protected]
>>>>>
>>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: [email protected]
>>> For additional commands, e-mail: [email protected]
>>>
>>>
>>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]