On 8/27/11 10:53 AM, Alex Karasulu wrote:
On Sat, Aug 27, 2011 at 5:35 AM, Emmanuel Lecharny<elecha...@gmail.com>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.

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


  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.


Emmanuel, thanks for chiming in here on behalf of the ASN.1 based codecs.
Alan these concepts are very important for us to factor in.

The problem here is that processing in one state of an FSM may alter the
control flow.

I know we're trying to find the design that leads to the sweetest and
easiest code for implementing these filters. However it's possible that this
process of defining protocols may evolve to where protocol implementors feed
in a state transition matrix and most of the code is generated minus
customizations supplied for actions to take.

I might be flying in the clouds with this but it might be another one of the
design constraints added to Emmanuel's list to at least consider.

After having thought about FSM all night long, I realize this morning that using a FSM and having post processing actions is a bit complex.

Assuming we let the controller deal with the transition from two states, then that mean a post action must itself be a State (Filter).

Such a method :

void messageReceived( context )
{
  ... // do something, updating the context, eventually setting a
status
 fsmMap.get( this ).get( status ).messageReceived( context );
  ... // do something after the call
}


would have to be mapped differently :

Filter 1 :

void messageReceived( context )
{
  ... // do something
  // End of the method, the control switch to the next configured filter
}


Filter2 (contain the post action)

void messageReceived( context )
{
  ... // do something, this is a post action
}


then the FSM should describe the following transition :

input ... -> Filter1.messageReceived() ---> handler.messageReceived() --> Filter2.messageReceived()

So the post action is called when the handler has processed the message.

IMHO, it's not really convenient...

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

Reply via email to