On Tue, Nov 1, 2011 at 1:15 PM, Alex Karasulu <[email protected]> wrote:
> > > On Mon, Oct 31, 2011 at 8:52 PM, Emmanuel Lecharny <[email protected]>wrote: > >> On 10/31/11 10:17 AM, Alex Karasulu wrote: >> >>> On Sun, Oct 30, 2011 at 7:02 PM, Göktürk Gezer<[email protected]>* >>> *wrote: >>> >>> Hi Devs, >>>> >>>> I'd like to do some brainstorming about Interceptor extension mechanism >>>> which we're about to implement. Ideas those will come out from that >>>> thread >>>> will enlighten our way on other extension points of the ApacheDS. >>>> >>>> The first main issue is whether we're going to preserve old standalone >>>> ApacheDS or not? >>>> >>>> Let's be really careful about the common terminology we will be using >>> for >>> this discussion. When you say "standalone ApacheDS", I automatically >>> think >>> about the standalone ApacheDS maven module that holds the ApacheDS main() >>> application launcher. >>> >>> In a previous thread Pierre recommended keeping such a module but >>> modifing >>> it so that it starts up an OSGi container which launches the ApacheDS >>> bundles. However the user experience does not change much. This merely >>> allows users to start up ApacheDS from the command line as before but >>> behind the scenes an OSGi container is launched as the main() >>> application. >>> This is one option and I think I like this approach because this way we >>> don't have to maintain a monolithic application startup and a OSGi >>> startup. >>> >>> >>> Preserving API in nonOSGI environments had purpose. And with the very >>>> simple method we've used in API, we can also preserve ApacheDS's nonOSGI >>>> version too. >>>> >>>> Sure we can do anything but will it add additional complexity and >>> overhead >>> for maintaining code and what's the gain that we get? Will it make >>> debugging easier to maintain this non-OSGi configuration? >>> >>> >>> Doing it will have pros and cons. >>>> >>>> Ahh there you go with the pros and cons :-). >>> >>> >>> The main advantage will be of course letting existing user semantics >>>> unchanged. >>>> >>>> It appears to me that you're talking about more than just the >>> application >>> launcher verses the OSGi based launch sequence. I guess you're referring >>> to >>> all the configuration mechanism changes that will impact the different >>> cases. >>> >>> To me these usage semantic changes are small compared to the overall >>> gains >>> we will get. >>> >>> >>> But implementing extendibility without breaking ApaheDS's nonOSGI >>>> version >>>> will put some limits on our extension capability on individual >>>> components. >>>> Besides those limitations, we'll also end up having two different >>>> runtime >>>> behaviour of ApacheDS. Documentation will be obviously painful. And some >>>> aspects won't be implementable if we choose to preserve nonOSGI version. >>>> For example, OSGI can give us the opportunity to don't restart server >>>> after >>>> some changes on configuration, which will be perfect improvement of >>>> course. >>>> But to make this we must go fully OSGI. List is long. >>>> >>>> Yeah I prefer to forget about maintaining the non-OSGi version. The >>> "standalone ApacheDS" maven module can launch the OSGi container or Karaf >>> then have the OSGi environment fire up ApacheDS as a full OSGi >>> application. >>> >>> >>> >>> We've talked about it before but i wanted to ask that question again, >>>> because its an alive topic and subject to change. Maybe some of yours >>>> mind >>>> could have been changed, and i want to know if it did. If we proceed >>>> like >>>> what we've been talked earlier, then I'm going to make ApacheDS (not >>>> shared) an OSGI application, and use all of its loveliness. >>>> >>>> >>>> +1 >>> >>> >>> To talk about Interceptors specifically, here is the design that i'm >>>> thinking. To manage OSGI heavy dynamic nature, we must implement our >>>> Interceptor related code in the closest module that is using >>>> Interceptors, >>>> which is InterceptorChain in our case. First step will be implement a >>>> component called InterceptorHub which is responsible for keeping list of >>>> all Interceptors installed in the container(means installed in OSGI as >>>> bundle). This hub will create an instance of every Interceptor per every >>>> ApacheDS instance and keep it. >>>> >>>> When an InterceptorChain want to iterate through interceptors, it will >>>> get >>>> them from InterceptorHub rather then DirectoryService.**getInterceptors(). >>>> So >>>> it will get the most recent list of interceptors every time. >>>> >>>> >>>> OK >>> >>> Just a question: why not just make the InterceptorChain act as or perform >>> the duties of the hub? I guess the hub is intended as an internal >>> component >>> of the chain that hides some details relating to OSGi from the chain? >>> >>> >>> Currently in our config.ldif file, there is an interceptors entries. We >>>> can leave those entries there for specifying mandatory interceptors. So >>>> if >>>> any of them is not exists at the time server is starting we can throw an >>>> exception saying necessary interceptor is not exist. But we won't be >>>> have >>>> to list additional interceptors in that list. They will be automatically >>>> attached to the active ApacheDS instances. >>>> >>>> We'll also change the Interceptor implementations to be an IPojo >>>> component. Those components will publish two main properties. First is >>>> their ordering and the second is their bypass list. >>>> >>>> Ordering is something we've talked about but i couldn't get a clear >>>> explanation about it. What i suggest is like this: we publish three >>>> kind of >>>> ordering from interceptor: strict, level and relax. "strict" means >>>> strict >>>> ordering, this will be published from core interceptors and that strict >>>> order will create a level. If we publish it as level we must also >>>> attach an >>>> index with it, such as level-3. If we publish it as relax it means it >>>> can >>>> be called anywhere in the chain after the strict ones. So lets suppose >>>> we >>>> documented the core interceptor ordering like: >>>> >>>> 1- InterceptorA >>>> 2- InterceptorB >>>> 3- InterceptorC >>>> >>>> So there is 3 level in interceptor chain. If somebody implement an >>>> additional interceptor named InterceptorD and publish its ordering >>>> as level-2, it is saying it must be called after InterceptorA(level-1). >>>> So >>>> the new list will be: >>>> >>>> 1- InterceptorA >>>> 2- InterceptorD >>>> InterceptorB >>>> 3- InterceptorC >>>> >>>> I didnt't numbered B as 3 but rather i grouped it with the InterceptorD, >>>> putting InterceptorD above it. Why? What happens if vendor wants to >>>> implement two custom interceptor named InterceptorD and InterceptorE and >>>> want 2 of them to be called right after InterceptorA(after 1th level) >>>> but >>>> want InterceptorD to be called first. So we must suborder those 2 >>>> interceptors. That's why i treated the first core list as levels rather >>>> than orders ! So the ordering which is published from custom >>>> interceptor is >>>> not sufficient to describe good ordering. We must also publish >>>> subordering >>>> which specifies the ordering between that specific vendor's >>>> interceptors. >>>> >>>> >>>> This is rather interesting. This approach never occurred to me but it's >>> appealing. I'll give this some thought and also would like to hear from >>> others on the list about it. >>> >> >> Jumping on Göktürk idea, some proposal. >> >> We all know that the core interceptors are to be executed in a given >> order. Calling the NormalizationInterceptor after the >> CollectiveAttributeInterceptor does not make any sense. >> >> OTOH, we allow the admin to modify the order, simply by changing the >> configuration, and it could lead to some bad bad things... >> >> What if we create an implicit order by defining which interceptor is >> allowed before each interceptor ? For instance, this is the default order : >> >> 1 normalizationInterceptor >> 2 authenticationInterceptor >> 3 referralInterceptor >> 4 aciAuthorizationInterceptor >> 5 defaultAuthorizationIntercepto**r >> 6 exceptionInterceptor >> 7 operationalAttributeIntercepto**r >> 8 keyDerivationInterceptor >> 9 passwordHashingInterceptor >> 10 schemaInterceptor >> 11 collectiveAttributeInterceptor >> 12 subentryInterceptor >> 13 eventInterceptor >> 14 triggerInterceptor >> >> We could obtain the same order by replacing the ads-interceptororder AT >> by a ads-previousInterceptor : >> >> 1 normalizationInterceptor ( previous : null ) >> 2 authenticationInterceptor ( previous : normalizationInterceptor ) >> 3 referralInterceptor ( previous : authenticationInterceptor ) >> 4 aciAuthorizationInterceptor ( previous : referralInterceptor ) >> 5 defaultAuthorizationIntercepto**r ( previous : >> aciAuthorizationInterceptor, referralInterceptor ) (here, the >> aciAuthorizationInterceptor may be disabled) >> 6 exceptionInterceptor ( previous : defaultAuthorizationIntercepto**r ) >> 7 operationalAttributeIntercepto**r ( previous : exceptionInterceptor ) >> 8 keyDerivationInterceptor ( previous : operationalAttributeIntercepto**r >> ) >> 9 passwordHashingInterceptor ( previous : keyDerivationInterceptor ) >> 10 schemaInterceptor ( previous : passwordHashingInterceptor ) >> 11 collectiveAttributeInterceptor ( previous : schemaInterceptor ) >> 12 subentryInterceptor ( previous : collectiveAttributeInterceptor ) >> 13 eventInterceptor ( previous : subentryInterceptor ) >> 14 triggerInterceptor ( previous : eventInterceptor ) >> >> Now, for interceptors that has no specific requirement, we can set the >> previous AT to the previous AT it will follow. >> >> The key is that we must distinguished between critical inteceptors (the >> level-1 interceptors) and others. We enforce the position only within one >> level (ie, level-1 interceptors orders are checked, then level-2, then >> level-3). So we can add a non critical interceptor (ie level-2 or 3) in the >> chain between two critical interceptors, without creating any trouble in >> the critical interceptor order : the check for level-1 interceptors' order >> is done ignoring level-2 interceptors. >> >> thoughts ? > > > Here's the one big point that sticks out in my mind regarding such > ordering mechanisms. When you have to provide dependency information > directly to an Interceptor (name, identifier, or some other descriptor for > the interceptor), then you're creating an inherent dependency. And on top > of this you need to know a priori the composition of the interceptor chain. > > If we want safe variability which can only happen with the proper ordering > of functionality while allowing for swappable interceptors including the > critical ones for a customized version, then we need to have some > indirection. Here's what I had proposed in the past: > > (1) Define some general mandatory invocation aspects that must be handled > by one or more Interceptors, either working alone or together. For example > these mandatory aspect descriptors can be: > > normalization > authentication > referral-handling > access-control > exception-handling > operational-attribute-handling > schema-checking > subentry-handling > event-handling > > These are general mandatory aspect descriptors. They are not dependent on > any specific interceptor implementation. We know how these must be ordered > to have the server operate properly. You just can't do much before > normalization right? What interceptor does this is irrelevant. > > So my recommendation is to manage this general invocation aspect > descriptor order and bind interceptors to the aspect descriptors at > component initialization time. What this takes is having an Interceptor > announce which general aspects it is involved with. So if I have > FooInterceptor which manages schema-checking, then when this interceptor > initializes, the chain can determine which aspect it is associated with by > asking the component. Then it knows where in the chain to inject the > component. > > This strategy/pattern creates a level of indirection between the aspect > functions performed by Interceptors and their implementations, allowing for > dependency free management of their ordering. > This is very similar to deferred (late) binding in Java. You have general funcationality in the windowing toolkits (open a window) but the actual toolkit binding (to the specific libraries: gwt vs. cocao?) is deferred until class loading of windowing system classes. > > Now Gokturk's idea deals with the non-essential injection and quite > frankly it sounds like a good idea to me to use levels (or hierarchy here) > while preserving essential-mandatory interceptor ordering. That's a > separate matter to consider however it might add additional implementation > complexity for us and make configuration matters a tiny bit more confusing > for our users. That's something we together must evaluate, however the > interceptor chain altering user profile is not the common user profile but > one where they know and understand the pitfalls (one would hope). > > -- > Best Regards, > -- Alex > > -- Best Regards, -- Alex
