Hi all,

Forgive the prepost here: need to report on a off list conversation I just
had with Emmanuel. We generated some very nice ideas on these matters. I'm
going to be very direct with implementation details rather than being high
level and general with these ideas to directly dump the thoughts:

(1)  For each intercepted operation (add, delete, modify etc), the server
maintains an ordered list of core aspect descriptors out of the box
(normalization, access-control, authorization etc) which must be applied in
order to an invocation of an intercepted operation.

To do this we can have an operation expose aspect ordering:

add.getAspects() ... returns order list or array of Aspects like
{Normalization, AccessControl, Authorization, ...}.

Dynamic configuration should allow us to change this ordered list on the
fly to introduce new aspects or remove old ones. Meaning if we like we can
define a new logical aspect like craptastic aspect and have it participate
in various operation invocations in the order we like it to participate.

This is our logical aspect ordering model and exposed as a dynamic
configuration point in the server.

(2) Each Interceptor must publish one and only one aspect it participates
in. The aspect must be in the set of aspects configured in the server via
dynamic configuration so we have a list of aspects managed by the server
without the need for ordering since ordering is operation specific.

normalization
craptastic
authentication
access-control
foobar

...

Interceptor.getAspect()  should return an aspect within this set, and if it
does not then it simply is not considered for injection into the chains
created.

In the configuration area we also manage operation aspects with order:

bind: normalization, authentication
add: normalization ....
del: ...
modify ....
...

The user is constrained to only include aspects in the set of supported
aspects above. No problem though, the user can add his or her custom aspect
to the set, then can start adding that aspect to the operation aspect lists
in the configuration. If no interceptor exists to supply functionality for
that aspect, no problem it's just not injected during actual physical chain
construction time. Once an interceptor appears it can be considered for
injection when calculating the interceptor ordering in chains ... see below.

This is good for the OSGi model where services (interceptors in this case)
can come and go.

(3) The server tracks the actual interceptor implementation execution order
by calculating this order using these aspects on a per operation basis. If
interceptor Foo.getAspect = Normalization and interceptor Bar.getAspect =
Authentication, then for bind the interceptor implementation order would
be:

Foo, Bar

The result of this calculation will be dynamically configurable as
described above by altering configurations for aspect order per operation.
This way we can add new aspects, that have not even been conceived of while
creating ApacheDS. Users will have this freedom. And at chain construction
time the right implementations will be properly selected and injected in
the right order.

(3) At session creation time, the server constructs interceptor reference
lists with actual references to interceptor instances for each operation.
Sessions do not need unique interceptor instances: the interceptors are
shared across sessions and chains. The server uses the aspect information
from an Interceptor and operation aspect lists to determine this reference
list order and construct it.

For Bind operation the interceptor reference list would be Foo, Bar as in
the example above.

Each session has an interceptor reference list calculated for each
operation and this is stored within each session.   This way sessions can
modify their interceptor reference lists for various operations to have
fine grained auditing for example for a single operation in a single
connection without impacting all sessions or the entire server.

The overhead for managing separate interceptor reference lists for each
operation in each session is minimal.

(4) The interceptor chain changes character somewhat. It is modified to not
be statically hardwired but to use the interceptor reference list of the
operation invoked from a session to conduct invocations with the correct
interceptor order.

I think this can be done without causing inefficiencies. I don't have
suggestions on how best we can do this in the code right now.

Thoughts? Additions?

On Wed, Nov 2, 2011 at 10:04 PM, Emmanuel Lecharny <elecha...@gmail.com>wrote:

> Hi guys,
>
> I had a bit of time and I reviewed the interceptors today. And I had an
> idea which may be interesting to discuss.
>
> First, here is a table where all the interceptors operation are listed,
> and for each interceptor, I listed the operation they are processing :
>
> AciAuthorizationInterceptor : ACI
> AdministrativePointInterceptor : API
> AuthenticationInterceptor : AI
> ChangeLogInterceptor : CLI
> CollectiveAttributeInterceptor : CAI
> DefaultAuthorizationIntercepto**r : DAI
> EventInterceptor : EI
> ExceptionInterceptor : EXI
> JournalInterceptor : JI
> KeyDerivationInterceptor : KDI
> NormalizationInterceptor : NI
> OperationalAttributeIntercepto**r : OAI
> PasswordHashingInterceptor : PHI
> ReferralInterceptor : RI
> SchemaInterceptor : SI
> SubentryInterceptor : SEI
> TriggerInterceptor : TI
>
>                ACI API  AI CLI CAI DAI  EI EXI  JI KDI  NI OAI PHI  RI  SI
> SEI  TI
> add           :  x   x   x   x   x   ?   x   x   x   x   x   x   x   x   x
>   x   x
> bind          :  -   -   x   -   -   -   -   -   -   -   x   -   -   -   -
>   -   -
> compare       :  x   -   x   -   -   -   -   -   -   -   x   -   -   -   x
>   -   -
> delete        :  x   x   x   x   -   x   x   x   x   -   x   -   -   x   -
>   x   x
> getRootDSE    :  -   -   x   -   -   -   -   -   -   -   -   -   -   -   -
>   -   -
> hasEntry      :  x   -   x   -   -   -   -   -   -   -   x   -   -   -   -
>   -   -
> list          :  x   -   x   -   x   x   -   x   -   -   x   x   -   -   x
>   x   -
> lookup        :  x   -   x   -   x   x   -   x   -   -   x   x   -   -   x
>   -   -
> modify        :  x   x   x   x   x   x   x   x   x   x   x   x   x   x   x
>   x   x
> move          :  x   x   x   x   -   x   x   x   x   -   x   x   -   x   -
>   x   x
> moveAndRename :  x   x   x   x   -   x   x   x   x   -   x   x   -   x   ?
>   x   x
> rename        :  x   x   x   x   -   x   x   x   x   -   x   x   -   x   x
>   x   x
> search        :  x   -   x   -   x   x   -   -   -   -   x   x   -   -   x
>   x   -
> unbind        :  -   -   x   -   -   -   -   -   -   -   -   -   -   -   -
>   -   -
>
> (It's interesting that there are two operations that should be processed
> by some interceptors, and that are not : it's most certainly a bug. They
> are marked with a '?' in this table)
>
> Now, we can see that all the operation are only processed by a few
> interceptors. I was thinking that it could be an option to list the
> mandatory interceptors for each operation, instead of letting the chain
> determinate if an interceptor will process this operation.
>
> In the Operation manager, we will then call all the needed interceptors
> chain for each operation. For instance, for a delete operation, we will
> proceed this way :
>
> operationManager.delete( DeleteOperationContext deleteContext )
> {
>    // ThedeleteContext.getOperation(**) is used to get the correct list
> of interceptors for the operation,
>    // as we may have more than one delete operation (see below)
>    InterceptorChain deleteChain = directoryService.**getInterceptors(
> deleteContext.getOperation() );
>
>    deleteChain.delete( deleteContext );
> }
> The biggest advantage is that we know have a clear list of interceptors
> for each operation, and we cna expose this list to the user, who can add
> its own interceptor. We can even compute this chain by checking which
> operation an interceptor will handle, using reflection, when the
> interceptor is added in the chain.
>
> For internal operation, I'm quiet sure we should ask the nexus directly,
> instead of going through the chain again. However, we can perfectly proceed
> exactly the same way, by defining some other operation, like
> lookupInternal, which describes the list of needed interceptors.
>
> One other advantage is that we will not go through N useless interceptor
> for each operation, speeding up (ok, marginaly but still) the operations.
>
> Lats, not least, I'm quite sure that if we expose the list of interceptors
> involved by each operation, we make it easier for someone who want to add
> an interceptor, as all those lists will be available through teh
> configuration, and not in the code, as it is atm. It also remove the need
> for interceptors bypasses, if we inject the type of operation we want to
> execute in the context (xxxContext.getOperation()  will return the type of
> operation).
>
> It may sound a bit crazy, but I think it would work with a little impact
> on the existing code...
>
> thoughts ?
>
> -- Regards, Cordialement, Emmanuel Lécharny www.iktek.com
>



-- 
Best Regards,
-- Alex

Reply via email to