Hi guys,

I played around some of the ideas we discussed last week on the mailing list, about the way we handle the chain and the interceptors.

What I did was pretty simple : I modified the way we process the getRootDse() operation. This impact many classes :
o OperationContext :
This interface exposes 4 more methods :
List<String> getInterceptors() which returns the list of interceptors to execute for this operation void setInterceptors( List<String> interceptors ) which sets the list of interceptors to execute for this operation int getCurrentInterceptor() : returns the current interceptor for this context void nextInterceptor() : move the current interceptor to the next interceptor

o AbstractOperationContext :
This is where we implement the four added methods.

...
    /** The interceptors to call for this operation */
    protected List<String> interceptors;

    /** The current interceptor position */
    protected int currentInterceptor;
...
    public AbstractOperationContext( CoreSession session )
    {
        this.session = session;
        currentInterceptor = 0;
    }
...
    public List<String> getInterceptors()
    {
        return interceptors;
    }

    public void setInterceptors( List<String> interceptors )
    {
        this.interceptors = interceptors;
    }

    public int getCurrentInterceptor()
    {
        return currentInterceptor;
    }

    public void nextInterceptor()
    {
        currentInterceptor++;
    }

Nothing big here, just accessors.


o ServerContext.doGetRootDSEOperation :
the GetRootDseOperationContext now contains the list of interceptors to call :

    protected Entry doGetRootDSEOperation( Dn target ) throws Exception
    {
GetRootDSEOperationContext getRootDseContext = new GetRootDSEOperationContext( session, target ); getRootDseContext.addRequestControls( convertControls( true, requestControls ) );

-->     // We should get this list from the DS !!!
-->     List<String> interceptors = new ArrayList<String>();
-->     interceptors.add( AuthenticationInterceptor.class.getSimpleName() );
-->     getRootDseContext.setInterceptors( interceptors );

        // do not reset request controls since this is not an external
        // operation and not do bother setting the response controls either
        OperationManager operationManager = service.getOperationManager();

        return operationManager.getRootDSE( getRootDseContext );
    }

Here, it's hard wired, but the logic would be to ask the DS to provide the interceptor list, which will be copied and stored into the OperationContext. Otherwise, the code is the same.

o DefaultOperationManager :
The first main difference :
public Entry getRootDSE( GetRootDSEOperationContext getRootDseContext ) throws LdapException
    {
        ...
        try
        {
Interceptor head = directoryService.getInterceptor( getRootDseContext.getInterceptors().get( 0 ) );
            getRootDseContext.nextInterceptor();

            return head.getRootDSE( getRootDseContext );
            ...

Here, we compute the first interceptor to call by getting the first of the list from the OperationContext, and we call it. As we can see, we don't use the InterceptorChain anymore. (Note that we can improve the code by adding a method in the OperationContext to return the Interceptor directly.)

o Interceptor :
The second main difference. We don't pass anymore the NextInterceptor parameter : Entry getRootDSE( GetRootDSEOperationContext getRootDseContext ) throws LdapException;

o The inherited classes (here, AuthenticatorInterceptor) :
We have to change the getRootDSE method in order to call the next interceptor. This is done by substituing this line :
        return next.getRootDSE( getRootDseContext );
by this one :
        return next( getRootDseContext );

where the next() method is a final method in the BaseInterceptor class

o BaseInterceptor :
This is where we compute the next interceptor to call :

protected final Entry next( GetRootDSEOperationContext getRootDseContext ) throws LdapException
    {
        Interceptor interceptor = getNextInterceptor( getRootDseContext );

        return interceptor.getRootDSE( getRootDseContext );
    }

and

private Interceptor getNextInterceptor( OperationContext operationContext )
    {
        int currentInterceptor = operationContext.getCurrentInterceptor();

if ( currentInterceptor == operationContext.getInterceptors().size() )
        {
            return FINAL_INTERCEPTOR;
        }

        operationContext.nextInterceptor();

Interceptor interceptor = directoryService.getInterceptor( operationContext.getInterceptors().get( currentInterceptor ) );

        return interceptor;
    }


The FINAL_INTERCEPTOR interceptor is the one which reroute calls to the nexus (It's the same class we have in the InterceptorChain).


That's it, the code works, and when it comes to debug it, it's just easy : we don't have to go through multiple classes when stepping through, and we don't have to go through the BaseInterceptor for each disabled or bypassed interceptor.

It's not totally finished though : the list creation is just horrible in the given code. It must be generated in the DirectoryService by using introspection over all the activated Interceptors.

Thoughts ?

--
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com

Reply via email to