directory-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Alex Karasulu <akaras...@apache.org>
Subject Re: Implementing Interceptor Extendibility
Date Tue, 01 Nov 2011 11:25:09 GMT
On Tue, Nov 1, 2011 at 1:15 PM, Alex Karasulu <akarasulu@apache.org> wrote:

>
>
> On Mon, Oct 31, 2011 at 8:52 PM, Emmanuel Lecharny <elecharny@gmail.com>wrote:
>
>> On 10/31/11 10:17 AM, Alex Karasulu wrote:
>>
>>> On Sun, Oct 30, 2011 at 7:02 PM, Göktürk Gezer<gokturk.gezer@gmail.com>*
>>> *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

Mime
View raw message