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.common.AbstractPollingConnectionlessIoAcceptor;
32  import org.apache.mina.common.IoAcceptor;
33  import org.apache.mina.common.IoBuffer;
34  import org.apache.mina.common.IoProcessor;
35  import org.apache.mina.common.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: 600461 $, $Date: 2007-12-03 02:55:52 -0700 (Mon, 03 Dec 2007) $
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         DatagramChannel c = DatagramChannel.open();
104         boolean success = false;
105         try {
106             DatagramSessionConfig cfg = getSessionConfig();
107             c.socket().setReuseAddress(cfg.isReuseAddress());
108             c.socket().setBroadcast(cfg.isBroadcast());
109             c.socket().setReceiveBufferSize(cfg.getReceiveBufferSize());
110             c.socket().setSendBufferSize(cfg.getSendBufferSize());
111     
112             if (c.socket().getTrafficClass() != cfg.getTrafficClass()) {
113                 c.socket().setTrafficClass(cfg.getTrafficClass());
114             }
115     
116             c.configureBlocking(false);
117             c.socket().bind(localAddress);
118             c.register(selector, SelectionKey.OP_READ);
119             success = true;
120         } finally {
121             if (!success) {
122                 close(c);
123             }
124         }
125 
126         return c;
127     }
128 
129     @Override
130     protected boolean isReadable(DatagramChannel handle) {
131         SelectionKey key = handle.keyFor(selector);
132         if (key == null) {
133             return false;
134         }
135         if (!key.isValid()) {
136             return false;
137         }
138         return key.isReadable();
139     }
140 
141     @Override
142     protected boolean isWritable(DatagramChannel handle) {
143         SelectionKey key = handle.keyFor(selector);
144         if (key == null) {
145             return false;
146         }
147         if (!key.isValid()) {
148             return false;
149         }
150         return key.isWritable();
151     }
152 
153     @Override
154     protected SocketAddress localAddress(DatagramChannel handle)
155             throws Exception {
156         return handle.socket().getLocalSocketAddress();
157     }
158 
159     @Override
160     protected NioSession newSession(
161             IoProcessor<NioSession> processor, DatagramChannel handle,
162             SocketAddress remoteAddress) {
163         SelectionKey key = handle.keyFor(selector);
164         if (key == null) {
165             return null;
166         }
167         NioDatagramSession newSession = new NioDatagramSession(
168                 this, handle, processor, remoteAddress);
169         newSession.setSelectionKey(key);
170         
171         return newSession;
172     }
173 
174     @Override
175     protected SocketAddress receive(DatagramChannel handle, IoBuffer buffer)
176             throws Exception {
177         return handle.receive(buffer.buf());
178     }
179 
180     @Override
181     protected boolean select(int timeout) throws Exception {
182         return selector.select(timeout) > 0;
183     }
184 
185     @Override
186     protected Iterator<DatagramChannel> selectedHandles() {
187         return new DatagramChannelIterator(selector.selectedKeys());
188     }
189 
190     @Override
191     protected int send(NioSession session, IoBuffer buffer,
192             SocketAddress remoteAddress) throws Exception {
193         return ((DatagramChannel) session.getChannel()).send(
194                 buffer.buf(), remoteAddress);
195     }
196 
197     @Override
198     protected void setInterestedInWrite(NioSession session, boolean interested)
199             throws Exception {
200         SelectionKey key = session.getSelectionKey();
201         if (key == null) {
202             return;
203         }
204         
205         if (interested) {
206             key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
207         } else {
208             key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
209         }
210     }
211 
212     @Override
213     protected void close(DatagramChannel handle) throws Exception {
214         SelectionKey key = handle.keyFor(selector);
215         if (key != null) {
216             key.cancel();
217         }
218         handle.disconnect();
219         handle.close();
220     }
221 
222     @Override
223     protected void wakeup() {
224         selector.wakeup();
225     }
226     
227     private static class DatagramChannelIterator implements Iterator<DatagramChannel> {
228         
229         private final Iterator<SelectionKey> i;
230         
231         private DatagramChannelIterator(Collection<SelectionKey> keys) {
232             this.i = keys.iterator();
233         }
234         
235         public boolean hasNext() {
236             return i.hasNext();
237         }
238 
239         public DatagramChannel next() {
240             return (DatagramChannel) i.next().channel();
241         }
242 
243         public void remove() {
244             i.remove();
245         }
246         
247     }
248 }