dev@grizzly.java.net

Re: About recycling the server channel in XXXSelectorHandler

From: Bongjae Chang <carryel_at_korea.com>
Date: Fri, 19 Jun 2009 10:32:42 +0900

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?

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