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 IoFuture dispose0() throws Exception {
97          // stop the idle checking task
98          idleChecker.getNotifyingTask().cancel();
99          unbind();
100         return null;
101     }
102 
103     @Override
104     protected Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws IOException {
105         Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();
106 
107         synchronized (boundHandlers) {
108             for (SocketAddress a: localAddresses) {
109                 VmPipeAddress localAddress = (VmPipeAddress) a;
110                 if (localAddress == null || localAddress.getPort() == 0) {
111                     localAddress = null;
112                     for (int i = 10000; i < Integer.MAX_VALUE; i++) {
113                         VmPipeAddress newLocalAddress = new VmPipeAddress(i);
114                         if (!boundHandlers.containsKey(newLocalAddress) &&
115                             !newLocalAddresses.contains(newLocalAddress)) {
116                             localAddress = newLocalAddress;
117                             break;
118                         }
119                     }
120     
121                     if (localAddress == null) {
122                         throw new IOException("No port available.");
123                     }
124                 } else if (localAddress.getPort() < 0) {
125                     throw new IOException("Bind port number must be 0 or above.");
126                 } else if (boundHandlers.containsKey(localAddress)) {
127                     throw new IOException("Address already bound: " + localAddress);
128                 }
129                 
130                 newLocalAddresses.add(localAddress);
131             }
132 
133             for (SocketAddress a: newLocalAddresses) {
134                 VmPipeAddress localAddress = (VmPipeAddress) a;
135                 if (!boundHandlers.containsKey(localAddress)) {
136                     boundHandlers.put(localAddress, new VmPipe(this, localAddress,
137                             getHandler(), getListeners()));
138                 } else {
139                     for (SocketAddress a2: newLocalAddresses) {
140                         boundHandlers.remove(a2);
141                     }
142                     throw new IOException("Duplicate local address: " + a);
143                 }
144             }
145         }
146 
147         return newLocalAddresses;
148     }
149 
150     @Override
151     protected void unbind0(List<? extends SocketAddress> localAddresses) {
152         synchronized (boundHandlers) {
153             for (SocketAddress a: localAddresses) {
154                 boundHandlers.remove(a);
155             }
156         }
157     }
158 
159     public IoSession newSession(SocketAddress remoteAddress, SocketAddress localAddress) {
160         throw new UnsupportedOperationException();
161     }
162 
163     void doFinishSessionInitialization(IoSession session, IoFuture future) {
164         initSession(session, future, null);
165     }
166 }