dev@grizzly.java.net

Re: About recycling the server channel in XXXSelectorHandler

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Fri, 19 Jun 2009 12:51:24 -0400

salut,

Bongjae Chang wrote:
> Hi Jeanfrancois,
>
> Thank you for reviewing this.
>
> I will apply your comments and create the issue.
>
> And I would like to explain something about your some comment. Please see the following inline.
>
>>> 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)
> ...
>>> -
>>> - /**
>>> - * Register a CallBackHandler to this Selector.
>>> - *
>>> - * @param remoteAddress remote address to connect
>>> - * @param localAddress local address to bin
>>> - * @param callbackHandler {_at_link CallbackHandler}
>>> - * @throws java.io.IOException
>>> - */
>>> @Override
>>> - protected void connect(SocketAddress remoteAddress, SocketAddress localAddress,
>>> - CallbackHandler callbackHandler) throws IOException {
>> Do we need to remove the above?
>
> UDPSelectorHandler overrided TCPSelectorHandler#connect(), but UDPSelectorHandler had the same logic except for using DatagramChannel.
>
> Here was the same logic:
>
>>> - SelectionKeyOP.ConnectSelectionKeyOP keyOP = new ConnectSelectionKeyOP();
>>> -
>>> - keyOP.setOp(SelectionKey.OP_CONNECT);
>>> - keyOP.setChannel(newDatagramChannel);
>>> - keyOP.setRemoteAddress(remoteAddress);
>>> - keyOP.setCallbackHandler(callbackHandler);
>>> - opToRegister.offer(keyOP);
>>> - selector.wakeup(); -----------(*)
>
> As you know, above logic is very similar to TCPSelectorHandler#connect(). But in TCPSelectorHandler#connect(), "private wakeUp()" method is called instead of selector.wakeup() (*).
>
> Here is TCPSelectorHandler#wakeUp():
> --
> private void wakeUp() {
> try {
> selector.wakeup();
> } catch( NullpointerException ne) {
> // Swallow as this is a JDK issue.
> }
> }
> --
>
> I think that it seems JDK's bug. This workaround had been applied to only TCPSelectorHandler. So I intended to share the common logic between TCP and UDP in order to prevent a mistake like above.
>
> So I separated the logic of opening an appropriate channel from common logic for SelectableChannel.
>
> But if you think that UDPSelectorHandler should have a separate or independent connect() method, I will be able to revert it such as the following.
>
> In UDPSelectorHandler.java
> ---
> /**
> ...
> */
> protected void connect(...) {
> // original UDPSelectorHandler#connect() code
> ...
> }
> ---
> or
> ---
> /**
> ...
> */
> protected void connect(...) {
> super.connect(...);
> }
> --
>
> What do you think?

As usual, good catch! Agree with your change.

Thanks!

-- Jeanfrancois



>
> --
> Bongjae Chang
>
>
> ----- Original Message -----
> From: "Jeanfrancois Arcand" <Jeanfrancois.Arcand_at_Sun.COM>
> To: <dev_at_grizzly.dev.java.net>
> Sent: Friday, June 19, 2009 12:08 AM
> Subject: Re: About recycling the server channel in XXXSelectorHandler
>
>
>> Salut,
>>
>> Bongjae Chang wrote:
>>> Hi,
>>>
>>> I created new SelectorHandler like ReusableTCP|UDPSelectorHandler and SelectorHanderFactory#createSelectorHandler( Protocol, boolean reusable ).
>>>
>>> And TCP|UDPSelectorHandler was modified a little bit. Of course, original logic of TCP|UDPSelectorHandler was preserved.
>>>
>>> Could you review this again?
>> see inline...
>>
>>
>>> Thanks.
>>> --
>>> Bongjae Chang
>>>
>>> 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
>> [minor] Remove Date, add small documentation
>>
>>
>>> + */
>>> +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
>> [minor] Remove Date, add small documentation. Explain what it does :-)
>>
>>
>>> + */
>>> +public class ReusableTCPSelectorHandler extends TCPSelectorHandler {
>>> +
>>> + private final ConcurrentHashMap<SocketAddress, SocketChannel> acceptedSocketChannelMap =
>>> + new ConcurrentHashMap<SocketAddress, SocketChannel>();
>>> + private final CopyOnWriteArrayList<SocketChannel> reusableSocketChannels =
>>> + new CopyOnWriteArrayList<SocketChannel>();
>>> +
>>> + 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;
>>> + }
>>> + }
>>> +
>>> + /**
>>> + * {_at_inheritDoc}
>>> + */
>>> + @Override
>>> + public void shutdown() {
>>> + super.shutdown();
>>> + acceptedSocketChannelMap.clear();
>>> + reusableSocketChannels.clear();
>>> + }
>>> +
>>> + /**
>>> + * {_at_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;
>>> + }
>>> +
>>> + /**
>>> + * {_at_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 {_at_link CallbackHandler}
>>> - * @throws java.io.IOException
>>> - */
>>> @Override
>>> - protected void connect(SocketAddress remoteAddress, SocketAddress localAddress,
>>> - CallbackHandler callbackHandler) throws IOException {
>> Do we need to remove the above?
>>
>>
>>> -
>>> + 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
>>> + */
>> [minor] Remove Date, add small documentation.
>>
>>> +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;
>>> + }
>>> +
>>> + /**
>>> + * {_at_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.<br>
>>> * 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;
>>> + }
>>> +
>>> /**
>>> * {_at_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 {_at_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 @@
>>> * {_at_inheritDoc}
>>> */
>>> public void resetSpinCounter(){
>>> - emptySpinCounter = 0;
>>> + emptySpinCounter = 0;
>>> }
>>>
>>> /**
>>>
>>>
>> Looks good.
>>
>> Thanks!
>>
>> -- Jeanfrancois
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>>
>>
>>
>>