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.
>
signature.asc
Description: PGP signature
