users@grizzly.java.net

Re: Tunnel implementation

From: Kshitiz Saxena <Kshitiz.Saxena_at_Sun.COM>
Date: Tue, 05 Jun 2007 23:53:52 +0530

Hi Alexey,

I have latest ReadFilter.java from grizzly trunk. I still have this issue.

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
>