Hi you know how much I prefer 2.1 but the need of post() method force
us reworking all the filters, so 2.3 is the way to go.

Keep 2.1 for the big 3.0 API breakup ;)
Julien

On Fri, 07 Nov 2008 02:59:59 +0100
Emmanuel Lecharny <[EMAIL PROTECTED]> wrote:

> Hi guys,
> 
> here are some thoughts and ideas I have had those last few days, 
> thoughts that I have experimented in branches. It's not finished yet, 
> but I think I have something likely to work well and be easier to use 
> than the current implementation.
> 
> So here are the gathered thoughts, please feel free to give me
> feedback :
> 
> 
> Refactoring the current chain : possible implementations
> ---------------------------------------------------------
> 
> So, guys, after having spent a few days thinking and experiencing,
> here are the different possibilities I have thought about. I will try
> to list all of them, with their pros and cons.
> 
> 1) The chain, and the chain builder
> -----------------------------------
> 
> We use a chain of filters to process events. An event, once processed
> by either the Acceptor/Connector or the Processor, is pushed through
> a chain of filters, up to a handler, and a tail filter which does
> nothing but terminate the chain. This chain is associated witheach
> new session, and copied from a template, which is created before we
> start the client/server (depending on what you are iomplementing).
> 
> The chain template is created using a chain builder. The idea is to 
> first create a chain template, which will be copied when a new
> session is created, so that we will be able to dynamically modify the
> copied chain within the session without modifying the template (for
> instance, you can dynamically add a logging filter during a session)
> 
> So we have two different vision for the chain, a template, and N 
> instance of this template (one per session).
> 
> 1.1) Operations on a chain
> ------------------------
> We want to be able to walk the chain, jumping from one filter to the 
> next one. We also want to add or remove filters, dynamically. Both 
> chains (template and instances) dn't support all of these
> operations : it's obviously useless to process event on the template,
> we just want to be able to manage the filters into the chain while
> building it. Also, the copy should be fast and cost as less as memory
> as possible.
> 
> When an event is processed, it goes through events following this
> logic :
> 
> processEventXXX() {
>   doPreOperation();
>   callNextFilter();
>   doPostOperation()
> }
> 
> the callNexrFilter() is the important part of the problem : how do we 
> jump to the next filter, allow a dynamic modification of the chain,
> and protect the chain against concurrent modifications ?
> 
> It also has to be fast, and easy to debug... Challenging !
> 
> 2) Proposed solutions
> ---------------------
> 
> 2.1) Using List<T>
> ---------------------------------
> 
> We can imagine that filters are stored into a list, and that we
> process an event through all the filters this way :
> 
> for (Filter filter:listOfFilters ) {
>   filter.processEventXXX();
> }
> 
> It will obviously work, be easy to debug, be fast, but we will have
> two problems here :
> - we have to use a synchronized list, in order to guarantee that we 
> can't modify the list while jumping from one filter to another
> - we can't any more call pre and post processing.
> 
> The first point is a bit problematic, because we have to lock all the 
> list. Performance can suffer, but not that much, considering that we 
> don't have so much chain modifications (hopefully)
> The real issue is more serious. One improvement would be to have such
> a loop :
> 
> for (Filter filter:listOfFilters ) {
>   filter.doPreXXX()
>   filter.processEventXXX();
>   filter.doPostXXX()
> }
> 
> but this is far from being enough.
> 
> How do we handle the list modification ? As it's a list, we have all
> the LIST API to do that : add, add(index), etc. Easy, as we can
> access this list from the session object.
> 
> 
> 2.2) Using a linked list
> ------------------------
> 
> Instead of using a list, we can also link the filters. Passing from
> one filter to the other will then be just a matter of doing :
> 
> F1.processEventXXX()
>   pre processing
>   nextFilter.processEventXXX()
>   post processing
> 
> The nextFilter is a field pointing to the next filter in the chain.
> 
> This solution has the big advantage of being very simple to
> implement, allows pre and post processing, whatever it can be, and
> fast and easy to debug.
> 
> The main issue is that it's difficult to protect this chain from 
> concurrent modification, unless you synchronize the nextFilter field :
> F1.processEventXXX()
>   pre processing
>   synchronized( nextFilter ) {
>     nextFilter.processEventXXX()
>   }
>   post processing
> 
> This may be acceptable, though. The cost of checking if this 
> synchronization might be not null, as we can see that if the chain 
> contains many filters,
> we will have as many synchronized sections as we have filter, plus
> the time during which the section is synchronized is the global
> execution time.
> 
> Modifying the list is quite simple. As each filter has a link to the 
> next filter, it's just a matter of manipulating this list to add or 
> remove a filter. Obviously, adding or removing a filter back in the 
> chain is useless.
> 
> 2.3 Using a double level structure
> ----------------------------------
> The idea is to separate the filters from the chain. We will store the 
> chain into a list, and each element fo this list is a filter. This
> list is handled by the session.
> Here is the code :
> 
> // First invocation
> processEvent(XXX) {
>   session.getFilter(0).processEventXXX( session, 0 );
> }
> 
> // Nth invocation
> Fx.processEventXXX(session, pos) {
>   pre processing
>   pos++
>   session.getFilter(pos).processEventXXX(session, pos)
>   post processing
> }
> 
> // And of course, the TailFilter won't call the next filter :)
> 
> How do we modifiy the list ?
> 
> Fx.processEventXXX(session, pos) {
>   pre processing
>   pos++
>   // Add a new filter to the chain
>   session.addFiler(pos, filter)
>   session.getFilter(pos).processEventXXX(session, pos)
>   post processing
> }
> 
> The session.addFilter() method will just update the list, and then
> the next call will be done. If we use a CopyOnWriteArrayList, we are
> thread safe.
> 
> So far, using this method, we have all the advantages and none of the 
> inconvenients we have seen in the other methods.
> 
> 3) Choice
> ---------
> 
> If we cant to keep all the existing functionalites MINA has, solution 
> 2.3 is obviously the way to go. Well implemented, it will also be
> fast and easy to debug, and, last, not least, it's close to what we
> curently have, but with less code and a better interface.
> 

Attachment: signature.asc
Description: PGP signature

Reply via email to