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.net.InetSocketAddress;
23  import java.net.SocketAddress;
24  import java.nio.channels.DatagramChannel;
25  import java.nio.channels.SelectionKey;
26  import java.nio.channels.Selector;
27  import java.util.Collection;
28  import java.util.Iterator;
29  import java.util.concurrent.Executor;
30  
31  import org.apache.mina.core.buffer.IoBuffer;
32  import org.apache.mina.core.polling.AbstractPollingConnectionlessIoAcceptor;
33  import org.apache.mina.core.service.IoAcceptor;
34  import org.apache.mina.core.service.IoProcessor;
35  import org.apache.mina.core.service.TransportMetadata;
36  import org.apache.mina.transport.socket.DatagramAcceptor;
37  import org.apache.mina.transport.socket.DatagramSessionConfig;
38  import org.apache.mina.transport.socket.DefaultDatagramSessionConfig;
39  
40  /**
41   * {@link IoAcceptor} for datagram transport (UDP/IP).
42   *
43   * @author The Apache MINA Project (dev@mina.apache.org)
44   * @version $Rev: 708218 $, $Date: 2008-10-27 16:16:48 +0100 (Mon, 27 Oct 2008) $
45   * @org.apache.xbean.XBean
46   */
47  public final class NioDatagramAcceptor
48          extends AbstractPollingConnectionlessIoAcceptor<NioSession, DatagramChannel>
49          implements DatagramAcceptor {
50  
51      private volatile Selector selector;
52  
53      /**
54       * Creates a new instance.
55       */
56      public NioDatagramAcceptor() {
57          super(new DefaultDatagramSessionConfig());
58      }
59  
60      /**
61       * Creates a new instance.
62       */
63      public NioDatagramAcceptor(Executor executor) {
64          super(new DefaultDatagramSessionConfig(), executor);
65      }
66      
67      @Override
68      protected void init() throws Exception {
69          this.selector = Selector.open();
70      }
71  
72      @Override
73      protected void destroy() throws Exception {
74          if (selector != null) {
75              selector.close();
76          }
77      }
78  
79      public TransportMetadata getTransportMetadata() {
80          return NioDatagramSession.METADATA;
81      }
82  
83      @Override
84      public DatagramSessionConfig getSessionConfig() {
85          return (DatagramSessionConfig) super.getSessionConfig();
86      }
87  
88      @Override
89      public InetSocketAddress getLocalAddress() {
90          return (InetSocketAddress) super.getLocalAddress();
91      }
92      
93      @Override
94      public InetSocketAddress getDefaultLocalAddress() {
95          return (InetSocketAddress) super.getDefaultLocalAddress();
96      }
97  
98      public void setDefaultLocalAddress(InetSocketAddress localAddress) {
99          setDefaultLocalAddress((SocketAddress) localAddress);
100     }
101 
102     @Override
103     protected DatagramChannel open(SocketAddress localAddress) throws Exception {
104         final DatagramChannel c = DatagramChannel.open();
105         boolean success = false;
106         try {
107             new NioDatagramSessionConfig(c).setAll(getSessionConfig());
108             c.configureBlocking(false);
109             c.socket().bind(localAddress);
110             c.register(selector, SelectionKey.OP_READ);
111             success = true;
112         } finally {
113             if (!success) {
114                 close(c);
115             }
116         }
117 
118         return c;
119     }
120 
121     @Override
122     protected boolean isReadable(DatagramChannel handle) {
123         SelectionKey key = handle.keyFor(selector);
124 
125         if ((key == null) || (!key.isValid())) {
126             return false;
127         }
128 
129         return key.isReadable();
130     }
131 
132     @Override
133     protected boolean isWritable(DatagramChannel handle) {
134         SelectionKey key = handle.keyFor(selector);
135 
136         if ((key == null) || (!key.isValid())) {
137             return false;
138         }
139 
140         return key.isWritable();
141     }
142 
143     @Override
144     protected SocketAddress localAddress(DatagramChannel handle)
145             throws Exception {
146         return handle.socket().getLocalSocketAddress();
147     }
148 
149     @Override
150     protected NioSession newSession(
151             IoProcessor<NioSession> processor, DatagramChannel handle,
152             SocketAddress remoteAddress) {
153         SelectionKey key = handle.keyFor(selector);
154         
155         if ((key == null) || (!key.isValid())) {
156             return null;
157         }
158         
159         NioDatagramSession newSession = new NioDatagramSession(
160                 this, handle, processor, remoteAddress);
161         newSession.setSelectionKey(key);
162         
163         return newSession;
164     }
165 
166     @Override
167     protected SocketAddress receive(DatagramChannel handle, IoBuffer buffer)
168             throws Exception {
169         return handle.receive(buffer.buf());
170     }
171 
172     @Override
173     protected int select() throws Exception {
174         return selector.select();
175     }
176 
177     @Override
178     protected int select(int timeout) throws Exception {
179         return selector.select(timeout);
180     }
181 
182     @Override
183     protected Iterator<DatagramChannel> selectedHandles() {
184         return new DatagramChannelIterator(selector.selectedKeys());
185     }
186 
187     @Override
188     protected int send(NioSession session, IoBuffer buffer,
189             SocketAddress remoteAddress) throws Exception {
190         return ((DatagramChannel) session.getChannel()).send(
191                 buffer.buf(), remoteAddress);
192     }
193 
194     @Override
195     protected void setInterestedInWrite(NioSession session, boolean interested)
196             throws Exception {
197         SelectionKey key = session.getSelectionKey();
198         if (key == null) {
199             return;
200         }
201         
202         if (interested) {
203             key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
204         } else {
205             key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
206         }
207     }
208 
209     @Override
210     protected void close(DatagramChannel handle) throws Exception {
211         SelectionKey key = handle.keyFor(selector);
212 
213         if (key != null) {
214             key.cancel();
215         }
216         
217         handle.disconnect();
218         handle.close();
219     }
220 
221     @Override
222     protected void wakeup() {
223         selector.wakeup();
224     }
225     
226     private static class DatagramChannelIterator implements Iterator<DatagramChannel> {
227         
228         private final Iterator<SelectionKey> i;
229         
230         private DatagramChannelIterator(Collection<SelectionKey> keys) {
231             this.i = keys.iterator();
232         }
233         
234         public boolean hasNext() {
235             return i.hasNext();
236         }
237 
238         public DatagramChannel next() {
239             return (DatagramChannel) i.next().channel();
240         }
241 
242         public void remove() {
243             i.remove();
244         }
245         
246     }
247 }