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