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