users@grizzly.java.net

Re: Tunnel implementation

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Tue, 05 Jun 2007 23:48:58 +0200

Hi,


Kshitiz Saxena wrote:
> Hi Alexey,
>
> I have latest ReadFilter.java from grizzly trunk. I still have this
> issue.
Should be fixed now. Please update one more time.

Thanks!

Alexey.
>
> 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
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>