On Aug 26, 2011, at 7:35 PM, Emmanuel Lecharny wrote:

> On 8/27/11 2:04 AM, Alan D. Cabrera wrote:
>> On Aug 26, 2011, at 1:27 PM, Emmanuel Lecharny wrote:
>> 
>>> On 8/26/11 8:47 PM, Alan D. Cabrera wrote:
>>>> On Aug 26, 2011, at 11:03 AM, Emmanuel Lecharny wrote:
>>>> 
>>>>> On 8/26/11 7:22 PM, Alan D. Cabrera wrote:
>>>>>> On Aug 26, 2011, at 9:33 AM, Emmanuel Lecharny wrote:
>>>>>> What I have in mind is much more something like :
>>>>>> 
>>>>>> void messageReceived( context )
>>>>>> {
>>>>>>    ... // do something, updating the context, eventually setting a status
>>>>>>   controller.callNextFilter( context, currentFilter );
>>>>>>    ... // do something after the call
>>>>>> }
>>>>>> 
>>>>>> and in controller :
>>>>>> void callNextFilter( Context context, Filter currentFilter )
>>>>>> {
>>>>>>    Status status = context.getStatus();
>>>>>>    Map<Status, Filter>    map = fsmMap.get( currentFilter );
>>>>>>    Filter nextFilter = map.get( status );
>>>>>> 
>>>>>>    nextFilter.messageReceived( context );
>>>>>> }
>>>>>> This strikes me as pretty complex, jmho.  Also, I don't like the idea of 
>>>>>> forcing the filter to call the controller.callNextFilter() to make 
>>>>>> things work.
>>>>> the alternative would be something like :
>>>>> 
>>>>> void messageReceived( context )
>>>>> {
>>>>>   ... // do something, updating the context, eventually setting a status
>>>>>  fsmMap.get( this ).get( status ).messageReceived( context );
>>>>>   ... // do something after the call
>>>>> }
>>>>> 
>>>>> No controller, but a long list of chained call.
>>>> But we're still forcing the filter to participate in things that really 
>>>> should be the domain of the controller not the filter.
>>> If we delegate the transition to the controller, then we can't have post 
>>> actions... Obviously, not having post actions makes it easier. (Post action 
>>> are really important if we want to do something when we come back from the 
>>> application.)
>> I think we're getting to some interesting bits. Can you provide more exact 
>> detail?
> 
> One very simple example, taken from the ProfilerFilter :
> 
>    @Override
>    public void messageReceived(NextFilter nextFilter, IoSession session,
>            Object message) throws Exception {
>        if (profileMessageReceived) {
>            long start = timeNow();
>            nextFilter.messageReceived(session, message);
>            long end = timeNow();
>            messageReceivedTimerWorker.addNewDuration(end - start);
>        } else {
>            nextFilter.messageReceived(session, message);
>        }
>    }
> 
> If you depend on the controller to call thenext filter, then you have no easy 
> way to compute the time it takes to process the action, as you won't be able 
> to execute the post action.

This is a good use case, instrumentation of the protocol stack.  Something to 
think about.

What I still object to is forcing filters to participate via this code bit:

 fsmMap.get( this ).get( status ).messageReceived( context );
> 


> Note that the decoding of multiple messages within one PDU won't be possible 
> either without being able to process post-actions. (see below)
>>> One clear exemple would be a decoder processing a PDU with more than one 
>>> message : you can't anymore loop on the PDU if you delegate the next call 
>>> to the controller.
>> What is the format of this PDU and how is it presented to the FSM, i.e. in 
>> what kind of pieces does it arrive?
> 
> You get an array of bytes, containing potentially more than one message. The 
> fact is that you have no way to get a byte array from the socket as soon as a 
> complete message has been received : the socket does not know anything about 
> messages.
> 
> You just have to assume that the PDU you've got can be :
> - either a portion of a message, and you have to wait for more bytes in order 
> to produce a message
> - a full message, once decoded
> - more than one message you have to send to the handler one by one
> - some full messages plus a fraction of a message

I had/have the same understanding of how to crack a PDU and pass on translated 
messages.  This can easily, and I think a fare bit cleaner, be accomplished 
using the mechanism that I propose as well.

>>>> With that said I think that an FSM where we have, here letters are filters:
>>>> 
>>>> [outside filter] ->   {A ->   [state change decides to send to] ->   B ->  
>>>>   [state change decides to send to]  ->   C} ->   [outside filter]
>>>> 
>>>> is very confusing.  What protocol would require that?  Just an honest 
>>>> question; one does not come to my mind atm.
>>> all of them :) This is what we currently do in MINA.
>> I think that I am hearing a reply that explains that all the protocols are 
>> implemented in this way.  I'm not hearing an explanation as to why it *must* 
>> be that way.
> 
> simply because you can't move to the next filter unless you have transformed 
> what you've got from the previous filter. If we exclude all the utility 
> filters (like the loggers), a filter can only process a certain type of 
> message, and produce another type of message. The chain of filters is 
> dictated by the transformation done at each step. One good example is LDAP 
> processing : in order to decode a LDAP message, you first have to decode the 
> TLVs, then you can decode the messages themselves. A LDAP chain would be 
> something like :
> 
> [outside filter] -> (bytes) -> { TLV decoder filter -> (TLVs) -> LDAP decoder 
> filter -> (LDAPmessages) } -> [outside filter]
> 
> (add to this the fact that you may loop on the TLV filter *and* the LDAP 
> filter, plus the fact that you may have to wait for more bytes)
> 
> Now, it makes *no sense* to exchange the filters. It will simply not work. 
> It's the very same for any protocol we will process with such a mechanism.
> 
> In other words, the order the filters are executed is not random. It's fixed 
> by design, and does not change (as soon as we have ruled out the possibility 
> to have a dynamic chain).
> 
> 
> Another way to see this mechanism is that it's a path from one point to 
> another : you may have many different paths, but for a set of bytes, you will 
> always follow the same path. The only way to follow two different paths is 
> when you get two different sets of bytes.

I'm not sure that this needs to be a single FSM.  Why not

[outside filter] -> (bytes) -> [TLV decoder filter] -> (TLVs) -> [LDAP decoder 
filter] -> (LDAPmessages) -> [outside filter]

I hear "looping" being a justification but it strikes me that using an FSM 
obfuscates things needlessly as I believe that a simple filter will do.

Is there some code I can look at to see your above implementation?  I think 
here is a perfect case for code bits to compare.


Regards,
Alan







Reply via email to