View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.transport.socket.nio;
    21
    22  import java.io.IOException;
    23  import java.net.InetSocketAddress;
    24  import java.net.ServerSocket;
    25  import java.net.SocketAddress;
    26  import java.nio.channels.ClosedSelectorException;
    27  import java.nio.channels.SelectionKey;
    28  import java.nio.channels.Selector;
    29  import java.nio.channels.ServerSocketChannel;
    30  import java.nio.channels.SocketChannel;
    31  import java.util.Collection;
    32  import java.util.Iterator;
    33  import java.util.concurrent.Executor;
    34
    35  import org.apache.mina.core.polling.AbstractPollingIoAcceptor;
    36  import org.apache.mina.core.service.IoAcceptor;
    37  import org.apache.mina.core.service.IoProcessor;
    38  import org.apache.mina.core.service.IoService;
    39  import org.apache.mina.core.service.SimpleIoProcessorPool;
    40  import org.apache.mina.core.service.TransportMetadata;
    41  import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
    42  import org.apache.mina.transport.socket.SocketAcceptor;
    43  import org.apache.mina.transport.socket.SocketSessionConfig;
    44
    45  /**
    46   * {@link IoAcceptor} for socket transport (TCP/IP).  This class
    47   * handles incoming TCP/IP based socket connections.
    48   *
    49   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    50   */
    51  public final class NioSocketAcceptor extends AbstractPollingIoAcceptor<NioSession, ServerSocketChannel> implements
    52          SocketAcceptor {
    53
    54      private volatile Selector selector;
    55
    56      /**
    57       * Constructor for {@link NioSocketAcceptor} using default parameters (multiple thread model).
    58       */
    59      public NioSocketAcceptor() {
    60          super(new DefaultSocketSessionConfig(), NioProcessor.class);
    61          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
    62      }
    63
    64      /**
    65       * Constructor for {@link NioSocketAcceptor} using default parameters, and
    66       * given number of {@link NioProcessor} for multithreading I/O operations.
    67       *
    68       * @param processorCount the number of processor to create and place in a
    69       * {@link SimpleIoProcessorPool}
    70       */
    71      public NioSocketAcceptor(int processorCount) {
    72          super(new DefaultSocketSessionConfig(), NioProcessor.class, processorCount);
    73          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
    74      }
    75
    76      /**
    77      *  Constructor for {@link NioSocketAcceptor} with default configuration but a
    78       *  specific {@link IoProcessor}, useful for sharing the same processor over multiple
    79       *  {@link IoService} of the same type.
    80       * @param processor the processor to use for managing I/O events
    81       */
    82      public NioSocketAcceptor(IoProcessor<NioSession> processor) {
    83          super(new DefaultSocketSessionConfig(), processor);
    84          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
    85      }
    86
    87      /**
    88       *  Constructor for {@link NioSocketAcceptor} with a given {@link Executor} for handling
    89       *  connection events and a given {@link IoProcessor} for handling I/O events, useful for
    90       *  sharing the same processor and executor over multiple {@link IoService} of the same type.
    91       * @param executor the executor for connection
    92       * @param processor the processor for I/O operations
    93       */
    94      public NioSocketAcceptor(Executor executor, IoProcessor<NioSession> processor) {
    95          super(new DefaultSocketSessionConfig(), executor, processor);
    96          ((DefaultSocketSessionConfig) getSessionConfig()).init(this);
    97      }
    98
    99      /**
    100      * {@inheritDoc}
    101      */
    102     @Override
    103     protected void init() throws Exception {
    104         selector = Selector.open();
    105     }
    106
    107     /**
    108      * {@inheritDoc}
    109      */
    110     @Override
    111     protected void destroy() throws Exception {
    112         if (selector != null) {
    113             selector.close();
    114         }
    115     }
    116
    117     /**
    118      * {@inheritDoc}
    119      */
    120     public TransportMetadata getTransportMetadata() {
    121         return NioSocketSession.METADATA;
    122     }
    123
    124     /**
    125      * {@inheritDoc}
    126      */
    127     @Override
    128     public SocketSessionConfig getSessionConfig() {
    129         return (SocketSessionConfig) super.getSessionConfig();
    130     }
    131
    132     /**
    133      * {@inheritDoc}
    134      */
    135     @Override
    136     public InetSocketAddress getLocalAddress() {
    137         return (InetSocketAddress) super.getLocalAddress();
    138     }
    139
    140     /**
    141      * {@inheritDoc}
    142      */
    143     @Override
    144     public InetSocketAddress getDefaultLocalAddress() {
    145         return (InetSocketAddress) super.getDefaultLocalAddress();
    146     }
    147
    148     /**
    149      * {@inheritDoc}
    150      */
    151     public void setDefaultLocalAddress(InetSocketAddress localAddress) {
    152         setDefaultLocalAddress((SocketAddress) localAddress);
    153     }
    154
    155     /**
    156      * {@inheritDoc}
    157      */
    158     @Override
    159     protected NioSession accept(IoProcessor<NioSession> processor, ServerSocketChannel handle) throws Exception {
    160
    161         SelectionKey key = handle.keyFor(selector);
    162
    163         if ((key == null) || (!key.isValid()) || (!key.isAcceptable())) {
    164             return null;
    165         }
    166
    167         // accept the connection from the client
    168         SocketChannel ch = handle.accept();
    169
    170         if (ch == null) {
    171             return null;
    172         }
    173
    174         return new NioSocketSession(this, processor, ch);
    175     }
    176
    177     /**
    178      * {@inheritDoc}
    179      */
    180     @Override
    181     protected ServerSocketChannel open(SocketAddress localAddress) throws Exception {
    182         // Creates the listening ServerSocket
    183         ServerSocketChannel channel = ServerSocketChannel.open();
    184
    185         boolean success = false;
    186
    187         try {
    188             // This is a non blocking socket channel
    189             channel.configureBlocking(false);
    190
    191             // Configure the server socket,
    192             ServerSocket socket = channel.socket();
    193
    194             // Set the reuseAddress flag accordingly with the setting
    195             socket.setReuseAddress(isReuseAddress());
    196
    197             // and bind.
    198             socket.bind(localAddress, getBacklog());
    199
    200             // Register the channel within the selector for ACCEPT event
    201             channel.register(selector, SelectionKey.OP_ACCEPT);
    202             success = true;
    203         } finally {
    204             if (!success) {
    205                 close(channel);
    206             }
    207         }
    208         return channel;
    209     }
    210
    211     /**
    212      * {@inheritDoc}
    213      */
    214     @Override
    215     protected SocketAddress localAddress(ServerSocketChannel handle) throws Exception {
    216         return handle.socket().getLocalSocketAddress();
    217     }
    218
    219     /**
    220       * Check if we have at least one key whose corresponding channels is
    221       * ready for I/O operations.
    222       *
    223       * This method performs a blocking selection operation.
    224       * It returns only after at least one channel is selected,
    225       * this selector's wakeup method is invoked, or the current thread
    226       * is interrupted, whichever comes first.
    227       *
    228       * @return The number of keys having their ready-operation set updated
    229       * @throws IOException If an I/O error occurs
    230       * @throws ClosedSelectorException If this selector is closed
    231       */
    232     @Override
    233     protected int select() throws Exception {
    234         return selector.select();
    235     }
    236
    237     /**
    238      * {@inheritDoc}
    239      */
    240     @Override
    241     protected Iterator<ServerSocketChannel> selectedHandles() {
    242         return new ServerSocketChannelIterator(selector.selectedKeys());
    243     }
    244
    245     /**
    246      * {@inheritDoc}
    247      */
    248     @Override
    249     protected void close(ServerSocketChannel handle) throws Exception {
    250         SelectionKey key = handle.keyFor(selector);
    251
    252         if (key != null) {
    253             key.cancel();
    254         }
    255
    256         handle.close();
    257     }
    258
    259     /**
    260      * {@inheritDoc}
    261      */
    262     @Override
    263     protected void wakeup() {
    264         selector.wakeup();
    265     }
    266
    267     /**
    268      * Defines an iterator for the selected-key Set returned by the
    269      * selector.selectedKeys(). It replaces the SelectionKey operator.
    270      */
    271     private static class ServerSocketChannelIterator implements Iterator<ServerSocketChannel> {
    272         /** The selected-key iterator */
    273         private final Iterator<SelectionKey> iterator;
    274
    275         /**
    276          * Build a SocketChannel iterator which will return a SocketChannel instead of
    277          * a SelectionKey.
    278          *
    279          * @param selectedKeys The selector selected-key set
    280          */
    281         private ServerSocketChannelIterator(Collection<SelectionKey> selectedKeys) {
    282             iterator = selectedKeys.iterator();
    283         }
    284
    285         /**
    286          * Tells if there are more SockectChannel left in the iterator
    287          * @return <code>true</code> if there is at least one more
    288          * SockectChannel object to read
    289          */
    290         public boolean hasNext() {
    291             return iterator.hasNext();
    292         }
    293
    294         /**
    295          * Get the next SocketChannel in the operator we have built from
    296          * the selected-key et for this selector.
    297          *
    298          * @return The next SocketChannel in the iterator
    299          */
    300         public ServerSocketChannel next() {
    301             SelectionKey key = iterator.next();
    302
    303             if (key.isValid() && key.isAcceptable()) {
    304                 return (ServerSocketChannel) key.channel();
    305             }
    306
    307             return null;
    308         }
    309
    310         /**
    311          * Remove the current SocketChannel from the iterator
    312          */
    313         public void remove() {
    314             iterator.remove();
    315         }
    316     }
    317 }