users@grizzly.java.net

Re: Tunnel implementation

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Tue, 05 Jun 2007 11:04:44 +0200

>>
>> 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
>