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.vmpipe;
    21
    22  import java.io.IOException;
    23  import java.net.SocketAddress;
    24  import java.util.HashMap;
    25  import java.util.HashSet;
    26  import java.util.List;
    27  import java.util.Map;
    28  import java.util.Set;
    29  import java.util.concurrent.Executor;
    30
    31  import org.apache.mina.core.future.IoFuture;
    32  import org.apache.mina.core.service.AbstractIoAcceptor;
    33  import org.apache.mina.core.service.IoHandler;
    34  import org.apache.mina.core.service.TransportMetadata;
    35  import org.apache.mina.core.session.IdleStatusChecker;
    36  import org.apache.mina.core.session.IoSession;
    37
    38  /**
    39   * Binds the specified {@link IoHandler} to the specified
    40   * {@link VmPipeAddress}.
    41   *
    42   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    43   */
    44  public final class VmPipeAcceptor extends AbstractIoAcceptor {
    45
    46      // object used for checking session idle
    47      private IdleStatusChecker idleChecker;
    48
    49      static final Map<VmPipeAddress, VmPipe> boundHandlers = new HashMap<VmPipeAddress, VmPipe>();
    50
    51      /**
    52       * Creates a new instance.
    53       */
    54      public VmPipeAcceptor() {
    55          this(null);
    56      }
    57
    58      /**
    59       * Creates a new instance.
    60       */
    61      public VmPipeAcceptor(Executor executor) {
    62          super(new DefaultVmPipeSessionConfig(), executor);
    63          idleChecker = new IdleStatusChecker();
    64          // we schedule the idle status checking task in this service exceutor
    65          // it will be woke up every seconds
    66          executeWorker(idleChecker.getNotifyingTask(), "idleStatusChecker");
    67      }
    68
    69      public TransportMetadata getTransportMetadata() {
    70          return VmPipeSession.METADATA;
    71      }
    72
    73      @Override
    74      public VmPipeSessionConfig getSessionConfig() {
    75          return (VmPipeSessionConfig) super.getSessionConfig();
    76      }
    77
    78      @Override
    79      public VmPipeAddress getLocalAddress() {
    80          return (VmPipeAddress) super.getLocalAddress();
    81      }
    82
    83      @Override
    84      public VmPipeAddress getDefaultLocalAddress() {
    85          return (VmPipeAddress) super.getDefaultLocalAddress();
    86      }
    87
    88      // This method is overriden to work around a problem with
    89      // bean property access mechanism.
    90
    91      public void setDefaultLocalAddress(VmPipeAddress localAddress) {
    92          super.setDefaultLocalAddress(localAddress);
    93      }
    94
    95      @Override
    96      protected void dispose0() throws Exception {
    97          // stop the idle checking task
    98          idleChecker.getNotifyingTask().cancel();
    99          unbind();
    100     }
    101
    102     @Override
    103     protected Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws IOException {
    104         Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
    105
    106         synchronized (boundHandlers) {
    107             for (SocketAddress a : localAddresses) {
    108                 VmPipeAddress localAddress = (VmPipeAddress) a;
    109                 if (localAddress == null || localAddress.getPort() == 0) {
    110                     localAddress = null;
    111                     for (int i = 10000; i < Integer.MAX_VALUE; i++) {
    112                         VmPipeAddress newLocalAddress = new VmPipeAddress(i);
    113                         if (!boundHandlers.containsKey(newLocalAddress) && !newLocalAddresses.contains(newLocalAddress)) {
    114                             localAddress = newLocalAddress;
    115                             break;
    116                         }
    117                     }
    118
    119                     if (localAddress == null) {
    120                         throw new IOException("No port available.");
    121                     }
    122                 } else if (localAddress.getPort() < 0) {
    123                     throw new IOException("Bind port number must be 0 or above.");
    124                 } else if (boundHandlers.containsKey(localAddress)) {
    125                     throw new IOException("Address already bound: " + localAddress);
    126                 }
    127
    128                 newLocalAddresses.add(localAddress);
    129             }
    130
    131             for (SocketAddress a : newLocalAddresses) {
    132                 VmPipeAddress localAddress = (VmPipeAddress) a;
    133                 if (!boundHandlers.containsKey(localAddress)) {
    134                     boundHandlers.put(localAddress, new VmPipe(this, localAddress, getHandler(), getListeners()));
    135                 } else {
    136                     for (SocketAddress a2 : newLocalAddresses) {
    137                         boundHandlers.remove(a2);
    138                     }
    139                     throw new IOException("Duplicate local address: " + a);
    140                 }
    141             }
    142         }
    143
    144         return newLocalAddresses;
    145     }
    146
    147     @Override
    148     protected void unbind0(List<? extends SocketAddress> localAddresses) {
    149         synchronized (boundHandlers) {
    150             for (SocketAddress a : localAddresses) {
    151                 boundHandlers.remove(a);
    152             }
    153         }
    154     }
    155
    156     public IoSession newSession(SocketAddress remoteAddress, SocketAddress localAddress) {
    157         throw new UnsupportedOperationException();
    158     }
    159
    160     void doFinishSessionInitialization(IoSession session, IoFuture future) {
    161         initSession(session, future, null);
    162     }
    163 }