|
View:
New views
4 Messages
—
Rating Filter:
Alert me
|
|
|
Grizzly 2.0: Echo sampleHi,
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@... |
|
|
Re: Grizzly 2.0: Echo sampleSalut,
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 sampleOn 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. 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. 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 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. 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? 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. 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? 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. 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 :-) 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 sampleSalut,
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@... |
| Free embeddable forum powered by Nabble | Forum Help |