users@grizzly.java.net

Re: [Latest code] Tunnel implementation

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Wed, 06 Jun 2007 12:23:10 -0400

Hi,

Kshitiz Saxena wrote:
> Hi,
>
> The latest code provided by Alexey is attached.
>
> I have one question. In HTTP Get request, content-length header may not
> be present. How do we decide in this case that we have read complete
> request?

Take a look at
modules/http/src/main/java/com/sun/grizzly/http/algorithm/StateMachineAlgorithm.
Mainly, you need to look for /r/n/r/n between the headers and the body
of the request.

Thanks

-- Jeanfrancois


>
> Thanks,
> Kshitiz
>
> Jeanfrancois Arcand wrote:
>> Hi,
>>
>> can someone post the latest version of the code? I would like to take
>> a look to see if I can improve the performance :-)
>>
>> Thanks
>>
>> -- Jeanfrancois
>>
>>
>> Oleksiy Stashok wrote:
>>> 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
>>>>
>>>
>>> ---------------------------------------------------------------------
>>> 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