On 3 mars 2014, at 16:48, Bengt Rodehav <[email protected]> wrote: > I now tried to call only one of those methods with the following result: > > ONLY SELECTED > > bin\karaf.bat clean > ------------------- > accept: intercepted > onServiceArrival: 1 matching references > getServiceReferences > accept: intercepted > > bin\karaf.bat > ------------- > accept: intercepted > configurationChanged invalidating... > Invalidating selected... > Done invalidating > Validated > getServiceReferences > Invalidated > > > ONLY MATCHING > > bin\karaf.bat clean > ------------------- > accept: intercepted > onServiceArrival: 1 matching references > getServiceReferences > > bin\karaf.bat > ------------- > karaf@root> accept: intercepted > configurationChanged invalidating... > Invalidating matching... > accept: intercepted > Done invalidating > Validated > getServiceReferences > Invalidated > > It seems to give the same result as calling both of them.
Invalidating matching services, also invalidate the selected services (as selected is a sorted subset of matching). So, something is wrong when invalidating the matching service set. I suspect something in org.apache.felix.ipojo.dependency.impl.ServiceReferenceManager#computeChangesInMatchingServices. Clement > > /Bengt > > > 2014-03-03 16:36 GMT+01:00 Bengt Rodehav <[email protected]>: > >> I call both of them: >> >> public void invalidateSelectedServices() { >> List<DependencyModel> list = new ArrayList<DependencyModel>(); >> synchronized (this) { >> list.addAll(dependencies); >> } >> >> for (DependencyModel dep : list) { >> if (isMine(dep)) { >> System.out.println("Invalidating matching..."); >> dep.invalidateMatchingServices(); >> System.out.println("Invalidating selected..."); >> dep.invalidateSelectedServices(); >> System.out.println("Done invalidating"); >> } >> } >> } >> >> @Override >> synchronized public void configurationChanged(ComponentInstance theArg0, >> Map<String, Object> theArg1) { >> System.out.println("configurationChanged invalidating..."); >> invalidateSelectedServices(); >> } >> >> I think I used to only call invalidateSelectedServices() but then I had >> the opposite problem. Since the accept() method wasn't called, the >> intercepted property was not set to true. Also, if I only call >> invalidateMatchingServices(), the service references are not recalculated. >> It is important that both my accept() method and my getServiceReferences() >> method are called. >> >> Sounds like this might be an issue now that you mention it. How are the >> invalidateXYZ() methods supposed to work? >> >> /Bengt >> >> >> 2014-03-03 16:19 GMT+01:00 Clement Escoffier <[email protected]> >> : >> >> >>> 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] >>> >>> >> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]

