Grizzly 2.0: Echo sample

View: New views
4 Messages — Rating Filter:   Alert me  

Grizzly 2.0: Echo sample

by Oleksiy Stashok :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

wanted to share the simple Grizzly 2.0 sample (echo sample) and will  
very appreciate the feedback or better contributions :) to the  
proposed design.
The complete sources are attached, though to orient better I'll  
briefly describe what is what :)

Let's start from the server.
1)
         TCPNIOTransport transport =  
TransportManager.instance().createTCPTransport();

         // Add TransportFilter, which is responsible
         // for reading and writing data to the connection
         transport.getFilterChain().add(new TransportFilter());
         transport.getFilterChain().add(new EchoFilter());

         try {
             // binding transport to start listen on certain host and  
port
             transport.bind(HOST, PORT);

             // start the transport
             transport.start();

             System.out.println("Press any key to stop the server...");
             System.in.read();
         } finally {
             // stop the transport
             transport.stop();

             // release TransportManager resources like ThreadPool
             TransportManager.instance().close();
         }
     }

here we just initialize the TCP transport, adding 2 filters:  
TransportFilter and EchoFilter, binding the server to the specific  
host and port and... that's it :)
It's similar to what we have in 1.x, except may be new term  
TransportFilter.
TransportFilter is very similar to ReadFilter from Grizzly 1.x, so it  
knows how to read/write the data depending on the transport. Each  
transport can implement its own read/write logic, in this case  
TransportFilter will silently forward the control the the specific  
implementation. In our case TCPNIOTransport has own read/write logic  
implementation, which is hidden from us, and TransportFilter uses it  
in order to read/write the bytes on the filter chain.

2) How does the EchoFilter look like.

     /**
      * Handle just read operation, when some message has come and  
ready to be
      * processed.
      *
      * @param ctx Context of {@link FilterChainContext} processing
      * @param nextAction default {@link NextAction} filter chain will  
execute
      *                   after processing this {@link Filter}. Could  
be modified.
      * @return the next action
      * @throws java.io.IOException
      */
     @Override
     public NextAction handleRead(FilterChainContext ctx, NextAction  
nextAction)
             throws IOException {
         // Get the read message
         Object message = ctx.getMessage();

         /* Send the same message on the connection. The filter chain  
write
          * will pass each filter on a filter chain (interceptWrite  
method),
          * before sending the message on a wire. It means each filter  
can modify
          * the message, before it will be sent to the recipient
          */
         ctx.getFilterChain().write(ctx.getConnection(), message);

         return nextAction;
     }

common interface for all filters is Filter, which if very similar to  
the ProtocolFilter from Grizzly 1.x, but, IMHO, it's more suitable to  
extend FilterAdapter class, which lets you separate the logic. For  
example in case of EchoFilter we just want to handle read operation  
and not interested in others.
You can note how we write the response, using the filter chain, not to  
the connection directly. It means that all the Filters in the chain  
can intercept the write operation and transform the writing buffer  
before TransportFilter will put it on a wire. In our case it looks  
redundant, because we don't have any Filter, which could be interested  
in transforming the response, and  
"ctx.getConnection().write(message);" could be used instead. But as  
common solution filterchain.write is better.


3) Client

         Connection connection = null;

         // Create the TCP transport
         TCPNIOTransport transport = TransportManager.instance().
                 createTCPTransport();

         try {
             // start the transport
             transport.start();

             // perform async. connect to the server
             ConnectFuture future =  
transport.connectAsync(EchoServer.HOST,
                     EchoServer.PORT);
             // wait for connect operation to complete
             connection = (TCPNIOConnection) future.get(10,  
TimeUnit.SECONDS);

             assert connection != null;

             // create the message
             ByteBuffer message = ByteBuffer.wrap("Echo  
test".getBytes());
             // sync. write the complete message using
             // temporary selectors if required
             WriteResult result = connection.write(message);

             assert result.getWrittenSize() == message.capacity();

             // allocate the buffer for receiving bytes
             ByteBuffer receiverBuffer =  
ByteBuffer.allocate(message.capacity());

             ReadResult readResult = null;
             // read the same number of bytes as we sent before
             while (receiverBuffer.hasRemaining() &&
                     (readResult == null || readResult.getReadSize() >  
0)) {
                 readResult = connection.read(receiverBuffer);
             }

             // check the result
             assert message.flip().equals(receiverBuffer.flip());
         } finally {
             // close the client connection
             if (connection != null) {
                 connection.close();
             }

             // stop the transport
             transport.stop();
             // release TransportManager resources like ThreadPool etc.
             TransportManager.instance().close();
         }

it does similar things as server to initialize/release the transport  
and TransportManager.
Also you can find, how client is getting connected to the server,  
writes and reads data.
Want to note, that currently there is no async read and write  
implementations in Grizzly 2.0 (it will be ready soon), so all reads  
and writes are working sync., using temporary selectors if required.

Will appreciate your feedback.

Thanks.

WBR,
Alexey.





---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@...
For additional commands, e-mail: dev-help@...

EchoClient.java (6K) Download Attachment
EchoFilter.java (4K) Download Attachment
EchoServer.java (4K) Download Attachment

Re: Grizzly 2.0: Echo sample

by Jeanfrancois Arcand-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Salut,

Oleksiy Stashok wrote:

> Hi,
>
> wanted to share the simple Grizzly 2.0 sample (echo sample) and will
> very appreciate the feedback or better contributions :) to the proposed
> design.
> The complete sources are attached, though to orient better I'll briefly
> describe what is what :)
>
> Let's start from the server.
> 1)
>         TCPNIOTransport transport =
> TransportManager.instance().createTCPTransport();

+0 on the instance() method :-) We discussed that a while ago, but I
would think we need to have something similar to the Controller, and get
Transport from the Controller.

Now what I don't like is also (we have the same problem with 1.8 right
now) is the fact that you have the TCP named in the method name. I would
recommend something like:


createTransport(Transport.TCP)

instead.


>
>         // Add TransportFilter, which is responsible
>         // for reading and writing data to the connection
>         transport.getFilterChain().add(new TransportFilter());
>         transport.getFilterChain().add(new EchoFilter());

For backward compatibility we can probably still use getProtocolChain().
Do you see any problem?


>
>         try {
>             // binding transport to start listen on certain host and port
>             transport.bind(HOST, PORT);
>
>             // start the transport
>             transport.start();
>
>             System.out.println("Press any key to stop the server...");
>             System.in.read();
>         } finally {
>             // stop the transport
>             transport.stop();
>
>             // release TransportManager resources like ThreadPool
>             TransportManager.instance().close();

Hum :-) Can we find a way to avoid such extra method call:

TransportManager.instance().close()

Instead, can we do something like:


Transport transport = createTransport(Transport.TCP);
TransportManager.addListener(transport,TransportManager.CLOSE);

SO when transport.close() is called, the TransportManager is
automatically invoked. That will be less error prone IMO.



>         }
>     }
>
> here we just initialize the TCP transport, adding 2 filters:
> TransportFilter and EchoFilter, binding the server to the specific host
> and port and... that's it :)
> It's similar to what we have in 1.x, except may be new term
> TransportFilter.
> TransportFilter is very similar to ReadFilter from Grizzly 1.x, so it
> knows how to read/write the data depending on the transport.

We need to decide if we keep the ProtocolFilter name. I would think
ProtocolFilter defined for 1.8 can still work with 2.0


Each
> transport can implement its own read/write logic, in this case
> TransportFilter will silently forward the control the the specific
> implementation. In our case TCPNIOTransport has own read/write logic
> implementation, which is hidden from us, and TransportFilter uses it in
> order to read/write the bytes on the filter chain.

OK that sound interesting. Now we need to take into account NIO.2 here.
So we probably need to have TCPAIOTransport as well. Switching from
NIO.1 to NIO.2 should be transparent IMO to the user.


>
> 2) How does the EchoFilter look like.
>
>     /**
>      * Handle just read operation, when some message has come and ready
> to be
>      * processed.
>      *
>      * @param ctx Context of {@link FilterChainContext} processing
>      * @param nextAction default {@link NextAction} filter chain will
> execute
>      *                   after processing this {@link Filter}. Could be
> modified.
>      * @return the next action
>      * @throws java.io.IOException
>      */
>     @Override
>     public NextAction handleRead(FilterChainContext ctx, NextAction
> nextAction)
>             throws IOException {
>         // Get the read message
>         Object message = ctx.getMessage();

Hum...how do you know you have a complete/incomplete message?


>
>         /* Send the same message on the connection. The filter chain write
>          * will pass each filter on a filter chain (interceptWrite method),
>          * before sending the message on a wire. It means each filter
> can modify
>          * the message, before it will be sent to the recipient
>          */
>         ctx.getFilterChain().write(ctx.getConnection(), message);

Here the write operation will be blocking? We probably need some
WriteSessionListener here to get some cue about what's happenning with
the write operation.


>
>         return nextAction;
>     }
>
> common interface for all filters is Filter, which if very similar to the
> ProtocolFilter from Grizzly 1.x, but, IMHO, it's more suitable to extend
> FilterAdapter class, which lets you separate the logic. For example in
> case of EchoFilter we just want to handle read operation and not
> interested in others.
> You can note how we write the response, using the filter chain, not to
> the connection directly. It means that all the Filters in the chain can
> intercept the write operation and transform the writing buffer before
> TransportFilter will put it on a wire. In our case it looks redundant,
> because we don't have any Filter, which could be interested in
> transforming the response, and "ctx.getConnection().write(message);"
> could be used instead. But as common solution filterchain.write is better.

Can you elaborates more here? I'm not sure I understand properly. How
will you know a Filter is interested in write operations?


>
>
> 3) Client
>
>         Connection connection = null;
>
>         // Create the TCP transport
>         TCPNIOTransport transport = TransportManager.instance().
>                 createTCPTransport();

Same as above :-) -1 for the instance() :-)



>
>         try {
>             // start the transport
>             transport.start();
>
>             // perform async. connect to the server
>             ConnectFuture future = transport.connectAsync(EchoServer.HOST,
>                     EchoServer.PORT);
>             // wait for connect operation to complete
>             connection = (TCPNIOConnection) future.get(10,
> TimeUnit.SECONDS);
>
>             assert connection != null;
>
>             // create the message
>             ByteBuffer message = ByteBuffer.wrap("Echo test".getBytes());
>             // sync. write the complete message using
>             // temporary selectors if required
>             WriteResult result = connection.write(message);
>
>             assert result.getWrittenSize() == message.capacity();

Hum :-) If the message has not been fully written,
result.getWrittenSize() will return the wrong value. I would instead
change your write() signature and have something like NIO.2:

write(msg, CompletionHandler);

http://openjdk.java.net/projects/nio/javadoc/java/nio/channels/CompletionHandler.html

And follow a similar approach for read and write operations.


>
>             // allocate the buffer for receiving bytes
>             ByteBuffer receiverBuffer =
> ByteBuffer.allocate(message.capacity());
>
>             ReadResult readResult = null;
>             // read the same number of bytes as we sent before
>             while (receiverBuffer.hasRemaining() &&
>                     (readResult == null || readResult.getReadSize() > 0)) {
>                 readResult = connection.read(receiverBuffer);
>             }
>
>             // check the result
>             assert message.flip().equals(receiverBuffer.flip());
>         } finally {
>             // close the client connection
>             if (connection != null) {
>                 connection.close();
>             }
>
>             // stop the transport
>             transport.stop();
>             // release TransportManager resources like ThreadPool etc.
>             TransportManager.instance().close();
>         }
>
> it does similar things as server to initialize/release the transport and
> TransportManager.
> Also you can find, how client is getting connected to the server, writes
> and reads data.
> Want to note, that currently there is no async read and write
> implementations in Grizzly 2.0 (it will be ready soon), so all reads and
> writes are working sync., using temporary selectors if required.

OK this is a great start. I haven't looked at the code yet....what I
recommend is first document the 2.0 core classes and generate the
JavaDoc API...that will be a really good startup for review during our
weekly meeting. Looking at the code directly will makes the task to
harder for external people (nobody except a couple of us will have time
to look at the implementation). So I recommend you javadoc the new
monster :-)

Also we must have in mind that we may have to be backward compatible
with some concept (like ProtocolFIlter/Chain). I say we might :-) We
should dress a list and probably vote. We have to keep in mind that
customer using 1.8 might not have time to re-write their application,
and we don't want to loose them for another framework in case they don't
like our 2.0 design.

Thanks

-- Jeanfrancois


>
> Will appreciate your feedback.
>
> Thanks.
>
> WBR,
> Alexey.
>
>
> ------------------------------------------------------------------------
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@...
> For additional commands, e-mail: dev-help@...

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@...
For additional commands, e-mail: dev-help@...


Re: Grizzly 2.0: Echo sample

by Oleksiy Stashok :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Sep 3, 2008, at 17:10 , Jeanfrancois Arcand wrote:

> Salut,
>
> Oleksiy Stashok wrote:
>> Hi,
>> wanted to share the simple Grizzly 2.0 sample (echo sample) and  
>> will very appreciate the feedback or better contributions :) to the  
>> proposed design.
>> The complete sources are attached, though to orient better I'll  
>> briefly describe what is what :)
>> Let's start from the server.
>> 1)
>>        TCPNIOTransport transport =  
>> TransportManager.instance().createTCPTransport();
>
> +0 on the instance() method :-) We discussed that a while ago, but I  
> would think we need to have something similar to the Controller, and  
> get Transport from the Controller.
>
> Now what I don't like is also (we have the same problem with 1.8  
> right now) is the fact that you have the TCP named in the method  
> name. I would recommend something like:
>
>
> createTransport(Transport.TCP)
>
> instead.
As for instance() I don't agree... Having static method  
TransportManager.createTransport() is not flexible, as doesn't let us  
to have custom TransportManager implementation.
Having something like:
TransportManager.instance().createTransport(Transport.TCP);
looks like good idea :)

>>        // Add TransportFilter, which is responsible
>>        // for reading and writing data to the connection
>>        transport.getFilterChain().add(new TransportFilter());
>>        transport.getFilterChain().add(new EchoFilter());
>
> For backward compatibility we can probably still use  
> getProtocolChain(). Do you see any problem?
I just think, it's more clear to have FilterChain, which consists of  
Filters, than ProtocolChain, consisting of ProtocolFilter. In first  
case names look more clear and shorter.


>>        try {
>>            // binding transport to start listen on certain host and  
>> port
>>            transport.bind(HOST, PORT);
>>            // start the transport
>>            transport.start();
>>            System.out.println("Press any key to stop the server...");
>>            System.in.read();
>>        } finally {
>>            // stop the transport
>>            transport.stop();
>>            // release TransportManager resources like ThreadPool
>>            TransportManager.instance().close();
>
> Hum :-) Can we find a way to avoid such extra method call:
>
> TransportManager.instance().close()
>
> Instead, can we do something like:
>
>
> Transport transport = createTransport(Transport.TCP);
> TransportManager.addListener(transport,TransportManager.CLOSE);
>
> SO when transport.close() is called, the TransportManager is  
> automatically invoked. That will be less error prone IMO.
Really not sure which way is less error prone :))
Basically TransportManager could create several Transports and if we  
close just one of them - it doesn't mean we need to release all the  
TransportManager resources (such as ThreadPool), because we have other  
Transports, which may use them.


>>        }
>>    }
>> here we just initialize the TCP transport, adding 2 filters:  
>> TransportFilter and EchoFilter, binding the server to the specific  
>> host and port and... that's it :)
>> It's similar to what we have in 1.x, except may be new term  
>> TransportFilter.
>> TransportFilter is very similar to ReadFilter from Grizzly 1.x, so  
>> it knows how to read/write the data depending on the transport.
>
> We need to decide if we keep the ProtocolFilter name. I would think  
> ProtocolFilter defined for 1.8 can still work with 2.0
TransportFilter has wider logic. It knows how to read and write. So,  
IMHO, it makes sense to call it TransportFilter?


> Each
>> transport can implement its own read/write logic, in this case  
>> TransportFilter will silently forward the control the the specific  
>> implementation. In our case TCPNIOTransport has own read/write  
>> logic implementation, which is hidden from us, and TransportFilter  
>> uses it in order to read/write the bytes on the filter chain.
>
> OK that sound interesting. Now we need to take into account NIO.2  
> here. So we probably need to have TCPAIOTransport as well. Switching  
> from NIO.1 to NIO.2 should be transparent IMO to the user.
Sure, as I told each Transport could have own TransportFilter logic,  
so NIO.2 could have its own logic, which will be used by common  
TransportFilter.


>> 2) How does the EchoFilter look like.
>>    /**
>>     * Handle just read operation, when some message has come and  
>> ready to be
>>     * processed.
>>     *
>>     * @param ctx Context of {@link FilterChainContext} processing
>>     * @param nextAction default {@link NextAction} filter chain  
>> will execute
>>     *                   after processing this {@link Filter}. Could  
>> be modified.
>>     * @return the next action
>>     * @throws java.io.IOException
>>     */
>>    @Override
>>    public NextAction handleRead(FilterChainContext ctx, NextAction  
>> nextAction)
>>            throws IOException {
>>        // Get the read message
>>        Object message = ctx.getMessage();
>
> Hum...how do you know you have a complete/incomplete message?
For echo filter it doesn't matter, we just reply with the same  
sequence of byte, which was received.


>>        /* Send the same message on the connection. The filter chain  
>> write
>>         * will pass each filter on a filter chain (interceptWrite  
>> method),
>>         * before sending the message on a wire. It means each  
>> filter can modify
>>         * the message, before it will be sent to the recipient
>>         */
>>        ctx.getFilterChain().write(ctx.getConnection(), message);
>
> Here the write operation will be blocking? We probably need some  
> WriteSessionListener here to get some cue about what's happenning  
> with the write operation.
Yes. Connection.write(...) or FilterChain.write() are always blocking,  
for async. write there is different method set:  
Connection.writeAsync(...), FilterChain.writeAsync(...)


>>        return nextAction;
>>    }
>> common interface for all filters is Filter, which if very similar  
>> to the ProtocolFilter from Grizzly 1.x, but, IMHO, it's more  
>> suitable to extend FilterAdapter class, which lets you separate the  
>> logic. For example in case of EchoFilter we just want to handle  
>> read operation and not interested in others.
>> You can note how we write the response, using the filter chain, not  
>> to the connection directly. It means that all the Filters in the  
>> chain can intercept the write operation and transform the writing  
>> buffer before TransportFilter will put it on a wire. In our case it  
>> looks redundant, because we don't have any Filter, which could be  
>> interested in transforming the response, and  
>> "ctx.getConnection().write(message);" could be used instead. But as  
>> common solution filterchain.write is better.
>
> Can you elaborates more here? I'm not sure I understand properly.  
> How will you know a Filter is interested in write operations?
Each Filter could override interceptFilterChainWrite(...) method,  
which is called on each Filter in a FilterChain, when  
FilterChain.write/writeAsync is called. So each Filter (like SSL) will  
be able to transform the original message before it will come to the  
TransportFilter.

>
>> 3) Client
>>        Connection connection = null;
>>        // Create the TCP transport
>>        TCPNIOTransport transport = TransportManager.instance().
>>                createTCPTransport();
>
> Same as above :-) -1 for the instance() :-)
>
>
>
>>        try {
>>            // start the transport
>>            transport.start();
>>            // perform async. connect to the server
>>            ConnectFuture future =  
>> transport.connectAsync(EchoServer.HOST,
>>                    EchoServer.PORT);
>>            // wait for connect operation to complete
>>            connection = (TCPNIOConnection) future.get(10,  
>> TimeUnit.SECONDS);
>>            assert connection != null;
>>            // create the message
>>            ByteBuffer message = ByteBuffer.wrap("Echo  
>> test".getBytes());
>>            // sync. write the complete message using
>>            // temporary selectors if required
>>            WriteResult result = connection.write(message);
>>            assert result.getWrittenSize() == message.capacity();
>
> Hum :-) If the message has not been fully written,  
> result.getWrittenSize() will return the wrong value. I would instead  
> change your write() signature and have something like NIO.2:
>
> write(msg, CompletionHandler);
>
> http://openjdk.java.net/projects/nio/javadoc/java/nio/channels/CompletionHandler.html
>
> And follow a similar approach for read and write operations.
There is such an approach for readAsync/writeAsync methods of  
Connection and FilterChain, you can pass the CompletionHandler there.  
Read() and write() methods are always sync. and blocking.


>>            // allocate the buffer for receiving bytes
>>            ByteBuffer receiverBuffer =  
>> ByteBuffer.allocate(message.capacity());
>>            ReadResult readResult = null;
>>            // read the same number of bytes as we sent before
>>            while (receiverBuffer.hasRemaining() &&
>>                    (readResult == null || readResult.getReadSize()  
>> > 0)) {
>>                readResult = connection.read(receiverBuffer);
>>            }
>>            // check the result
>>            assert message.flip().equals(receiverBuffer.flip());
>>        } finally {
>>            // close the client connection
>>            if (connection != null) {
>>                connection.close();
>>            }
>>            // stop the transport
>>            transport.stop();
>>            // release TransportManager resources like ThreadPool etc.
>>            TransportManager.instance().close();
>>        }
>> it does similar things as server to initialize/release the  
>> transport and TransportManager.
>> Also you can find, how client is getting connected to the server,  
>> writes and reads data.
>> Want to note, that currently there is no async read and write  
>> implementations in Grizzly 2.0 (it will be ready soon), so all  
>> reads and writes are working sync., using temporary selectors if  
>> required.
>
> OK this is a great start. I haven't looked at the code yet....what I  
> recommend is first document the 2.0 core classes and generate the  
> JavaDoc API...that will be a really good startup for review during  
> our weekly meeting. Looking at the code directly will makes the task  
> to harder for external people (nobody except a couple of us will  
> have time to look at the implementation). So I recommend you javadoc  
> the new monster :-)
Sure, I'm trying to write as much javadocs as possible. Once I'll push  
Grizzly2.0 to the maven - there will be JavaDoc generated.


> Also we must have in mind that we may have to be backward compatible  
> with some concept (like ProtocolFIlter/Chain). I say we might :-) We  
> should dress a list and probably vote. We have to keep in mind that  
> customer using 1.8 might not have time to re-write their  
> application, and we don't want to loose them for another framework  
> in case they don't like our 2.0 design.
I'm 100% agree, we have to have some migration guide. But not sure  
keeping old names, with completely new implementation will help much.

Thank you for feedback!!!

WBR,
Alexey.

>
>
> Thanks
>
> -- Jeanfrancois
>
>
>> Will appreciate your feedback.
>> Thanks.
>> WBR,
>> Alexey.
>> ------------------------------------------------------------------------
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@...
>> For additional commands, e-mail: dev-help@...
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@...
> For additional commands, e-mail: dev-help@...
>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@...
For additional commands, e-mail: dev-help@...


Re: Grizzly 2.0: Echo sample

by Jeanfrancois Arcand-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Salut,

Oleksiy Stashok wrote:

>
> On Sep 3, 2008, at 17:10 , Jeanfrancois Arcand wrote:
>
>> Salut,
>>
>> Oleksiy Stashok wrote:
>>> Hi,
>>> wanted to share the simple Grizzly 2.0 sample (echo sample) and will
>>> very appreciate the feedback or better contributions :) to the
>>> proposed design.
>>> The complete sources are attached, though to orient better I'll
>>> briefly describe what is what :)
>>> Let's start from the server.
>>> 1)
>>>        TCPNIOTransport transport =
>>> TransportManager.instance().createTCPTransport();
>>
>> +0 on the instance() method :-) We discussed that a while ago, but I
>> would think we need to have something similar to the Controller, and
>> get Transport from the Controller.
>>
>> Now what I don't like is also (we have the same problem with 1.8 right
>> now) is the fact that you have the TCP named in the method name. I
>> would recommend something like:
>>
>>
>> createTransport(Transport.TCP)
>>
>> instead.
> As for instance() I don't agree... Having static method
> TransportManager.createTransport() is not flexible, as doesn't let us to
> have custom TransportManager implementation.
> Having something like:
> TransportManager.instance().createTransport(Transport.TCP);
> looks like good idea :)

I'm still -1 :-) Or at least we need to rename TransportManagerFactory()
and have a getFactory() static method. I do think this is more a common
way of naming factory :-)


>
>>>        // Add TransportFilter, which is responsible
>>>        // for reading and writing data to the connection
>>>        transport.getFilterChain().add(new TransportFilter());
>>>        transport.getFilterChain().add(new EchoFilter());
>>
>> For backward compatibility we can probably still use
>> getProtocolChain(). Do you see any problem?
> I just think, it's more clear to have FilterChain, which consists of
> Filters, than ProtocolChain, consisting of ProtocolFilter. In first case
> names look more clear and shorter.

Hum...+0 Might be shorter, but might not tell/describe what they are
for. And that would help backward compatibility...but leave it as it is
for now, this is minor.

>
>
>>>        try {
>>>            // binding transport to start listen on certain host and port
>>>            transport.bind(HOST, PORT);
>>>            // start the transport
>>>            transport.start();
>>>            System.out.println("Press any key to stop the server...");
>>>            System.in.read();
>>>        } finally {
>>>            // stop the transport
>>>            transport.stop();
>>>            // release TransportManager resources like ThreadPool
>>>            TransportManager.instance().close();
>>
>> Hum :-) Can we find a way to avoid such extra method call:
>>
>> TransportManager.instance().close()
>>
>> Instead, can we do something like:
>>
>>
>> Transport transport = createTransport(Transport.TCP);
>> TransportManager.addListener(transport,TransportManager.CLOSE);
>>
>> SO when transport.close() is called, the TransportManager is
>> automatically invoked. That will be less error prone IMO.
> Really not sure which way is less error prone :))
> Basically TransportManager could create several Transports and if we
> close just one of them - it doesn't mean we need to release all the
> TransportManager resources (such as ThreadPool), because we have other
> Transports, which may use them.

But should calling transport.stop() should take care at least to destroy
its own resource? I think the example was unclear. You don't necessary
have to invoke the close() when you stop a transport, right?


>
>
>>>        }
>>>    }
>>> here we just initialize the TCP transport, adding 2 filters:
>>> TransportFilter and EchoFilter, binding the server to the specific
>>> host and port and... that's it :)
>>> It's similar to what we have in 1.x, except may be new term
>>> TransportFilter.
>>> TransportFilter is very similar to ReadFilter from Grizzly 1.x, so it
>>> knows how to read/write the data depending on the transport.
>>
>> We need to decide if we keep the ProtocolFilter name. I would think
>> ProtocolFilter defined for 1.8 can still work with 2.0
> TransportFilter has wider logic. It knows how to read and write. So,
> IMHO, it makes sense to call it TransportFilter?

OK then :-)

>
>
>> Each
>>> transport can implement its own read/write logic, in this case
>>> TransportFilter will silently forward the control the the specific
>>> implementation. In our case TCPNIOTransport has own read/write logic
>>> implementation, which is hidden from us, and TransportFilter uses it
>>> in order to read/write the bytes on the filter chain.
>>
>> OK that sound interesting. Now we need to take into account NIO.2
>> here. So we probably need to have TCPAIOTransport as well. Switching
>> from NIO.1 to NIO.2 should be transparent IMO to the user.
> Sure, as I told each Transport could have own TransportFilter logic, so
> NIO.2 could have its own logic, which will be used by common
> TransportFilter.

Great.



>
>
>>> 2) How does the EchoFilter look like.
>>>    /**
>>>     * Handle just read operation, when some message has come and
>>> ready to be
>>>     * processed.
>>>     *
>>>     * @param ctx Context of {@link FilterChainContext} processing
>>>     * @param nextAction default {@link NextAction} filter chain will
>>> execute
>>>     *                   after processing this {@link Filter}. Could
>>> be modified.
>>>     * @return the next action
>>>     * @throws java.io.IOException
>>>     */
>>>    @Override
>>>    public NextAction handleRead(FilterChainContext ctx, NextAction
>>> nextAction)
>>>            throws IOException {
>>>        // Get the read message
>>>        Object message = ctx.getMessage();
>>
>> Hum...how do you know you have a complete/incomplete message?
> For echo filter it doesn't matter, we just reply with the same sequence
> of byte, which was received.

But how do you construct the Message and how do you know all bytes has
been consumed from the client?


>
>
>>>        /* Send the same message on the connection. The filter chain
>>> write
>>>         * will pass each filter on a filter chain (interceptWrite
>>> method),
>>>         * before sending the message on a wire. It means each filter
>>> can modify
>>>         * the message, before it will be sent to the recipient
>>>         */
>>>        ctx.getFilterChain().write(ctx.getConnection(), message);
>>
>> Here the write operation will be blocking? We probably need some
>> WriteSessionListener here to get some cue about what's happenning with
>> the write operation.
> Yes. Connection.write(...) or FilterChain.write() are always blocking,
> for async. write there is different method set:
> Connection.writeAsync(...), FilterChain.writeAsync(...)

OK this is where we should explore the NIO.2 API.


>
>
>>>        return nextAction;
>>>    }
>>> common interface for all filters is Filter, which if very similar to
>>> the ProtocolFilter from Grizzly 1.x, but, IMHO, it's more suitable to
>>> extend FilterAdapter class, which lets you separate the logic. For
>>> example in case of EchoFilter we just want to handle read operation
>>> and not interested in others.
>>> You can note how we write the response, using the filter chain, not
>>> to the connection directly. It means that all the Filters in the
>>> chain can intercept the write operation and transform the writing
>>> buffer before TransportFilter will put it on a wire. In our case it
>>> looks redundant, because we don't have any Filter, which could be
>>> interested in transforming the response, and
>>> "ctx.getConnection().write(message);" could be used instead. But as
>>> common solution filterchain.write is better.
>>
>> Can you elaborates more here? I'm not sure I understand properly. How
>> will you know a Filter is interested in write operations?
> Each Filter could override interceptFilterChainWrite(...) method, which
> is called on each Filter in a FilterChain, when
> FilterChain.write/writeAsync is called. So each Filter (like SSL) will
> be able to transform the original message before it will come to the
> TransportFilter.

OK.

>
>>
>>> 3) Client
>>>        Connection connection = null;
>>>        // Create the TCP transport
>>>        TCPNIOTransport transport = TransportManager.instance().
>>>                createTCPTransport();
>>
>> Same as above :-) -1 for the instance() :-)
>>
>>
>>
>>>        try {
>>>            // start the transport
>>>            transport.start();
>>>            // perform async. connect to the server
>>>            ConnectFuture future =
>>> transport.connectAsync(EchoServer.HOST,
>>>                    EchoServer.PORT);
>>>            // wait for connect operation to complete
>>>            connection = (TCPNIOConnection) future.get(10,
>>> TimeUnit.SECONDS);
>>>            assert connection != null;
>>>            // create the message
>>>            ByteBuffer message = ByteBuffer.wrap("Echo test".getBytes());
>>>            // sync. write the complete message using
>>>            // temporary selectors if required
>>>            WriteResult result = connection.write(message);
>>>            assert result.getWrittenSize() == message.capacity();
>>
>> Hum :-) If the message has not been fully written,
>> result.getWrittenSize() will return the wrong value. I would instead
>> change your write() signature and have something like NIO.2:
>>
>> write(msg, CompletionHandler);
>>
>> http://openjdk.java.net/projects/nio/javadoc/java/nio/channels/CompletionHandler.html 
>>
>>
>> And follow a similar approach for read and write operations.
> There is such an approach for readAsync/writeAsync methods of Connection
> and FilterChain, you can pass the CompletionHandler there. Read() and
> write() methods are always sync. and blocking.

OK.

>
>
>>>            // allocate the buffer for receiving bytes
>>>            ByteBuffer receiverBuffer =
>>> ByteBuffer.allocate(message.capacity());
>>>            ReadResult readResult = null;
>>>            // read the same number of bytes as we sent before
>>>            while (receiverBuffer.hasRemaining() &&
>>>                    (readResult == null || readResult.getReadSize() >
>>> 0)) {
>>>                readResult = connection.read(receiverBuffer);
>>>            }
>>>            // check the result
>>>            assert message.flip().equals(receiverBuffer.flip());
>>>        } finally {
>>>            // close the client connection
>>>            if (connection != null) {
>>>                connection.close();
>>>            }
>>>            // stop the transport
>>>            transport.stop();
>>>            // release TransportManager resources like ThreadPool etc.
>>>            TransportManager.instance().close();
>>>        }
>>> it does similar things as server to initialize/release the transport
>>> and TransportManager.
>>> Also you can find, how client is getting connected to the server,
>>> writes and reads data.
>>> Want to note, that currently there is no async read and write
>>> implementations in Grizzly 2.0 (it will be ready soon), so all reads
>>> and writes are working sync., using temporary selectors if required.
>>
>> OK this is a great start. I haven't looked at the code yet....what I
>> recommend is first document the 2.0 core classes and generate the
>> JavaDoc API...that will be a really good startup for review during our
>> weekly meeting. Looking at the code directly will makes the task to
>> harder for external people (nobody except a couple of us will have
>> time to look at the implementation). So I recommend you javadoc the
>> new monster :-)
> Sure, I'm trying to write as much javadocs as possible. Once I'll push
> Grizzly2.0 to the maven - there will be JavaDoc generated.

Thanks!

>
>
>> Also we must have in mind that we may have to be backward compatible
>> with some concept (like ProtocolFIlter/Chain). I say we might :-) We
>> should dress a list and probably vote. We have to keep in mind that
>> customer using 1.8 might not have time to re-write their application,
>> and we don't want to loose them for another framework in case they
>> don't like our 2.0 design.
> I'm 100% agree, we have to have some migration guide. But not sure
> keeping old names, with completely new implementation will help much.

OK let's start the Grizzly war on name :-) Note that I'm not the best
with name, except for Grizzly as project's name.

>
> Thank you for feedback!!!

Thanks!

-- Jeanfrancois

>
> WBR,
> Alexey.
>
>>
>>
>> Thanks
>>
>> -- Jeanfrancois
>>
>>
>>> Will appreciate your feedback.
>>> Thanks.
>>> WBR,
>>> Alexey.
>>> ------------------------------------------------------------------------
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe@...
>>> For additional commands, e-mail: dev-help@...
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@...
>> For additional commands, e-mail: dev-help@...
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@...
> For additional commands, e-mail: dev-help@...
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@...
For additional commands, e-mail: dev-help@...