Jeanfrancois Arcand wrote:
Salut,

Another option, and it's not a bad idea, would be to define a threadSafe chain, which can be modified, or a not synchronized chain, which can't be changed. We have to dig those ideas.

Just for my understanding, does the chain be modified by the user? Would it be too demanding to ask the user to sync its filter itself. That's one of the reason why we have 2 mode in Grizzly, but that might not be a good idea :-)
Yrs, the user can modify the chain (well, 'user' here means the guy who write the application using MINA :) But we can also think about a self-configuring system which add a new filter in the chain right in the middle of an event processing. A good exemple could also be to add a new logging filter when having some error we want to log, but only if we get this error.

In order to protect the chain against concurrent modification, the ideas I have are : - always call the next filter using a getNextFilter() method which can contain some protected section - define a thread-safe chain a bit like you can declare a protected collection (Collections.synchronizedCollection( set )). We may do the very same for the chain: ChainUtil.synchronizeChain( myChain). - maybe set a simple volatile flag, used in the getNextFilter to avoid a heavy synchronization

Anyway, there are options here, and it can be user driven (as you create the chain before it is injected into the server, you can create it thread safe, or not).

It has to be tested in the branch...
But this is only what I have in mind, and I think we can ellaborate a bit more, possibly discarding my crazy ideas :)

The getNext() approach is promising. At least in Tomcat they moved their internal Valve architecture to exactly use that approach. GlassFish forked Tomcat and the approach used is preExecute/postExecute. There is pro and con for both (preExecute/postExecute was faster when we measured long time ago) but I would think for user is it simple using the getNext() (strange I say that as I've implemented the pre/post :-)). I think it is simpler.
We have such code :

   public void messageReceived(IoSession session, Object message) {
       if (!(message instanceof IoBuffer)) {
           getNextFilter().messageReceived(session, message);
           return;
       }

       IoBuffer in = (IoBuffer) message;
       ProtocolDecoder decoder = getDecoder(session);
if ( decoder == null) {
           ProtocolDecoderException pde = new ProtocolDecoderException(
"Cannot decode if the decoder is null. Add the filter in the chain" +
               "before the first session is created" );
           getNextFilter().exceptionCaught(session, pde);
           return;
       }
ProtocolDecoderOutput decoderOut = getDecoderOut(session, getNextFilter()); if ( decoderOut == null) {
           ProtocolDecoderException pde = new ProtocolDecoderException(
"Cannot decode if the decoder is null. Add the filter in the chain" +
               "before the first session is created" );
           getNextFilter().exceptionCaught(session, pde);
           return;
       }
while (in.hasRemaining()) {
           int oldPos = in.position();
           try {
               synchronized (decoderOut) {
                   decoder.decode(session, in, decoderOut);
               }

               decoderOut.flush();
           } catch (Throwable t) {
               ...
           }
       }
   }

As you can see, (it's in the ProtocolCodecFilter) we have more than one place where we call the next filter, for different messages. Implementing such a behavior with pre(), callNext(), post() method would be quite a PITA to implement... (forget about this code, it's not necessarily a perfect exemple of good code, but it demonstracte what I mean)


Thanks !

--
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org


Reply via email to