On Nov 27, 2009, at 12:39 AM, Ashish wrote:

they are not recent). Here they are.

First, let's start with what we really need :
o A chain has a start

Yup, very much needed

o A chain has an end

Very logical. Do we need a marker end of chain or if we don't get next
filter, we assume its the end?

I would be very much against markers as they clutter up the API. I'm relatively new here, what purpose would they serve?

o Both start and end are Filter instances

Very much true. Again to point to bullet 2. Do we need these start and
end to be marker Filters and we add them explicitly in the chain.

From the discussion on MINA 3.0 design page, it seems we want to get
rid of Head and Tail filter.



o We have as many filters as we need in the chain
o Filters can be added or removed dynamically

Hmm.. here I would like to add, that if the chain is modifiable

o A chain is instanciated for each session (if we have 10K sessions, we have
10K instances of chain)

Agreed. But is there a possibility to have it only for mutable chains.
Say if a Chain is static (User's choice), we may choose not to create
so many instances. Although we need to see how much complexity it adds
to our implementation.

o A filter can be activated (enabled) or disabled, dynamically

So its a convenience for User, rather than removing and adding
filter's, temporarily change the state.


That being said, we have many ways to implement such a mechanism. let's consider we are in a Filter, and we want to call the next filter. We have
three options here :
* The NextFilter is already computed, and is a part of the Filter's data.
This resolves to a direct call :
 ...
 nextFilter.<action>( params );
 ...

* The NextFilter is computed dynamically :
 ...
 nextFilter = computeNext( params );
 nextFilter.<action>( params );
 ...

* The nextFilter is computed by the caller, and is a parameter :

public void <action>( Filter nextFilter, <other params>... ) {
 ...
 nextFilter.<action>( params );
 ...

The current version (2.0) implements the third form. From the debugging PoV, it's a nightmare, as you have to step through many intermediate calls (in fact, an other call for each filter). The StackTrace is heavy. The next filter is not known when you are in a Filter, as it's computed outside of
the current method.

The first approach is way simpler, as is the second one.

Let's go a bit deeper : if there is an executor in the chain, suddenly things get a bit muddy. The "one session = one chain instance" is still correct, but we may have two (or more) messages being processed on one session on the same chain. If the chain is dynamically modified, then it may be ok for the thread modifying the chain, but not for the other threads.
Here is a picture describing this mechanism :


Thread1                                                  /--->
[Filter3]--->[tail]
Thread2 [head]---> [filter1]--->[filter2]--->[executor]-*---->
[Filter3]--->[tail]
Thread3                                                  \--->
[Filter3]--->[tail]

Now, if the Thread 2 modify the chain to add a Filter4, then there is no guarantee that Thread1 will call it. That means we must protect the chain
against concurrent modifications.

Another drawback of the first approach is that you must declare an instance of a Filter for your chain, as it carries some information specific to your
session. We would rather have a stateless Filter...

The second approach require an external system to give you the next filter.
It can be the session, which is passed as a parameter for each filter
call.In this case, if the external system is protected against concurrent modifications, then we are safe (except if we want each thread to define its own chain in the previous example... In this case, the executor must be
responsible for the chain duplication, and probably store it in a
ThreadLocal variable )

Not that simple...

Thoughts ?

I am still kinda looking at 2nd approach. Though I am not very much
sure about the whole design as of now.

There is one more thing, related to stateful filters. How do we take
care of them.

IoFilters could get passed an invocation context which would allow them to store their state. This context would also have the IoSession that's currently being processed. But now that I think about it, if these things are stateless, in that they store their values in the session, they why not have them be POJOs whose values are injected in when something needs to be processed.


public class Foo implements IoFilter
{
    private IoSession ioSession;
    private String bar;

    public void setIoSession(IoSession ioSession)
    {
        this.ioSession = ioSession;
    }

    public void setBar(String bar)
    {
        this.bar = bar;
    }

    void messageReceived(Object message)
    {
    }

    public String getBar()
    {
        return bar;
    }
}

Here, since there's a getter, the system would now to store "bar" into the IoSession for Foo, or other filters, to subsequently use.



Regards,
Alan

Reply via email to