I just discovered https://issues.apache.org/jira/browse/FELIX-4129 which is fixed. Sounds like this would make it possible to change the optionality dynamically like I needed - is that right?
This fix plus interceptors then seem like the perfect fit for me. /Bengt 2013/10/3 Bengt Rodehav <[email protected]> > OK - thanks. I can skip the @Modified then. > > I've had some more problems unfortunately. It seems like, although I use a > @Controller, which has the value "false", my instance still becomes valid. > Shortly thereafter it becomes invalid again but this "false start" gives me > problems. > > It's like the @Controller doesn't take effect immediately but only after a > while. Does this has anything to do with the fact that I set > "immediate=true" on my @Component? > > /Bengt > > > 2013/10/3 Clement Escoffier <[email protected]> > >> Hi, >> >> On 3 oct. 2013, at 08:33, Bengt Rodehav <[email protected]> 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 <[email protected]> >> > >> >> 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 <[email protected]> >> >> >> >>> Sent from my iPhone >> >>> >> >>>> On 2 oct. 2013, at 20:32, Bengt Rodehav <[email protected]> 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 <[email protected]> >> >>>> >> >>>>> 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 <[email protected]> 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 <[email protected]> >> >>>>>> >> >>>>>>> >> >>>>>>>> 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< >> >>>>> [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] >> >> >

