Index: test/java/com/sun/grizzly/ReusableSelectorHandlerTest.java =================================================================== --- test/java/com/sun/grizzly/ReusableSelectorHandlerTest.java (revision 0) +++ test/java/com/sun/grizzly/ReusableSelectorHandlerTest.java (revision 0) @@ -0,0 +1,181 @@ +/* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, 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/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + * + */ + +package com.sun.grizzly; + +import junit.framework.TestCase; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.net.Socket; +import java.net.BindException; +import java.net.SocketAddress; +import java.io.IOException; +import java.util.logging.Level; + +import com.sun.grizzly.utils.ControllerUtils; + +/** + * @author Bongjae Chang + * @date 2009. 6. 15 + */ +public class ReusableSelectorHandlerTest extends TestCase { + + private static final int PORT = 17521; + private static final int SLEEP_TIME = 3000; // ms + + private final InetAddress localInetAddress; + private final InetSocketAddress localInetSocketAddress; + + public ReusableSelectorHandlerTest() throws UnknownHostException { + localInetAddress = InetAddress.getLocalHost(); + localInetSocketAddress = new InetSocketAddress( localInetAddress, PORT ); + } + + public void testSimpleTCPConnect() throws IOException { + final Controller controller = new Controller(); + SelectorHandler selectorHandler = SelectorHandlerFactory.createSelectorHandler( Controller.Protocol.TCP, true ); + ( (TCPSelectorHandler)selectorHandler ).setPort( PORT ); + ( (TCPSelectorHandler)selectorHandler ).setInet( localInetAddress ); + ( (TCPSelectorHandler)selectorHandler ).setReuseAddress( false ); + controller.addSelectorHandler( selectorHandler ); + + Socket clientSocket = null; + try { + ControllerUtils.startController( controller ); + + boolean result = false; + Controller.logger().log( Level.INFO, "Try to get a connector handler with the local address which already has been bound." ); + try { + tryToConnect( controller, Controller.Protocol.TCP, null, localInetSocketAddress ); + } catch( IOException ie ) { + if( ie instanceof BindException ) { + result = true; + Controller.logger().log( Level.INFO, "Got the expected BindException." ); + assertTrue( "Got the expected BindException.", true ); + } else { + Controller.logger().log( Level.INFO, "Got the unexpected error.", ie ); + assertTrue( "Got the unexpected error.", false ); + } + } + if( !result ) + assertTrue( "The BindException was expected.", false ); + + Controller.logger().log( Level.INFO, "Try to connect the local server." ); + clientSocket = new Socket( localInetAddress, PORT ); + Controller.logger().log( Level.INFO, "Wait for " + SLEEP_TIME + "(ms)" ); + try { + Thread.sleep( SLEEP_TIME ); + } catch( InterruptedException e ) { + } + + Controller.logger().log( Level.INFO, "Try to get a connector handler with the local address which already has been bound again." ); + try { + tryToConnect( controller, Controller.Protocol.TCP, clientSocket.getLocalSocketAddress(), localInetSocketAddress ); + } catch( IOException ie ) { + Controller.logger().log( Level.INFO, "Got the unexpected error.", ie ); + assertTrue( "Got the unexpected error.", false ); + throw ie; + } + } finally { + if( clientSocket != null ) { + try { + clientSocket.shutdownInput(); + } catch( IOException e ) { + } + try { + clientSocket.shutdownOutput(); + } catch( IOException e ) { + } + try { + clientSocket.close(); + } catch( IOException e ) { + } + } + controller.stop(); + } + } + + public void testSimpleUDPConnect() throws IOException { + final Controller controller = new Controller(); + SelectorHandler selectorHandler = SelectorHandlerFactory.createSelectorHandler( Controller.Protocol.UDP, true ); + ( (UDPSelectorHandler)selectorHandler ).setPort( PORT ); + ( (UDPSelectorHandler)selectorHandler ).setInet( localInetAddress ); + ( (UDPSelectorHandler)selectorHandler ).setReuseAddress( false ); + controller.addSelectorHandler( selectorHandler ); + + try { + ControllerUtils.startController( controller ); + + Controller.logger().log( Level.INFO, "Try to get a connector handler with the local address which already has been bound." ); + try { + tryToConnect( controller, Controller.Protocol.UDP, localInetSocketAddress, localInetSocketAddress ); + } catch( IOException ie ) { + Controller.logger().log( Level.INFO, "Got the unexpected error.", ie ); + assertTrue( "Got the unexpected error.", false ); + throw ie; + } + } finally { + controller.stop(); + } + } + + private void tryToConnect( Controller controller, Controller.Protocol protocol, SocketAddress remote, SocketAddress local ) throws IOException { + ConnectorHandler connectorHandler = null; + try { + connectorHandler = controller.acquireConnectorHandler( protocol ); + connectorHandler.connect( remote, local ); + } finally { + if( connectorHandler != null ) { + try { + connectorHandler.close(); + } catch( IOException e ) { + e.printStackTrace(); + } + controller.releaseConnectorHandler( connectorHandler ); + } + } + } + + public static void main( String[] args ) throws IOException { + ReusableSelectorHandlerTest test = new ReusableSelectorHandlerTest(); + test.testSimpleTCPConnect(); + test.testSimpleUDPConnect(); + } +} Index: main/java/com/sun/grizzly/SelectorHandlerFactory.java =================================================================== --- main/java/com/sun/grizzly/SelectorHandlerFactory.java (revision 0) +++ main/java/com/sun/grizzly/SelectorHandlerFactory.java (revision 0) @@ -0,0 +1,70 @@ +/* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, 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/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + * + */ + +package com.sun.grizzly; + +/** + * @author Bongjae Chang + * @date 2009. 6. 18 + */ +public class SelectorHandlerFactory { + + public static SelectorHandler createSelectorHandler( Controller.Protocol protocol, boolean resuable ) { + SelectorHandler selectorHandler = null; + if( Controller.Protocol.TCP == protocol ) { + if( resuable ) + selectorHandler = new ReusableTCPSelectorHandler(); + else + selectorHandler = new TCPSelectorHandler(); + } else if ( Controller.Protocol.UDP == protocol ) { + if( resuable ) + selectorHandler = new ReusableUDPSelectorHandler(); + else + selectorHandler = new UDPSelectorHandler(); + } else if( Controller.Protocol.TLS == protocol ) { + if( resuable ) + selectorHandler = new SSLSelectorHandler(); // not supported yet + else + selectorHandler = new SSLSelectorHandler(); + } else { + // default + selectorHandler = new TCPSelectorHandler(); + } + return selectorHandler; + } +} Index: main/java/com/sun/grizzly/ReusableTCPSelectorHandler.java =================================================================== --- main/java/com/sun/grizzly/ReusableTCPSelectorHandler.java (revision 0) +++ main/java/com/sun/grizzly/ReusableTCPSelectorHandler.java (revision 0) @@ -0,0 +1,140 @@ +/* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, 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/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + * + */ + +package com.sun.grizzly; + +import java.net.SocketAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.channels.SocketChannel; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.ServerSocketChannel; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.io.IOException; + +/** + * @author Bongjae Chang + * @date 2009. 6. 18 + */ +public class ReusableTCPSelectorHandler extends TCPSelectorHandler { + + private final ConcurrentHashMap acceptedSocketChannelMap = + new ConcurrentHashMap(); + private final CopyOnWriteArrayList reusableSocketChannels = + new CopyOnWriteArrayList(); + + public ReusableTCPSelectorHandler() { + super( Role.CLIENT_SERVER ); + } + + @Override + protected SelectableChannel getSelectableChannel( SocketAddress remoteAddress, SocketAddress localAddress ) throws IOException { + SelectableChannel selectableChannel = null; + if( localAddress != null ) { + if( inet != null && localAddress instanceof InetSocketAddress ) { + InetSocketAddress inetSocketAddress = (InetSocketAddress)localAddress; + if( inet.equals( inetSocketAddress.getAddress() ) ) + selectableChannel = getUsedSelectableChannel( remoteAddress ); + } + } else { + selectableChannel = getUsedSelectableChannel( remoteAddress ); + } + if( selectableChannel == null ) + selectableChannel = super.getSelectableChannel( remoteAddress, localAddress ); + return selectableChannel; + } + + private SelectableChannel getUsedSelectableChannel( SocketAddress remoteAddress ) { + if( remoteAddress != null ) { + SocketChannel acceptedSocketChannel = acceptedSocketChannelMap.get( remoteAddress ); + if( acceptedSocketChannel != null ) + reusableSocketChannels.add( acceptedSocketChannel ); + return acceptedSocketChannel; + } else { + return null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void shutdown() { + super.shutdown(); + acceptedSocketChannelMap.clear(); + reusableSocketChannels.clear(); + } + + /** + * {@inheritDoc} + */ + @Override + public SelectableChannel acceptWithoutRegistration( SelectionKey key ) throws IOException { + SocketChannel acceptedSocketChannel = ( (ServerSocketChannel)key.channel() ).accept(); + if( acceptedSocketChannel != null ) { + SocketAddress remoteSocketAddress = null; + Socket acceptedSocket = acceptedSocketChannel.socket(); + if( acceptedSocket != null ) + remoteSocketAddress = acceptedSocket.getRemoteSocketAddress(); + if( remoteSocketAddress != null ) + acceptedSocketChannelMap.put( remoteSocketAddress, acceptedSocketChannel ); + } + return acceptedSocketChannel; + } + + /** + * {@inheritDoc} + */ + @Override + public void closeChannel( SelectableChannel channel ) { + if( channel instanceof SocketChannel ) { + SocketChannel socketChannel = (SocketChannel)channel; + if( reusableSocketChannels.remove( socketChannel ) ) + return; + Socket socket = socketChannel.socket(); + SocketAddress remoteSocketAddress = null; + if( socket != null ) + remoteSocketAddress = socket.getRemoteSocketAddress(); + if( remoteSocketAddress != null ) + acceptedSocketChannelMap.remove( remoteSocketAddress ); + } + super.closeChannel( channel ); + } +} Index: main/java/com/sun/grizzly/UDPSelectorHandler.java =================================================================== --- main/java/com/sun/grizzly/UDPSelectorHandler.java (revision 3351) +++ main/java/com/sun/grizzly/UDPSelectorHandler.java (working copy) @@ -38,11 +38,9 @@ package com.sun.grizzly; -import com.sun.grizzly.SelectionKeyOP.ConnectSelectionKeyOP; import com.sun.grizzly.async.UDPAsyncQueueReader; import com.sun.grizzly.async.UDPAsyncQueueWriter; import com.sun.grizzly.util.Copyable; -import com.sun.grizzly.util.State; import java.io.IOException; import java.net.BindException; import java.net.DatagramSocket; @@ -138,9 +136,9 @@ ConcurrentQueueDelegateCIH( getConnectorInstanceHandlerDelegate()); - datagramChannel = DatagramChannel.open(); selector = Selector.open(); if (role != Role.CLIENT){ + datagramChannel = DatagramChannel.open(); datagramSocket = datagramChannel.socket(); datagramSocket.setReuseAddress(reuseAddress); if (inet == null) @@ -159,35 +157,14 @@ } } - - /** - * Register a CallBackHandler to this Selector. - * - * @param remoteAddress remote address to connect - * @param localAddress local address to bin - * @param callbackHandler {@link CallbackHandler} - * @throws java.io.IOException - */ @Override - protected void connect(SocketAddress remoteAddress, SocketAddress localAddress, - CallbackHandler callbackHandler) throws IOException { - + protected SelectableChannel getSelectableChannel( SocketAddress remoteAddress, SocketAddress localAddress ) throws IOException { DatagramChannel newDatagramChannel = DatagramChannel.open(); - newDatagramChannel.socket().setReuseAddress(reuseAddress); - if (localAddress != null) { - newDatagramChannel.socket().bind(localAddress); - } - - newDatagramChannel.configureBlocking(false); - - SelectionKeyOP.ConnectSelectionKeyOP keyOP = new ConnectSelectionKeyOP(); - - keyOP.setOp(SelectionKey.OP_CONNECT); - keyOP.setChannel(newDatagramChannel); - keyOP.setRemoteAddress(remoteAddress); - keyOP.setCallbackHandler(callbackHandler); - opToRegister.offer(keyOP); - selector.wakeup(); + newDatagramChannel.socket().setReuseAddress( reuseAddress ); + if( localAddress != null ) + newDatagramChannel.socket().bind( localAddress ); + newDatagramChannel.configureBlocking( false ); + return newDatagramChannel; } /** @@ -196,19 +173,19 @@ @Override protected void onConnectOp(Context ctx, SelectionKeyOP.ConnectSelectionKeyOP selectionKeyOp) throws IOException { - DatagramChannel newDatagramChannel = (DatagramChannel) selectionKeyOp.getChannel(); + DatagramChannel datagramChannel = (DatagramChannel) selectionKeyOp.getChannel(); SocketAddress remoteAddress = selectionKeyOp.getRemoteAddress(); CallbackHandler callbackHandler = selectionKeyOp.getCallbackHandler(); CallbackHandlerSelectionKeyAttachment attachment = new CallbackHandlerSelectionKeyAttachment(callbackHandler); - SelectionKey key = newDatagramChannel.register(selector, + SelectionKey key = datagramChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE, attachment); attachment.associateKey(key); try { - newDatagramChannel.connect(remoteAddress); + datagramChannel.connect(remoteAddress); } catch(Exception e) { if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "Exception occured when tried to connect datagram channel", e); @@ -224,44 +201,26 @@ */ @Override public void shutdown(){ - // If shutdown was called for this SelectorHandler - if (isShutDown.getAndSet(true)) return; - - stateHolder.setState(State.STOPPED); - + super.shutdown(); try { - if ( datagramSocket != null ) + if ( datagramSocket != null ) { datagramSocket.close(); + datagramSocket = null; + } } catch (Throwable ex){ Controller.logger().log(Level.SEVERE, "closeSocketException",ex); } try{ - if ( datagramChannel != null) + if ( datagramChannel != null) { datagramChannel.close(); + datagramChannel = null; + } } catch (Throwable ex){ Controller.logger().log(Level.SEVERE, "closeSocketException",ex); } - - try{ - if ( selector != null) - selector.close(); - } catch (Throwable ex){ - Controller.logger().log(Level.SEVERE, - "closeSocketException",ex); - } - - if (asyncQueueReader != null) { - asyncQueueReader.close(); - asyncQueueReader = null; - } - - if (asyncQueueWriter != null) { - asyncQueueWriter.close(); - asyncQueueWriter = null; - } } Index: main/java/com/sun/grizzly/ReusableUDPSelectorHandler.java =================================================================== --- main/java/com/sun/grizzly/ReusableUDPSelectorHandler.java (revision 0) +++ main/java/com/sun/grizzly/ReusableUDPSelectorHandler.java (revision 0) @@ -0,0 +1,89 @@ +/* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, 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/CDDL+GPL.html + * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. + * Sun designates this particular file as subject to the "Classpath" exception + * as provided by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the License + * Header, with the fields enclosed by brackets [] replaced by your own + * identifying information: "Portions Copyrighted [year] + * [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + * + */ + +package com.sun.grizzly; + +import java.nio.channels.SelectableChannel; +import java.io.IOException; +import java.net.SocketAddress; +import java.net.InetSocketAddress; + +/** + * @author Bongjae Chang + * @date 2009. 6. 18 + */ +public class ReusableUDPSelectorHandler extends UDPSelectorHandler { + + public ReusableUDPSelectorHandler() { + super( Role.CLIENT_SERVER ); + } + + @Override + protected SelectableChannel getSelectableChannel( SocketAddress remoteAddress, SocketAddress localAddress ) throws IOException { + SelectableChannel selectableChannel = null; + if( localAddress != null ) { + if( inet != null && localAddress instanceof InetSocketAddress ) { + InetSocketAddress inetSocketAddress = (InetSocketAddress)localAddress; + if( inet.equals( inetSocketAddress.getAddress() ) ) + selectableChannel = getUsedSelectableChannel(); + } + } else { + selectableChannel = getUsedSelectableChannel(); + } + if( selectableChannel == null ) + selectableChannel = super.getSelectableChannel( remoteAddress, localAddress ); + return selectableChannel; + } + + private SelectableChannel getUsedSelectableChannel() { + if( role != Role.CLIENT && datagramChannel != null && datagramSocket != null ) + return datagramChannel; + else + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public void closeChannel( SelectableChannel channel ) { + if( datagramChannel == channel ) + return; + super.closeChannel( channel ); + } +} Index: main/java/com/sun/grizzly/TCPSelectorHandler.java =================================================================== --- main/java/com/sun/grizzly/TCPSelectorHandler.java (revision 3351) +++ main/java/com/sun/grizzly/TCPSelectorHandler.java (working copy) @@ -274,7 +274,7 @@ private long lastSpinTimestamp; private int emptySpinCounter; - + public TCPSelectorHandler(){ this(Role.CLIENT_SERVER); } @@ -397,15 +397,13 @@ serverSocketChannel.configureBlocking(false); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); + + serverSocket.setSoTimeout(serverTimeout); } ctx.getController().notifyReady(); } catch (SocketException ex){ throw new BindException(ex.getMessage() + ": " + port + "=" + this); } - - if (role != Role.CLIENT){ - serverSocket.setSoTimeout(serverTimeout); - } } /** @@ -531,7 +529,7 @@ }else{ ((Runnable)obj).run(); } - }catch(Throwable t){ + }catch(Throwable t){ logger.log(Level.FINEST, "doExecutePendiongIO failed.", t); } } @@ -567,7 +565,7 @@ * Register a SelectionKey to this Selector.
* Storing each interest type in different queues removes the need of wrapper (SelectionKeyOP) * while lowering thread contention due to the load is spread out on different queues. - * + * * @param key * @param ops */ @@ -595,7 +593,7 @@ opToRegister.offer(new SelectionKeyOP(null,ops,channel)); wakeUp(); } - + /** * Workaround for NIO issue 6524172 */ @@ -617,25 +615,25 @@ */ protected void connect(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler) throws IOException { - - SocketChannel socketChannel = SocketChannel.open(); - socketChannel.socket().setReuseAddress(reuseAddress); - if (localAddress != null) { - socketChannel.socket().bind(localAddress); - } - - socketChannel.configureBlocking(false); - + SelectableChannel selectableChannel = getSelectableChannel( remoteAddress, localAddress ); SelectionKeyOP.ConnectSelectionKeyOP keyOP = new ConnectSelectionKeyOP(); - keyOP.setOp(SelectionKey.OP_CONNECT); - keyOP.setChannel(socketChannel); + keyOP.setChannel(selectableChannel); keyOP.setRemoteAddress(remoteAddress); keyOP.setCallbackHandler(callbackHandler); opToRegister.offer(keyOP); wakeUp(); } + protected SelectableChannel getSelectableChannel( SocketAddress remoteAddress, SocketAddress localAddress ) throws IOException { + SocketChannel newSocketChannel = SocketChannel.open(); + newSocketChannel.socket().setReuseAddress( reuseAddress ); + if( localAddress != null ) + newSocketChannel.socket().bind( localAddress ); + newSocketChannel.configureBlocking( false ); + return newSocketChannel; + } + /** * {@inheritDoc} */ @@ -691,16 +689,20 @@ } try{ - if (serverSocket != null) + if (serverSocket != null) { serverSocket.close(); + serverSocket = null; + } } catch (Throwable ex){ Controller.logger().log(Level.SEVERE, "serverSocket.close",ex); } try{ - if (serverSocketChannel != null) + if (serverSocketChannel != null) { serverSocketChannel.close(); + serverSocketChannel = null; + } } catch (Throwable ex){ Controller.logger().log(Level.SEVERE, "serverSocketChannel.close",ex); @@ -845,7 +847,7 @@ // Added because of incompatibility with Grizzly 1.6.0 context.setSelectorHandler(this); - CallbackHandlerContextTask task = + CallbackHandlerContextTask task = context.getCallbackHandlerContextTask(callbackHandler); boolean isRunInSeparateThread = true; @@ -1268,14 +1270,14 @@ * @return {@link Context} */ protected NIOContext pollContext(final Context serverContext, - final SelectionKey key, final Context.OpType opType) { + final SelectionKey key, final Context.OpType opType) { Controller c = serverContext.getController(); ProtocolChain protocolChain = instanceHandler != null ? instanceHandler.poll() : c.getProtocolChainInstanceHandler().poll(); final NIOContext context = (NIOContext)c.pollContext(); - c.configureContext(key, opType, context, this); + c.configureContext(key, opType, context, this); context.setProtocolChain(protocolChain); return context; } @@ -1379,7 +1381,7 @@ * {@inheritDoc} */ public void resetSpinCounter(){ - emptySpinCounter = 0; + emptySpinCounter = 0; } /**