Hi Alexey,
I was using Tunnel implementation provided by you. I am new to grizzly
so I need some more help from you. Please provide steps how to plug in
parsing algorithm into it. Also tell me if parsing algorithm says data
is not read completely, what should be done next?
Also GET request in general does not have Content-Length header. What
should be done in those cases?
Thanks,
Kshitiz
Oleksiy Stashok wrote:
>
>>>
>>> Thanks a lot. Well, I get AlreadyConnectedExceptions if I connect
>>> more than once, the aquired connector seems to be already in use.
>>> What was the reason I could not allocate a new ConnectorHandler with
>>> new TCPConnectorHandler()? Well, but this helps
>>> also only limited: Every second connection does not work.
>>>
>> Looks like ConnectorHandler.close() wasn't called.
> Seems it was ReadFilter problem. Please retry after svn update.
>
> Alexey.
>
>
>>
>>> I have spend the day to get an own solution, but I failed. The first
>>> SelectionKey which is processed is always OP_READ, not an OP_ACCEPT.
>>> I noticed that the ProtocolFilter chain is only used if no
>>> CallbackHandler is attached
>> As JF wrote, CallbackHandler currently is used as *client side*
>> connection implementation. It was recently added, so there could be
>> some drawbacks, but with your feedback we can improve it.
>> ProtocolFilter is the part of *server side* processing chain.
>> OP_ACCEPT with default TCPSelectorHandler implementation will not be
>> passed for processing by server-chain. But in case of "tunnel" seems
>> it's not required, as connection initiator should send something, right?
>>
>> WBR,
>> Alexey.
>>
>>> (for which scenario is a CallbackHandler good for, and when a
>>> ProtocolFilter if they exclude each other?), so I attached null to
>>> the key after I got a connection. The sources are attached. I don't
>>> know why this programm fails.
>>>
>>> I also attached a modified version of the ConnectorHandler
>>> interface. A Channel can now be attached. For me it was useful or
>>> the only way I had seen to reuse a the convenient TCPConnectorHandler.
>>>
>>> Best Regards, Karsten
>>>
>>>
>>>> WBR,
>>>> Alexey.
>>>>
>>>> Karsten Ohme wrote:
>>>>
>>>>> On Fri, Jun 01, 2007 at 05:26:18PM +0200, Oleksiy Stashok wrote:
>>>>>
>>>>>
>>>>>> Hello Karsten,
>>>>>>
>>>>>> let me try to help you.
>>>>>> Let's start from the beginning and will not use cache for
>>>>>> simplicity, we can always add it later...
>>>>>> As I understood, you are not making http proxy, but some tunnel
>>>>>> for socket connections. In other words nothing http specific?
>>>>>>
>>>>>> So I would advice you to start implementing something called...
>>>>>> let's say ProxyProtocolFilter (as Jeanfrancois proposed) :)
>>>>>> To see how you can implement the Filter - please find EchoFilter
>>>>>> in Grizzly/framework test folder.
>>>>>>
>>>>>> As for proxy-to-tomcat connections - please use ConnectorHandlers
>>>>>> (to get one use controller.aquireConnectorHandler(), and don't
>>>>>> forget to release it).
>>>>>> We're working on documentations, but you can take a look at unit
>>>>>> tests we have to understand how you can use Grizzly both for
>>>>>> client and server sides.
>>>>>>
>>>>>> If you'll have questions - please ask.
>>>>>>
>>>>> OK, I have a ProxyProtocolFilter and I also found out that the
>>>>> WorkerThread contains the ByteBuffer. So I would do the following
>>>>>
>>>>> Use the returned ByteBuffer from the WorkerThread aquire a
>>>>> TCPConnectorHandler from the Controller in the Context
>>>>>
>>>>> register a CallBackHandler with a reference to the
>>>>> SocketConnection for the way from client to proxy and an
>>>>> implemented onConnect() method
>>>>>
>>>>> write out the data with write(byteBuffer, true)
>>>>>
>>>>> When do I release the TCPConnectorHandler? I store the
>>>>> TCPConnector with the SocketChannel for the way client-proxy in a
>>>>> Map in the Context. So the connection can be reused. What is better?
>>>>>
>>>>> When the connection is done onConnect gets executed and I can get
>>>>> the SocketChannel for the line proxy - Tomcat server
>>>>> The pair of SocketConnections client-proxy and proxy-Tomcat server
>>>>> is kept in a mapping in the context. This is important to remember
>>>>> who is talking over the proxy to whom.
>>>>>
>>>>> For the way server-proxy to proxy-client I have to write back the
>>>>> data. Problem I see no way how I can use here an
>>>>> TCPConnectorHandler. The TCPSelectorHandler offers no possibility
>>>>> to use an existing SocketChannel. I would change this to simplify
>>>>> my life or how is it intended?
>>>>>
>>>>> Why are there two methods: register(CallbackHandler) and
>>>>> setCallbackHandler(...)?
>>>>>
>>>>> Thanks,
>>>>> Karsten
>>>>>
>>>>>
>>>>>
>>>>>> WBR,
>>>>>> Alexey.
>>>>>>
>>>>>> Karsten Ohme wrote:
>>>>>>
>>>>>>> On Thu, May 31, 2007 at 02:43:43PM -0400, Jeanfrancois Arcand
>>>>>>> wrote:
>>>>>>>
>>>>>>>
>>>>>>>> Hi Karsten,
>>>>>>>>
>>>>>>>> don't stop the feedback!
>>>>>>>>
>>>>>>>> Karsten Ohme wrote:
>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> I want to program a proxy (actually tunnel). All connections
>>>>>>>>> are made to the proxy, the proxy makes some decisions and
>>>>>>>>> forwards them to the server. For my situation many clients
>>>>>>>>> connect to the proxy on port 80, the proxy forwards the
>>>>>>>>> requests to a Tomcat server on port 8080 and writes the
>>>>>>>>> response back to the client.
>>>>>>>>>
>>>>>>>> Stupid question: can the client connect directly to Tomcat or
>>>>>>>> does all connection must go to the proxy? I suspect all
>>>>>>>> connections have to pass through the proxy, but in case not,
>>>>>>>> the proxy can always send a redirect to the client (using the
>>>>>>>> location: header).
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> How can I acieve this with Grizzly? I though I had to extend
>>>>>>>>> the TCPSelectorHandler, overwrite the onAcceptInterest method,
>>>>>>>>> establish there a new TCPConnectorHandler for the path
>>>>>>>>> client-proxy and one for proxy-server and register
>>>>>>>>> CallbackHandlers wo propagate the read and write operations.
>>>>>>>>>
>>>>>>>> I would not override the onAcceptInterest but instead let the
>>>>>>>> default workflow happen. On of the reason is onAcceptInterest
>>>>>>>> is executed on the same thread as the Selector.select(), which
>>>>>>>> is a performance bottleneck. I would instead implement two
>>>>>>>> ProtocolFilters that uses the newly added ConnectionPool/Cache.
>>>>>>>> My recommendation is to do:
>>>>>>>>
>>>>>>>> 1. Use the default ReadFilter to execute the first read to make
>>>>>>>> sure the connection hasn't been closed between the accept() and
>>>>>>>> the first read.
>>>>>>>> 2. Add a new ProxyProtocolFilter:
>>>>>>>>
>>>>>>>> + When initializing, create a pool of connection your remote
>>>>>>>> server (Tomcat). I recommend you take a look at the new
>>>>>>>> ConnectionPool/Cache Alexey demonstrated yesterday at the
>>>>>>>> Grizzly meeting.
>>>>>>>>
>>>>>>> I don't know how to use it. What is a ConnectionPool? There is
>>>>>>> only a class ConnectionCache. What is it useful for? From the
>>>>>>> name I suspect that some sort of connections are cached and I
>>>>>>> have a method to get free connections which I can use. I would
>>>>>>> expect a constructor with a given number where this amount of
>>>>>>> connections are created. For me this would be always the same
>>>>>>> type of connection from the proxy to the client, for the
>>>>>>> way
>>>>>> >from client to proxy I need for each client a single connection
>>>>>> or not?
>>>>>>> What are doing requestReceived(), requestProcessed() and
>>>>>>> responseSent( C conn ). Which connection I have to pass in as
>>>>>>> parameter? What means cached? In the sources it looks like i
>>>>>>> have to pass the connectiosn on my own. From which class must
>>>>>>> the methods be called? How can I reuese such a cached exception
>>>>>>> when it is idle? There is not get method.
>>>>>>>
>>>>>>> Regards,
>>>>>>> Karsten
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> + When execute() is invoked, use a StreamAlgorithm
>>>>>>>> implementation to make sure you can read the complete HTTP
>>>>>>>> request (note: you gonna need to buffer the body as well). The
>>>>>>>> module/http sub module have a StreamAlgorithm implementations
>>>>>>>> called ContentLengthAlgorithm|StateMachineAlgoruithm that can
>>>>>>>> be reused. Mainly those classes will make sure the entire
>>>>>>>> headers + body are read.
>>>>>>>> + Once you have read all the bytes, get a connection from the
>>>>>>>> connection pool and flush the bytes to Tomcat. Make the
>>>>>>>> TCPConnectionHandler.write(bb,TRUE) so the temporary Selector
>>>>>>>> trick can be reused.
>>>>>>>> + Then read back the response and flush it back to the client.
>>>>>>>>
>>>>>>>> Would that make sense? You might also want to create two
>>>>>>>> ProtocolFilter, one for reading the request, and one for
>>>>>>>> writing the response to the active connection to Tomcat.
>>>>>>>>
>>>>>>>>
>>>>>>>>> But I don't know how the ProtocolFilter fits into the picture.
>>>>>>>>> How do I use it? I also want to use TLS connections. How can I
>>>>>>>>> get the data which is decoded?
>>>>>>>>>
>>>>>>>>> Is there any documentation or tutorial for the new Grizzly API?
>>>>>>>>>
>>>>>>>> Take a look at the following talks:
>>>>>>>>
>>>>>>>> https://grizzly.dev.java.net/presentations/FISL-2007.pdf
>>>>>>>> http://weblogs.java.net/blog/jfarcand/archive/BOF-4989-Grizzly.pdf
>>>>>>>>
>>>>>>>> We don't have yet tutorials but I'm working on one right now.
>>>>>>>>
>>>>>>>> Hope that help.
>>>>>>>>
>>>>>>>> -- Jeanfrancois
>>>>>>>>
>>>>>>>>
>>>>>>>>> Regards,
>>>>>>>>> Karsten
>>>>>>>>>
>>>>>>>>> ---------------------------------------------------------------------
>>>>>>>>>
>>>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>>>>>
>>>>>>>>>
>>>>>>>> ---------------------------------------------------------------------
>>>>>>>>
>>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>>>>
>>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>>
>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>>
>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>>
>>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>
>>>>>
>>>>>
>>>
>>>
>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>
>>>> ------------------------------------------------------------------------
>>>>
>>>>
>>>> /*
>>>> * The contents of this file are subject to the terms
>>>> * of the Common Development and Distribution License
>>>> * (the License). You may not use this file except in
>>>> * compliance with the License.
>>>> *
>>>> * You can obtain a copy of the license at
>>>> * https://glassfish.dev.java.net/public/CDDLv1.0.html or
>>>> * glassfish/bootstrap/legal/CDDLv1.0.txt.
>>>> * See the License for the specific language governing
>>>> * permissions and limitations under the License.
>>>> *
>>>> * When distributing Covered Code, include this CDDL
>>>> * Header Notice in each file and include the License file
>>>> * at glassfish/bootstrap/legal/CDDLv1.0.txt.
>>>> * If applicable, add the following below the CDDL Header,
>>>> * with the fields enclosed by brackets [] replaced by
>>>> * you own identifying information:
>>>> * "Portions Copyrighted [year] [name of copyright owner]"
>>>> *
>>>> * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
>>>> */
>>>> package com.sun.grizzly;
>>>>
>>>> import java.io.Closeable;
>>>> import java.io.IOException;
>>>> import java.net.SocketAddress;
>>>> import java.nio.ByteBuffer;
>>>> import java.nio.channels.SelectableChannel;
>>>> import java.nio.channels.SelectionKey;
>>>>
>>>> /**
>>>> * Client side interface used to implement non blocking client
>>>> operation.
>>>> * Implementation of this class must make sure the following
>>>> methods are invoked
>>>> * in that order:
>>>> * * (1) connect() (2) read() or write().
>>>> * * * @param E a <code>SelectorHandler</code>
>>>> * @author Jeanfrancois Arcand
>>>> */
>>>> public interface ConnectorHandler<E extends SelectorHandler, C
>>>> extends SelectableChannel> extends Handler, Closeable {
>>>>
>>>>
>>>> /**
>>>> * A token decribing the protocol supported by an
>>>> implementation of this
>>>> * interface
>>>> * @return <code>Controller.Protocol</code>
>>>> */
>>>> public Controller.Protocol protocol();
>>>>
>>>>
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g OP_READ
>>>> * or OP_WRITE), the <code>Controller</code> will invoke the
>>>> * CallBackHandler.
>>>> * * @param remoteAddress remote address to connect
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when an non
>>>> * blocking operation is ready to be handled.
>>>> * @param e <code>SelectorHandler</code>
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress,
>>>> CallbackHandler callbackHandler, E e) throws IOException;
>>>>
>>>>
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g OP_READ
>>>> * or OP_WRITE), the <code>Controller</code> will invoke the
>>>> * CallBackHandler.
>>>> * * @param remoteAddress remote address to connect *
>>>> @param callbackHandler the handler invoked by the Controller when
>>>> * an non blocking operation is ready to be handled.
>>>> * @throws java.io.IOException
>>>> */ public void connect(SocketAddress remoteAddress,
>>>> CallbackHandler callbackHandler) throws
>>>> IOException;
>>>> /**
>>>> * Connect to hostname:port. Internally an instance of
>>>> Controller and its
>>>> * default SelectorHandler will be created everytime this
>>>> method is called.
>>>> * This method should be used only and only if no external
>>>> Controller has
>>>> * been initialized.
>>>> * * @param remoteAddress remote address to connect
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress) throws
>>>> IOException;
>>>>
>>>>
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g OP_READ
>>>> * or OP_WRITE), the <code>Controller</code> will invoke the
>>>> * CallBackHandler.
>>>> * * @param remoteAddress remote address to connect *
>>>> @param localAddress local address to bind
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be
>>>> handled. * @param e <code>SelectorHandler</code>
>>>> * @throws java.io.IOException
>>>> */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress, CallbackHandler callbackHandler, E e) throws
>>>> IOException;
>>>>
>>>>
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g OP_READ
>>>> * or OP_WRITE), the <code>Controller</code> will invoke the
>>>> * CallBackHandler.
>>>> * * @param remoteAddress remote address to connect
>>>> * @param localAddress local address to bind
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> * @throws java.io.IOException */ public void
>>>> connect(SocketAddress remoteAddress, SocketAddress localAddress,
>>>> CallbackHandler callbackHandler) throws
>>>> IOException;
>>>> /**
>>>> * Connect to hostname:port. Internally an instance of
>>>> Controller and its
>>>> * default SelectorHandler will be created everytime this
>>>> method is called.
>>>> * This method should be used only and only if no external
>>>> Controller has
>>>> * been initialized.
>>>> * * @param remoteAddress remote address to connect
>>>> * @param localAddress local address to bind
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress) throws IOException;
>>>>
>>>>
>>>> /**
>>>> * Read bytes. If blocking is set to <tt>true</tt>, a pool of
>>>> temporary
>>>> * <code>Selector</code> will be used to read bytes.
>>>> * * @param byteBuffer The byteBuffer to store bytes.
>>>> * @param blocking <tt>true</tt> if a a pool of temporary
>>>> Selector is
>>>> * required to handle a blocking read.
>>>> * @return number of bytes read
>>>> * @throws java.io.IOException */
>>>> public long read(ByteBuffer byteBuffer, boolean blocking)
>>>> throws IOException;
>>>>
>>>>
>>>> /**
>>>> * Writes bytes. If blocking is set to <tt>true</tt>, a pool of
>>>> temporary
>>>> * <code>Selector</code> will be used to writes bytes.
>>>> * * @param byteBuffer The byteBuffer to write.
>>>> * @param blocking <tt>true</tt> if a a pool of temporary Selector
>>>> * is required to handle a blocking write.
>>>> * @return number of bytes written
>>>> * @throws java.io.IOException */ public long
>>>> write(ByteBuffer byteBuffer, boolean blocking) throws IOException;
>>>> /**
>>>> * Close the underlying connection.
>>>> * * @throws java.io.IOException
>>>> */
>>>> public void close() throws IOException;
>>>>
>>>>
>>>> /**
>>>> * Decide how the OP_CONNECT final steps are handled.
>>>> * @param key <code>SelectionKey</code>
>>>> */
>>>> public void finishConnect(SelectionKey key);
>>>>
>>>>
>>>> /**
>>>> * Set the <code>Controller</code> associated with this instance.
>>>> * @param controller <code>Controller</code>
>>>> */
>>>> public void setController(Controller controller);
>>>>
>>>>
>>>> /**
>>>> * Return the <code>Controller</code>
>>>> * * @return
>>>> */
>>>> public Controller getController();
>>>>
>>>> /**
>>>> * Method returns <code>SelectorHandler</code>, which manages this
>>>> * <code>ConnectorHandler</code>
>>>> * * @return <code>SelectorHandler</code>
>>>> */
>>>> public E getSelectorHandler();
>>>>
>>>> /**
>>>> * Method returns <code>ConnectorHandler</code>'s underlying
>>>> channel
>>>> * * @return channel
>>>> */
>>>> public C getUnderlyingChannel();
>>>>
>>>> /**
>>>> * Returns <code>ConnectorHandler</code>'s callback handler
>>>> instance,
>>>> * which is used to process occuring events
>>>> * * @return callback handler
>>>> */
>>>> public CallbackHandler getCallbackHandler();
>>>>
>>>> /**
>>>> * Sets an existing channel for this ConnectorHandler. This can
>>>> be used to
>>>> * (re)use this ConnectorHandler for an already existing
>>>> connection.
>>>> * <p>
>>>> * The controller which controls the channel must also be set.
>>>> * @param channel The channel to use. * @see
>>>> #setController(Controller).
>>>> */
>>>> public void setUnderlyingChannel(C channel);
>>>>
>>>> /**
>>>> * Sets <code>ConnectorHandler</code>'s callback handler
>>>> instance, which
>>>> * is used to process occuring events
>>>> * * @param callbackHandler handler
>>>> */
>>>> public void setCallbackHandler(CallbackHandler callbackHandler);
>>>> }
>>>>
>>>> ------------------------------------------------------------------------
>>>>
>>>>
>>>> /*
>>>> * The contents of this file are subject to the terms
>>>> * of the Common Development and Distribution License
>>>> * (the License). You may not use this file except in
>>>> * compliance with the License.
>>>> *
>>>> * You can obtain a copy of the license at
>>>> * https://glassfish.dev.java.net/public/CDDLv1.0.html or
>>>> * glassfish/bootstrap/legal/CDDLv1.0.txt.
>>>> * See the License for the specific language governing
>>>> * permissions and limitations under the License.
>>>> *
>>>> * When distributing Covered Code, include this CDDL
>>>> * Header Notice in each file and include the License file
>>>> * at glassfish/bootstrap/legal/CDDLv1.0.txt.
>>>> * If applicable, add the following below the CDDL Header,
>>>> * with the fields enclosed by brackets [] replaced by
>>>> * you own identifying information:
>>>> * "Portions Copyrighted [year] [name of copyright owner]"
>>>> *
>>>> * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
>>>> */
>>>>
>>>> package com.sun.grizzly;
>>>>
>>>> import com.sun.grizzly.Controller;
>>>> import com.sun.grizzly.util.ByteBufferInputStream;
>>>> import java.io.IOException;
>>>> import java.net.SocketAddress;
>>>> import java.nio.ByteBuffer;
>>>> import java.nio.channels.AlreadyConnectedException;
>>>> import java.nio.channels.NotYetConnectedException;
>>>> import java.nio.channels.SelectionKey;
>>>> import java.nio.channels.DatagramChannel;
>>>> import java.util.concurrent.CountDownLatch;
>>>> import java.util.concurrent.TimeUnit;
>>>>
>>>> /**
>>>> * Client side interface used to implement non blocking client
>>>> operation. * Implementation of this class must make sure the
>>>> following methods are * invoked in that order:
>>>> * * (1) connect()
>>>> * (2) read() or write().
>>>> * * @author Jeanfrancois Arcand
>>>> */
>>>> public class UDPConnectorHandler implements
>>>> ConnectorHandler<UDPSelectorHandler, DatagramChannel>{
>>>> /**
>>>> * The underlying UDPSelectorHandler used to mange SelectionKeys.
>>>> */
>>>> private UDPSelectorHandler selectorHandler;
>>>> /**
>>>> * A <code>CallbackHandler</code> handler invoked by the
>>>> UDPSelectorHandler
>>>> * when a non blocking operation is ready to be processed.
>>>> */
>>>> private CallbackHandler callbackHandler;
>>>>
>>>> /**
>>>> * The connection's DatagramChannel.
>>>> */
>>>> private DatagramChannel datagramChannel;
>>>> /**
>>>> * Is the connection established.
>>>> */
>>>> private volatile boolean isConnected;
>>>> /**
>>>> * The internal Controller used (in case not specified).
>>>> */
>>>> private Controller controller;
>>>>
>>>> /**
>>>> * IsConnected Latch related
>>>> */
>>>> private CountDownLatch isConnectedLatch; /**
>>>> * Are we creating a controller every run.
>>>> */
>>>> private boolean isStandalone = false;
>>>> /**
>>>> * A blocking <code>InputStream</code> that use a pool of Selector
>>>> * to execute a blocking read operation.
>>>> */
>>>> private ByteBufferInputStream inputStream; /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> */
>>>> public void connect(SocketAddress remoteAddress,
>>>> CallbackHandler callbackHandler) throws
>>>> IOException {
>>>> connect(remoteAddress,null,callbackHandler); }
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param localAddress local address to bind
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress,
>>>> CallbackHandler callbackHandler) throws
>>>> IOException { if (controller == null){
>>>> throw new IllegalStateException("Controller cannot be
>>>> null");
>>>> }
>>>> connect(remoteAddress,localAddress,callbackHandler,
>>>>
>>>> (UDPSelectorHandler)controller.getSelectorHandler(protocol()));
>>>> }
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> * @param selectorHandler an instance of SelectorHandler.
>>>> */
>>>> public void connect(SocketAddress remoteAddress,
>>>> CallbackHandler callbackHandler,
>>>> UDPSelectorHandler selectorHandler) throws
>>>> IOException {
>>>> connect(remoteAddress,null,callbackHandler,selectorHandler);
>>>> } /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param localAddress local address to bin
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> * @param selectorHandler an instance of SelectorHandler.
>>>> */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress,
>>>> CallbackHandler callbackHandler,
>>>> UDPSelectorHandler selectorHandler) throws
>>>> IOException {
>>>> if (isConnected){
>>>> throw new AlreadyConnectedException();
>>>> }
>>>> if (controller == null){
>>>> throw new IllegalStateException("Controller cannot be
>>>> null");
>>>> }
>>>> if (selectorHandler == null){
>>>> throw new IllegalStateException("Controller cannot be
>>>> null");
>>>> }
>>>> this.selectorHandler = selectorHandler;
>>>> this.callbackHandler = callbackHandler;
>>>> // Wait for the onConnect to be invoked.
>>>> isConnectedLatch = new CountDownLatch(1);
>>>> selectorHandler.connect(remoteAddress,localAddress,callbackHandler);
>>>> inputStream = new ByteBufferInputStream();
>>>> try {
>>>> isConnectedLatch.await(30, TimeUnit.SECONDS);
>>>> } catch (InterruptedException ex) {
>>>> throw new IOException(ex.getMessage());
>>>> }
>>>> }
>>>>
>>>> /**
>>>> * Connect to hostname:port. Internally an instance of
>>>> Controller and
>>>> * its default SelectorHandler will be created everytime this
>>>> method is * called. This method should be used only and only
>>>> if no external * Controller has been initialized.
>>>> * @param remoteAddress remote address to connect
>>>> */
>>>> public void connect(SocketAddress remoteAddress)
>>>> throws IOException {
>>>> connect(remoteAddress,(SocketAddress)null); }
>>>> /**
>>>> * Connect to hostname:port. Internally an instance of
>>>> Controller and
>>>> * its default SelectorHandler will be created everytime this
>>>> method is * called. This method should be used only and only
>>>> if no external * Controller has been initialized.
>>>> * @param remoteAddress remote address to connect
>>>> * @param localAddress local address to bin
>>>> */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress) throws IOException {
>>>> if (isConnected){
>>>> throw new AlreadyConnectedException();
>>>> }
>>>> if (controller == null){ isStandalone
>>>> = true;
>>>> controller = new Controller();
>>>> controller.setSelectorHandler(new
>>>> UDPSelectorHandler(true));
>>>> DefaultPipeline pipeline = new DefaultPipeline();
>>>> pipeline.initPipeline();
>>>> pipeline.startPipeline();
>>>> controller.setPipeline(pipeline);
>>>>
>>>> callbackHandler = new CallbackHandler<Context>(){
>>>> public void onConnect(IOEvent<Context> ioEvent) {
>>>> SelectionKey key =
>>>> ioEvent.attachment().getSelectionKey();
>>>> finishConnect(key);
>>>> }
>>>> public void onRead(IOEvent<Context> ioEvent) {
>>>> }
>>>> public void onWrite(IOEvent<Context> ioEvent) {
>>>> }
>>>> };
>>>>
>>>> final CountDownLatch latch = new CountDownLatch(1);
>>>> try{
>>>> pipeline.execute(new Context(){
>>>> public Object call() throws Exception {
>>>> latch.countDown();
>>>> controller.start();
>>>> return null;
>>>> } });
>>>> } catch (PipelineFullException ex){
>>>> throw new IOException(ex.getMessage());
>>>> }
>>>> try {
>>>> latch.await(); Thread.sleep(1000);
>>>> } catch (InterruptedException ex) {
>>>> }
>>>> }
>>>> connect(remoteAddress,localAddress,callbackHandler,
>>>>
>>>> (UDPSelectorHandler)controller.getSelectorHandler(protocol()));
>>>> }
>>>> /**
>>>> * Read bytes. If blocking is set to <tt>true</tt>, a pool of
>>>> temporary
>>>> * <code>Selector</code> will be used to read bytes.
>>>> * @param byteBuffer The byteBuffer to store bytes.
>>>> * @param blocking <tt>true</tt> if a a pool of temporary Selector
>>>> * is required to handle a blocking read.
>>>> */
>>>> public long read(ByteBuffer byteBuffer, boolean blocking)
>>>> throws IOException {
>>>> if (!isConnected){
>>>> throw new NotYetConnectedException();
>>>> }
>>>> SelectionKey key =
>>>> datagramChannel.keyFor(selectorHandler.getSelector());
>>>> if (blocking){
>>>> inputStream.setSelectionKey(key);
>>>> inputStream.setChannelType(
>>>>
>>>> ByteBufferInputStream.ChannelType.DatagramChannel);
>>>> int nRead = inputStream.read(byteBuffer);
>>>> return nRead;
>>>> } else {
>>>> if (callbackHandler == null){
>>>> throw new IllegalStateException
>>>> ("Non blocking read needs a CallbackHandler");
>>>> }
>>>> int nRead = datagramChannel.read(byteBuffer);
>>>>
>>>> if (nRead == 0){
>>>> key.attach(callbackHandler);
>>>> selectorHandler.register(key,
>>>> SelectionKey.OP_READ|SelectionKey.OP_WRITE);
>>>> }
>>>> return nRead;
>>>> }
>>>> }
>>>> /**
>>>> * Writes bytes. If blocking is set to <tt>true</tt>, a pool of
>>>> temporary
>>>> * <code>Selector</code> will be used to writes bytes.
>>>> * @param byteBuffer The byteBuffer to write.
>>>> * @param blocking <tt>true</tt> if a a pool of temporary Selector
>>>> * is required to handle a blocking write.
>>>> */ public long write(ByteBuffer byteBuffer, boolean
>>>> blocking) throws IOException {
>>>> if (!isConnected){
>>>> throw new NotYetConnectedException();
>>>> }
>>>> SelectionKey key =
>>>> datagramChannel.keyFor(selectorHandler.getSelector());
>>>> if (blocking){
>>>> throw new IllegalStateException("Blocking mode not
>>>> supported");
>>>> } else {
>>>> if (callbackHandler == null){
>>>> throw new IllegalStateException
>>>> ("Non blocking write needs a
>>>> CallbackHandler");
>>>> }
>>>> int nWrite = datagramChannel.write(byteBuffer);
>>>> if (nWrite == 0){
>>>> key.attach(callbackHandler);
>>>> selectorHandler.register(key,
>>>> SelectionKey.OP_READ|SelectionKey.OP_WRITE);
>>>> } return nWrite;
>>>> }
>>>> }
>>>> /**
>>>> * Receive bytes.
>>>> * @param byteBuffer The byteBuffer to store bytes.
>>>> * @param socketAddress * @return number bytes sent
>>>> * @throws java.io.IOException */
>>>> public long send(ByteBuffer byteBuffer, SocketAddress
>>>> socketAddress) throws IOException {
>>>> if (!isConnected){
>>>> throw new NotYetConnectedException();
>>>> }
>>>> if (callbackHandler == null){
>>>> throw new IllegalStateException
>>>> ("Non blocking read needs a CallbackHandler");
>>>> }
>>>>
>>>> return datagramChannel.send(byteBuffer,socketAddress);
>>>> }
>>>> /**
>>>> * Receive bytes.
>>>> * @param byteBuffer The byteBuffer to store bytes.
>>>> * @return <code>SocketAddress</code>
>>>> * @throws java.io.IOException */
>>>> public SocketAddress receive(ByteBuffer byteBuffer) throws
>>>> IOException {
>>>> if (!isConnected){
>>>> throw new NotYetConnectedException();
>>>> }
>>>> SelectionKey key =
>>>> datagramChannel.keyFor(selectorHandler.getSelector());
>>>> if (callbackHandler == null){
>>>> throw new IllegalStateException
>>>> ("Non blocking read needs a CallbackHandler");
>>>> }
>>>> SocketAddress socketAddress =
>>>> datagramChannel.receive(byteBuffer);
>>>> return socketAddress;
>>>> }
>>>> /**
>>>> * Close the underlying connection.
>>>> */
>>>> public void close() throws IOException{
>>>> if (datagramChannel != null){
>>>> if (selectorHandler != null){
>>>> SelectionKey key =
>>>> datagramChannel.keyFor(selectorHandler.getSelector());
>>>> if (key == null) return;
>>>> key.cancel();
>>>> key.attach(null);
>>>> }
>>>> datagramChannel.close(); }
>>>> if (controller != null && isStandalone){
>>>> controller.stop();
>>>> controller = null;
>>>> } isStandalone = false;
>>>> }
>>>>
>>>> /**
>>>> * Finish handling the OP_CONNECT interest ops.
>>>> */
>>>> public void finishConnect(SelectionKey key){
>>>> datagramChannel = (DatagramChannel)key.channel();
>>>> isConnected = datagramChannel.isConnected();
>>>> isConnectedLatch.countDown();
>>>> }
>>>> /**
>>>> * A token decribing the protocol supported by an
>>>> implementation of this
>>>> * interface
>>>> */
>>>> public Controller.Protocol protocol(){
>>>> return Controller.Protocol.UDP;
>>>> }
>>>> /**
>>>> * Is the underlying DatagramChannel connected.
>>>> * @return true if connected, othewise false
>>>> */
>>>> public boolean isConnected(){
>>>> return isConnected;
>>>> } public Controller getController() {
>>>> return controller;
>>>> }
>>>>
>>>> public void setController(Controller controller) {
>>>> this.controller = controller;
>>>> }
>>>>
>>>> public DatagramChannel getUnderlyingChannel() {
>>>> return datagramChannel;
>>>> }
>>>>
>>>> public CallbackHandler getCallbackHandler() {
>>>> return callbackHandler;
>>>> }
>>>>
>>>> public void setCallbackHandler(CallbackHandler callbackHandler) {
>>>> this.callbackHandler = callbackHandler;
>>>> }
>>>>
>>>> public UDPSelectorHandler getSelectorHandler() {
>>>> return selectorHandler;
>>>> }
>>>>
>>>> public void setChannel(DatagramChannel channel,
>>>> UDPSelectorHandler selectorHandler) {
>>>> this.selectorHandler = selectorHandler;
>>>> this.datagramChannel = channel;
>>>> }
>>>>
>>>> public void setUnderlyingChannel(DatagramChannel channel) {
>>>> this.datagramChannel = channel;
>>>> }
>>>> }
>>>>
>>>> ------------------------------------------------------------------------
>>>>
>>>>
>>>> /*
>>>> * The contents of this file are subject to the terms
>>>> * of the Common Development and Distribution License
>>>> * (the License). You may not use this file except in
>>>> * compliance with the License.
>>>> *
>>>> * You can obtain a copy of the license at
>>>> * https://glassfish.dev.java.net/public/CDDLv1.0.html or
>>>> * glassfish/bootstrap/legal/CDDLv1.0.txt.
>>>> * See the License for the specific language governing
>>>> * permissions and limitations under the License.
>>>> *
>>>> * When distributing Covered Code, include this CDDL
>>>> * Header Notice in each file and include the License file
>>>> * at glassfish/bootstrap/legal/CDDLv1.0.txt.
>>>> * If applicable, add the following below the CDDL Header,
>>>> * with the fields enclosed by brackets [] replaced by
>>>> * you own identifying information:
>>>> * "Portions Copyrighted [year] [name of copyright owner]"
>>>> *
>>>> * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
>>>> */
>>>> package com.sun.grizzly;
>>>>
>>>> import com.sun.grizzly.Controller.Protocol;
>>>> import com.sun.grizzly.util.ByteBufferInputStream;
>>>> import com.sun.grizzly.util.OutputWriter;
>>>> import java.io.IOException;
>>>> import java.net.SocketAddress;
>>>> import java.nio.ByteBuffer;
>>>> import java.nio.channels.AlreadyConnectedException;
>>>> import java.nio.channels.NotYetConnectedException;
>>>> import java.nio.channels.SelectableChannel;
>>>> import java.nio.channels.SelectionKey;
>>>> import java.nio.channels.SocketChannel;
>>>> import java.util.concurrent.CountDownLatch;
>>>> import java.util.concurrent.TimeUnit;
>>>>
>>>> /**
>>>> * Non blocking TCP Connector Handler. The recommended way to use
>>>> this class
>>>> * is by creating an external Controller and share the same
>>>> SelectorHandler
>>>> * instance.
>>>> *
>>>> * Recommended
>>>> * -----------
>>>> * Controller controller = new Controller();
>>>> * // new TCPSelectorHandler(true) means the Selector will be used
>>>> only
>>>> * // for client operation (OP_READ, OP_WRITE, OP_CONNECT).
>>>> * TCPSelectorHandler tcpSelectorHandler = new
>>>> TCPSelectorHandler(true); *
>>>> controller.setSelectorHandler(tcpSelectorHandler);
>>>> * TCPConnectorHandler tcpConnectorHandler = new
>>>> TCPConnectorHandler();
>>>> * tcpConnectorHandler.connect(localhost,port, new
>>>> CallbackHandler(){...},
>>>> * tcpSelectorHandler);
>>>> * TCPConnectorHandler tcpConnectorHandler2 = new
>>>> TCPConnectorHandler();
>>>> * tcpConnectorHandler2.connect(localhost,port, new
>>>> CallbackHandler(){...},
>>>> * tcpSelectorHandler);
>>>> *
>>>> * Not recommended (but still works)
>>>> * ---------------------------------
>>>> * TCPConnectorHandler tcpConnectorHandler = new
>>>> TCPConnectorHandler();
>>>> * tcpConnectorHandler.connect(localhost,port);
>>>> *
>>>> * Internally, an new Controller will be created everytime
>>>> connect(localhost,port)
>>>> * is invoked, which has an impact on performance.
>>>> *
>>>> * @author Jeanfrancois Arcand
>>>> */
>>>> public class TCPConnectorHandler implements
>>>> ConnectorHandler<TCPSelectorHandler, SocketChannel>{
>>>> /**
>>>> * The underlying TCPSelectorHandler used to mange SelectionKeys.
>>>> */
>>>> private TCPSelectorHandler selectorHandler;
>>>> /**
>>>> * A <code>CallbackHandler</code> handler invoked by the
>>>> TCPSelectorHandler
>>>> * when a non blocking operation is ready to be processed.
>>>> */
>>>> private CallbackHandler callbackHandler;
>>>> /**
>>>> * A blocking <code>InputStream</code> that use a pool of Selector
>>>> * to execute a blocking read operation.
>>>> */
>>>> private ByteBufferInputStream inputStream;
>>>> /**
>>>> * The connection's SocketChannel.
>>>> */
>>>> private SocketChannel socketChannel;
>>>> /**
>>>> * Is the connection established.
>>>> */
>>>> private volatile boolean isConnected;
>>>> /**
>>>> * The internal Controller used (in case not specified).
>>>> */
>>>> private Controller controller;
>>>>
>>>> /**
>>>> * IsConnected Latch related
>>>> */
>>>> private CountDownLatch isConnectedLatch; /**
>>>> * Are we creating a controller every run.
>>>> */
>>>> private boolean isStandalone = false;
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress,
>>>> CallbackHandler callbackHandler) throws
>>>> IOException {
>>>> connect(remoteAddress,null,callbackHandler); }
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param localAddress local address to bind
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress,
>>>> CallbackHandler callbackHandler) throws
>>>> IOException { if (controller == null){
>>>> throw new IllegalStateException("Controller cannot be
>>>> null");
>>>> }
>>>> connect(remoteAddress,localAddress,callbackHandler,
>>>>
>>>> (TCPSelectorHandler)controller.getSelectorHandler(protocol()));
>>>> }
>>>> /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> * @param selectorHandler an instance of SelectorHandler.
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress,
>>>> CallbackHandler callbackHandler,
>>>> TCPSelectorHandler selectorHandler) throws
>>>> IOException {
>>>> connect(remoteAddress,null,callbackHandler,selectorHandler);
>>>> } /**
>>>> * Connect to hostname:port. When an aysnchronous event happens
>>>> (e.g * OP_READ or OP_WRITE), the <code>Controller</code> will
>>>> invoke * the CallBackHandler.
>>>> * @param remoteAddress remote address to connect
>>>> * @param localAddress local address to bin
>>>> * @param callbackHandler the handler invoked by the Controller
>>>> when * an non blocking operation is ready to be handled.
>>>> * @param selectorHandler an instance of SelectorHandler.
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress,
>>>> CallbackHandler callbackHandler,
>>>> TCPSelectorHandler selectorHandler) throws
>>>> IOException {
>>>> if (isConnected){
>>>> throw new AlreadyConnectedException();
>>>> }
>>>> if (controller == null){
>>>> throw new IllegalStateException("Controller cannot be
>>>> null");
>>>> }
>>>> if (selectorHandler == null){
>>>> throw new IllegalStateException("Controller cannot be
>>>> null");
>>>> }
>>>> this.selectorHandler = selectorHandler;
>>>> this.callbackHandler = callbackHandler;
>>>> // Wait for the onConnect to be invoked.
>>>> isConnectedLatch = new CountDownLatch(1);
>>>> selectorHandler.connect(remoteAddress,localAddress,callbackHandler);
>>>> inputStream = new ByteBufferInputStream();
>>>>
>>>> try {
>>>> isConnectedLatch.await(30, TimeUnit.SECONDS);
>>>> } catch (InterruptedException ex) {
>>>> throw new IOException(ex.getMessage());
>>>> }
>>>> }
>>>>
>>>> /**
>>>> * Connect to hostname:port. Internally an instance of
>>>> Controller and
>>>> * its default SelectorHandler will be created everytime this
>>>> method is * called. This method should be used only and only
>>>> if no external * Controller has been initialized.
>>>> * @param remoteAddress remote address to connect
>>>> * @throws java.io.IOException */
>>>> public void connect(SocketAddress remoteAddress)
>>>> throws IOException {
>>>> connect(remoteAddress,(SocketAddress)null); }
>>>> /**
>>>> * Connect to hostname:port. Internally an instance of
>>>> Controller and
>>>> * its default SelectorHandler will be created everytime this
>>>> method is * called. This method should be used only and only
>>>> if no external * Controller has been initialized.
>>>> * @param remoteAddress remote address to connect
>>>> * @throws java.io.IOException * @param localAddress local
>>>> address to bin
>>>> */
>>>> public void connect(SocketAddress remoteAddress, SocketAddress
>>>> localAddress) throws IOException {
>>>> if (isConnected){
>>>> throw new AlreadyConnectedException();
>>>> }
>>>> if (controller == null){ isStandalone
>>>> = true;
>>>> controller = new Controller();
>>>> controller.setSelectorHandler(new
>>>> TCPSelectorHandler(true));
>>>> DefaultPipeline pipeline = new DefaultPipeline();
>>>> pipeline.initPipeline();
>>>> pipeline.startPipeline();
>>>> controller.setPipeline(pipeline);
>>>>
>>>> callbackHandler = new CallbackHandler<Context>(){
>>>> public void onConnect(IOEvent<Context> ioEvent) {
>>>> SelectionKey key =
>>>> ioEvent.attachment().getSelectionKey();
>>>> socketChannel = (SocketChannel)key.channel();
>>>> finishConnect(key);
>>>>
>>>> getController().registerKey(key,SelectionKey.OP_WRITE,
>>>> Protocol.TCP);
>>>> }
>>>> public void onRead(IOEvent<Context> ioEvent) {
>>>> }
>>>> public void onWrite(IOEvent<Context> ioEvent) {
>>>> }
>>>> };
>>>>
>>>> final CountDownLatch latch = new CountDownLatch(1);
>>>> try{
>>>> pipeline.execute(new Context(){
>>>> public Object call() throws Exception {
>>>> latch.countDown();
>>>> controller.start();
>>>> return null;
>>>> } });
>>>> } catch (PipelineFullException ex){
>>>> throw new IOException(ex.getMessage());
>>>> }
>>>> try {
>>>> latch.await(); Thread.sleep(1000);
>>>> } catch (InterruptedException ex) {
>>>> }
>>>> }
>>>> connect(remoteAddress,localAddress,callbackHandler,
>>>>
>>>> (TCPSelectorHandler)controller.getSelectorHandler(protocol()));
>>>> }
>>>> /**
>>>> * Read bytes. If blocking is set to <tt>true</tt>, a pool of
>>>> temporary
>>>> * <code>Selector</code> will be used to read bytes.
>>>> * @param byteBuffer The byteBuffer to store bytes.
>>>> * @param blocking <tt>true</tt> if a a pool of temporary Selector
>>>> * is required to handle a blocking read.
>>>> * @return number of bytes read
>>>> * @throws java.io.IOException */
>>>> public long read(ByteBuffer byteBuffer, boolean blocking)
>>>> throws IOException {
>>>> if (!isConnected){
>>>> throw new NotYetConnectedException();
>>>> }
>>>> SelectionKey key =
>>>> socketChannel.keyFor(selectorHandler.getSelector());
>>>> if (blocking){
>>>> inputStream.setSelectionKey(key);
>>>> return inputStream.read(byteBuffer);
>>>> } else {
>>>> if (callbackHandler == null){
>>>> throw new IllegalStateException
>>>> ("Non blocking read needs a CallbackHandler");
>>>> }
>>>> int nRead = socketChannel.read(byteBuffer);
>>>>
>>>> if (nRead == 0){
>>>> key.attach(callbackHandler);
>>>> selectorHandler.register(key,SelectionKey.OP_READ);
>>>> }
>>>> return nRead;
>>>> }
>>>> }
>>>> /**
>>>> * Writes bytes. If blocking is set to <tt>true</tt>, a pool of
>>>> temporary
>>>> * <code>Selector</code> will be used to writes bytes.
>>>> * @param byteBuffer The byteBuffer to write.
>>>> * @param blocking <tt>true</tt> if a a pool of temporary Selector
>>>> * is required to handle a blocking write.
>>>> * @return number of bytes written
>>>> * @throws java.io.IOException */ public long
>>>> write(ByteBuffer byteBuffer, boolean blocking) throws IOException {
>>>> if (!isConnected){
>>>> throw new NotYetConnectedException();
>>>> }
>>>> SelectionKey key =
>>>> socketChannel.keyFor(selectorHandler.getSelector());
>>>> if (blocking){
>>>> return
>>>> OutputWriter.flushChannel(socketChannel,byteBuffer);
>>>> } else {
>>>> if (callbackHandler == null){
>>>> throw new IllegalStateException
>>>> ("Non blocking write needs a
>>>> CallbackHandler");
>>>> }
>>>> int nWrite = 1;
>>>> while (nWrite > 0 && byteBuffer.hasRemaining()){
>>>> nWrite = socketChannel.write(byteBuffer);
>>>> }
>>>> if (nWrite == 0 && byteBuffer.hasRemaining()){
>>>> key.attach(callbackHandler);
>>>> selectorHandler.register(key,SelectionKey.OP_WRITE);
>>>> } return nWrite;
>>>> }
>>>> }
>>>>
>>>> /**
>>>> * Close the underlying connection.
>>>> */
>>>> public void close() throws IOException{
>>>> if (socketChannel != null){
>>>> if (selectorHandler != null){
>>>> SelectionKey key =
>>>> socketChannel.keyFor(selectorHandler.getSelector());
>>>> if (key == null) return;
>>>> key.cancel();
>>>> key.attach(null);
>>>> }
>>>> socketChannel.close(); }
>>>> if (controller != null && isStandalone){
>>>> controller.stop();
>>>> controller = null;
>>>> } isStandalone = false;
>>>> }
>>>>
>>>> /**
>>>> * Finish handling the OP_CONNECT interest ops.
>>>> * @param key - a <code>SelectionKey</code>
>>>> */
>>>> public void finishConnect(SelectionKey key){
>>>> try{
>>>> socketChannel = (SocketChannel)key.channel();
>>>> socketChannel.finishConnect();
>>>> isConnected = socketChannel.isConnected();
>>>> } catch (IOException ex){
>>>> // XXX LOG ME
>>>> ex.printStackTrace();
>>>> } finally {
>>>> isConnectedLatch.countDown();
>>>> }
>>>> }
>>>> public void setUnderlyingChannel(SocketChannel
>>>> socketChannel) {
>>>> this.socketChannel = socketChannel;
>>>> }
>>>> /**
>>>> * A token decribing the protocol supported by an
>>>> implementation of this
>>>> * interface
>>>> * @return this <code>ConnectorHandler</code>'s protocol
>>>> */
>>>> public Controller.Protocol protocol(){
>>>> return Controller.Protocol.TCP;
>>>> }
>>>> /**
>>>> * Is the underlying SocketChannel connected.
>>>> * @return <tt>true</tt> if connected, otherwise <tt>false</tt>
>>>> */
>>>> public boolean isConnected(){
>>>> return isConnected;
>>>> } public Controller getController() {
>>>> return controller;
>>>> }
>>>>
>>>> public void setController(Controller controller) {
>>>> this.controller = controller;
>>>> }
>>>>
>>>> public SocketChannel getUnderlyingChannel() {
>>>> return socketChannel;
>>>> }
>>>>
>>>> public CallbackHandler getCallbackHandler() {
>>>> return callbackHandler;
>>>> }
>>>>
>>>> public void setCallbackHandler(CallbackHandler callbackHandler) {
>>>> this.callbackHandler = callbackHandler;
>>>> }
>>>>
>>>> public TCPSelectorHandler getSelectorHandler() {
>>>> return selectorHandler;
>>>> }
>>>> }
>>>>
>>>>
>>>> ------------------------------------------------------------------------
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>