Salut,
Oleksiy Stashok wrote:
>>>>>>> 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 :-)
> Well, I don't agree it's the same room :)) Filterchain read is just
> feature, which could be especially useful for client side code.
Agree...but that API should be on Transport IMO, not on FilterChain ;-)
>
>
>>> 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).
> I'm looking at this, just as 3 sets of I/O operations:
> readNow/writeNow
> readAsync/writeAsync
> read/write
I disagree. I would like to see read/write and a boolean to
blocking/non-blocking. This is just too much and too complicated to code
against. Why do you have 6 methods instead of 2 :-)
>
> which, IMHO, is not too much :)
>
>>> ................
>>> 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).
> ReadFuture is just subclass of Feature with predefined result: ReadResult.
Yes but why do we need the cast? Implementation wise I suspect we can
get rid of it.
>
>
>>>>>> 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 :-)
> Agree :)
>
>
>>> 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?
> Well, you build the FilterChain... you should know :)
Naaa ;-) The FilterChain in 1.x doesn't have that "feature" :-)
>
> Usually the filter chain represents some ecoding/decoding + processing
> logics. And usually one single Filter implements either
> encoding/decoding or processing logic.
> In your example encoding/decoding is implemented by: SSLFilter. Other
> filters represent some processing logic: logging, echoing.
If you make such difference between filters, then we should split the
concept in two:
Decoder/Encoder
Processor
because with your example it is too complex IMO to know what the
getMessage() will return. So I'm sticking to my -1 :-) What do you think
about adding Decoded/Encoder concept, and move them out the the
FilterChain? We will start looking like MINA ;-)
> The standalone filterchain read/write reuses just encoding/decoding
> logic of filterchain, which IMHO, could be very interesting (especially
> for the client side).
But you will cache the getMessages() somewhere, right? In case on byte
buffer, I'm not sure this is a good idea, unless I've misunderstood your
example.
>
> Example I showed above with HttpMessage looks interesting, doesn't it? :)
Not yet convinced ;-) HttpMessage will contains what? The header and the
body? Aille! ;-)
A+
-- Jeanfrancois
> This way Grizzly HTTP client implementation could be very clear and easy.
>
>>> 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 :-)
> Sure :)
>
> Thank you for feedback!
>
> WBR,
> Alexey.
>
>
>>
>>
>> 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
>>
>> ---------------------------------------------------------------------
>> 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
>