dev@grizzly.java.net

Re: Grizzly 2.0: Standalone filterchain processing example

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Tue, 23 Sep 2008 12:20:49 -0400

Salut,

Oleksiy Stashok wrote:
>> Salut,
>>
>> Oleksiy Stashok wrote:
>>> Hi
>>>>> public static final int PORT = 7778;
>>>>> public void testStandaloneFilter() throws Exception {
>>>>> Connection connection = null;
>>>>> TCPNIOTransport transport =
>>>>> TransportManager.instance().createTCPTransport();
>>>>> transport.getFilterChain().add(new TransportFilter());
>>>>> transport.getFilterChain().add(new UTFStringFilter());
>>>>> transport.getFilterChain().add(new EchoFilter());
>>>>
>>>> We still need to discuss the getFilterChain() names ;-)
>>> :) ok
>>>>> try {
>>>>> transport.bind(PORT);
>>>>> transport.start();
>>>>> ConnectFuture future =
>>>>> transport.connectAsync("localhost", PORT);
>>>>> connection = (TCPNIOConnection) future.get(10,
>>>>> TimeUnit.SECONDS);
>>>>> assertTrue(connection != null);
>>>>> String message = "Hello world!";
>>>>> FilterChain filterChain = transport.getFilterChain();
>>>>> WriteResult result = filterChain.write(connection, message);
>>>>> assertEquals(result.getMessage(), message);
>>>>> ReadResult readResult = filterChain.read(connection);
>>>>
>>>> OK I'm not sure about this example. It seems we first works with the
>>>> Transport object and then switch to the FilterChain. If the
>>>> FilterChain handler the read/write logic, why not the connectAsync
>>>> be on the FilterChain as well?
>>> Well, I'm not trying to move transport logic to filterchain. I'm just
>>> showing how it's possible to use filterchain in standalone mode.
>>> How data could be read from the connection, pass the filterchain and
>>> finally we will have filterchain processed message (String in our case).
>>
>> That's still confusing IMO. We should really have a single point of
>> entry.
> But filterchain read/write should not be entry point. It's just feature.
> Which, IMHO, could be very useful for client side.

I agree, but we seems to have many doors to enter the same room. What
I'm trying to say is we should reduce the number of doors :-)

> On example I showed - we use the filterchain both on server and client
> sides. But client side uses it in standalone mode.
> It is just String example. But, if make, let's say, HttpFilter, which
> will work with HttpMessage, it will mean client side could be as simple as:
> Future writeFuture = filterChain.writeAsync(httpMessage);

Still not convinced that we need readSync/Async method. That will makes
the API way too long (like the 1.8.x Context API...way too long IMO).


> ................
> Future readFuture = filterChain.readAsync();
> HttpMessage response = (HttpMessage) readFuture.get();
>
> IMHO, this will make client side very easy and clear.

+1 For the Future :-) -1 for the readFuture cast (or at least we should
have a Message API).



>
>>>> Also, the connet() operations returns A Future, where read/write
>>>> return a Read/WriteResult. Should read/write return a Future as
>>>> well? I would propose we unify the API so any async operations like
>>>> connect/read/write return a Future. From the Future, we can return a
>>>> Result, which contains the requested information. Something like:
>>> connectAsync is async operation, that's why it returns Future.
>>> read/write are blocking - that's why Result.
>>> readAsync/writeAsync operations return Future<Result>.
>>> So, IMHO, it's we don't have unification problems :)
>>
>> Yes, but we should not make any difference between blocking or non
>> blocking. That will make things complicated and a long API (like we
>> currently have in 1.8.x). The shorter API we can have the better we
>> will be :-)
>
> Grizzly 1.x has blocking, non-blocking features implemented in different
> places: InputReader/OutputWriter, AsyncRead/Write queues.

Yes, and that doesn't means we were OK :-)

> In Grizzly 2.0 I want to have these features (at least basic part of it)
> being implemented under Connection API. Though it will be still possible
> to use TemporarySelectorIO.read/write and AsyncRead/Write queue API
> separately.

+1, but I want it more cleaner :-)

>
> But for me, having common IO features under single interface (like
> Connection) looks easier.
>
>
>>>> Result result = ConnectFuture.get()
>>>> Connection connection = result.getResult()
>>>>
>>>> or
>>>>
>>>> Connection connection = ConnectionFuture.get(..) //No cast needed
>>> that casting was redundant. Fixed.
>>>>
>>>> ReadResult result = ReadFuture.get();
>>>> WriteResult resukt = WriteFuture.get();
>>>>
>>>> So your example seems to "suffer" 2 issues:
>>>>
>>>> + Need one single Object to interact with.
>>> transport logic is inside Connection. And FilterChain just brings
>>> processing logic.
>>> The connection.read() in our example will return ByteBuffer, but
>>> filterchain.read() will return String (as result of UTFStringFilter).
>>
>> Hum...I need to look at it more. I'm not sure as how can you know
>> which filter will return what? Meaning something like:
>>
>> transport.getFilterChain().add(new TransportFilter());
>> transport.getFilterChain().add(new UTFStringFilter());
>> transport.getFilterChain().add(new LogFilter());
>> transport.getFilterChain().add(new EchoFilter());
>>
>> How can I predict that readResult.getMessage() is coming from which
>> Filter?
> The filterchain.read() processes the chain in regular manner from the
> first to the last. And the result message will be returned.
> In your example, just UTFStringFilter makes some message transformation,
> looks like other filters will just process the message (not transform).
> So String will be returned.
>
> Example like this:
>
> transport.getFilterChain().add(new TransportFilter());
> transport.getFilterChain().add(new SSLFilter());
> transport.getFilterChain().add(new LogFilter());
> transport.getFilterChain().add(new EchoFilter());
>
> ByteBuffer message = (ByteBuffer) filterChain.read().getMessage();
>
> will return ByteBuffer, the result of SSLFilter decoding. This way we
> can implement SSL clients.


But how can the client knows that? How can I change my mind and instead
get the LogFilter results instead of SSLFilter result?

>
> the following example:
>
> transport.getFilterChain().add(new TransportFilter());
> transport.getFilterChain().add(new SSLFilter());
> transport.getFilterChain().add(new HttpFilter());
> transport.getFilterChain().add(new LogFilter());
> transport.getFilterChain().add(new EchoFilter());
>
> HttpMessage message = (HttpMessage) filterChain.read().getMessage();
>
> will return HttpMessage, the result of HttpFilter, which is invoked
> after SSLFilter. And you see how we can implement HTTPS client.
>
>
>> [Small thing] -> ReadResult should know what will be returned by doing
>> getMessage(), hence no need to cast IMO.
> In general not. But it's possible to customize the message type using
> ReadResult generics. ReadResult<HttpMessage, SocketAddress>

+1

>
>
>>>> + Unify API for async operations.
>>> it's not problem :)
>>>>> String responseMessage = (String) readResult.getMessage();
>>>>> assertEquals(message, responseMessage);
>>>>> } finally {
>>>>> if (connection != null) {
>>>>> connection.close();
>>>>> }
>>>>> transport.stop();
>>>>> TransportManager.instance().close();
>>>>
>>>> I still find it dangerous to have 2 operations to execute here :-)
>>>> But maybe it is only me :-)
>>> No, no, you may be right. Just didn't time to revisit this.
>>
>> I think we should start filling issue on 2.0 to not loose track. So
>> far we are only two discussing, but when every body is up to speed we
>> will loose content :-). What do you think?
> I agree! :)

OK let's agree first and I will file after :-)

Great work so far!

A+

-- Jeanfranncois


>
> Thanks.
>
> WBR,
> Alexey.
>
>>
>>
>> A+
>>
>> -- Jeanfrancois
>>
>>
>>> Thanks!
>>> WBR,
>>> Alexey.
>>>>
>>>>
>>>> A+
>>>>
>>>> -- Jeanfrancois
>>>>
>>>>
>>>>
>>>>> }
>>>>> }
>>>>> }
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>