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       * @param executor The executor to use
62       */
63      public VmPipeAcceptor(Executor executor) {
64          super(new DefaultVmPipeSessionConfig(), executor);
65          idleChecker = new IdleStatusChecker();
66          // we schedule the idle status checking task in this service exceutor
67          // it will be woke up every seconds
68          executeWorker(idleChecker.getNotifyingTask(), "idleStatusChecker");
69      }
70  
71      /**
72       * {@inheritDoc}
73       */
74      public TransportMetadata getTransportMetadata() {
75          return VmPipeSession.METADATA;
76      }
77  
78      /**
79       * {@inheritDoc}
80       */
81      public VmPipeSessionConfig getSessionConfig() {
82          return (VmPipeSessionConfig) sessionConfig;
83      }
84  
85      /**
86       * {@inheritDoc}
87       */
88      @Override
89      public VmPipeAddress getLocalAddress() {
90          return (VmPipeAddress) super.getLocalAddress();
91      }
92  
93      /**
94       * {@inheritDoc}
95       */
96      @Override
97      public VmPipeAddress getDefaultLocalAddress() {
98          return (VmPipeAddress) super.getDefaultLocalAddress();
99      }
100 
101     // This method is overriden to work around a problem with
102     // bean property access mechanism.
103     /**
104      * Sets the local Address for this acceptor
105      * 
106      * @param localAddress The local address to use
107      */
108     public void setDefaultLocalAddress(VmPipeAddress localAddress) {
109         super.setDefaultLocalAddress(localAddress);
110     }
111 
112     /**
113      * {@inheritDoc}
114      */
115     @Override
116     protected void dispose0() throws Exception {
117         // stop the idle checking task
118         idleChecker.getNotifyingTask().cancel();
119         unbind();
120     }
121 
122     /**
123      * {@inheritDoc}
124      */
125     @Override
126     protected Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws IOException {
127         Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
128 
129         synchronized (boundHandlers) {
130             for (SocketAddress a : localAddresses) {
131                 VmPipeAddress localAddress = (VmPipeAddress) a;
132                 if (localAddress == null || localAddress.getPort() == 0) {
133                     localAddress = null;
134                     for (int i = 10000; i < Integer.MAX_VALUE; i++) {
135                         VmPipeAddress newLocalAddress = new VmPipeAddress(i);
136                         if (!boundHandlers.containsKey(newLocalAddress) && !newLocalAddresses.contains(newLocalAddress)) {
137                             localAddress = newLocalAddress;
138                             break;
139                         }
140                     }
141 
142                     if (localAddress == null) {
143                         throw new IOException("No port available.");
144                     }
145                 } else if (localAddress.getPort() < 0) {
146                     throw new IOException("Bind port number must be 0 or above.");
147                 } else if (boundHandlers.containsKey(localAddress)) {
148                     throw new IOException("Address already bound: " + localAddress);
149                 }
150 
151                 newLocalAddresses.add(localAddress);
152             }
153 
154             for (SocketAddress a : newLocalAddresses) {
155                 VmPipeAddress localAddress = (VmPipeAddress) a;
156                 if (!boundHandlers.containsKey(localAddress)) {
157                     boundHandlers.put(localAddress, new VmPipe(this, localAddress, getHandler(), getListeners()));
158                 } else {
159                     for (SocketAddress a2 : newLocalAddresses) {
160                         boundHandlers.remove(a2);
161                     }
162                     throw new IOException("Duplicate local address: " + a);
163                 }
164             }
165         }
166 
167         return newLocalAddresses;
168     }
169 
170     @Override
171     protected void unbind0(List<? extends SocketAddress> localAddresses) {
172         synchronized (boundHandlers) {
173             for (SocketAddress a : localAddresses) {
174                 boundHandlers.remove(a);
175             }
176         }
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     public IoSession newSession(SocketAddress remoteAddress, SocketAddress localAddress) {
183         throw new UnsupportedOperationException();
184     }
185 
186     void doFinishSessionInitialization(IoSession session, IoFuture future) {
187         initSession(session, future, null);
188     }
189 }