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.io.IOException;
23  import java.nio.channels.ByteChannel;
24  import java.nio.channels.SelectableChannel;
25  import java.nio.channels.SelectionKey;
26  import java.nio.channels.Selector;
27  import java.util.Iterator;
28  import java.util.Set;
29  import java.util.concurrent.Executor;
30  
31  import org.apache.mina.core.RuntimeIoException;
32  import org.apache.mina.core.buffer.IoBuffer;
33  import org.apache.mina.core.file.FileRegion;
34  import org.apache.mina.core.polling.AbstractPollingIoProcessor;
35  
36  /**
37   * TODO Add documentation
38   * 
39   * @author The Apache MINA Project (dev@mina.apache.org)
40   * @version $Rev: 708218 $, $Date: 2008-10-27 16:16:48 +0100 (Mon, 27 Oct 2008) $
41   */
42  public final class NioProcessor extends AbstractPollingIoProcessor<NioSession> {
43      /** The selector associated with this processor */
44      private final Selector selector;
45  
46      /**
47       * 
48       * Creates a new instance of NioProcessor.
49       *
50       * @param executor
51       */
52      public NioProcessor(Executor executor) {
53          super(executor);
54          try {
55              // Open a new selector
56              selector = Selector.open();
57          } catch (IOException e) {
58              throw new RuntimeIoException("Failed to open a selector.", e);
59          }
60      }
61  
62      @Override
63      protected void dispose0() throws Exception {
64          selector.close();
65      }
66  
67      @Override
68      protected int select(int timeout) throws Exception {
69          return selector.select(timeout);
70      }
71  
72      @Override
73      protected int select() throws Exception {
74          return selector.select();
75      }
76  
77      @Override
78      protected boolean isSelectorEmpty() {
79          return selector.keys().isEmpty();
80      }
81  
82      @Override
83      protected void wakeup() {
84          selector.wakeup();
85      }
86  
87      @Override
88      protected Iterator<NioSession> allSessions() {
89          return new IoSessionIterator(selector.keys());
90      }
91  
92      @Override
93      protected Iterator<NioSession> selectedSessions() {
94          return new IoSessionIterator(selector.selectedKeys());
95      }
96  
97      @Override
98      protected void init(NioSession session) throws Exception {
99          SelectableChannel ch = (SelectableChannel) session.getChannel();
100         ch.configureBlocking(false);
101         session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
102     }
103 
104     @Override
105     protected void destroy(NioSession session) throws Exception {
106         ByteChannel ch = session.getChannel();
107         SelectionKey key = session.getSelectionKey();
108         if (key != null) {
109             key.cancel();
110         }
111         ch.close();
112     }
113 
114     @Override
115     protected SessionState state(NioSession session) {
116         SelectionKey key = session.getSelectionKey();
117         if (key == null) {
118             return SessionState.PREPARING;
119         }
120 
121         return key.isValid()? SessionState.OPEN : SessionState.CLOSED;
122     }
123 
124     @Override
125     protected boolean isReadable(NioSession session) {
126         SelectionKey key = session.getSelectionKey();
127         return key.isValid() && key.isReadable();
128     }
129 
130     @Override
131     protected boolean isWritable(NioSession session) {
132         SelectionKey key = session.getSelectionKey();
133         return key.isValid() && key.isWritable();
134     }
135 
136     @Override
137     protected boolean isInterestedInRead(NioSession session) {
138         SelectionKey key = session.getSelectionKey();
139         return key.isValid() && (key.interestOps() & SelectionKey.OP_READ) != 0;
140     }
141 
142     @Override
143     protected boolean isInterestedInWrite(NioSession session) {
144         SelectionKey key = session.getSelectionKey();
145         return key.isValid() && (key.interestOps() & SelectionKey.OP_WRITE) != 0;
146     }
147 
148     @Override
149     protected void setInterestedInRead(NioSession session, boolean value) throws Exception {
150         SelectionKey key = session.getSelectionKey();
151         int oldInterestOps = key.interestOps();
152         int newInterestOps;
153         if (value) {
154             newInterestOps = oldInterestOps | SelectionKey.OP_READ;
155         } else {
156             newInterestOps = oldInterestOps & ~SelectionKey.OP_READ;
157         }
158         if (oldInterestOps != newInterestOps) {
159             key.interestOps(newInterestOps);
160         }
161     }
162 
163     @Override
164     protected void setInterestedInWrite(NioSession session, boolean value) throws Exception {
165         SelectionKey key = session.getSelectionKey();
166         int oldInterestOps = key.interestOps();
167         int newInterestOps;
168         if (value) {
169             newInterestOps = oldInterestOps | SelectionKey.OP_WRITE;
170         } else {
171             newInterestOps = oldInterestOps & ~SelectionKey.OP_WRITE;
172         }
173         if (oldInterestOps != newInterestOps) {
174             key.interestOps(newInterestOps);
175         }
176     }
177 
178     @Override
179     protected int read(NioSession session, IoBuffer buf) throws Exception {
180         return session.getChannel().read(buf.buf());
181     }
182 
183     @Override
184     protected int write(NioSession session, IoBuffer buf, int length) throws Exception {
185         if (buf.remaining() <= length) {
186             return session.getChannel().write(buf.buf());
187         } else {
188             int oldLimit = buf.limit();
189             buf.limit(buf.position() + length);
190             try {
191                 return session.getChannel().write(buf.buf());
192             } finally {
193                 buf.limit(oldLimit);
194             }
195         }
196     }
197 
198     @Override
199     protected int transferFile(NioSession session, FileRegion region, int length) throws Exception {
200         try {
201             return (int) region.getFileChannel().transferTo(region.getPosition(), length, session.getChannel());
202         } catch (IOException e) {
203             // Check to see if the IOException is being thrown due to
204             // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103988
205             String message = e.getMessage();
206             if (message != null && message.contains("temporarily unavailable")) {
207                 return 0;
208             } else {
209                 throw e;
210             }
211         }
212     }
213 
214     /**
215      * An encapsulating iterator around the  {@link Selector#selectedKeys()} 
216      * or the {@link Selector#keys()} iterator;
217      */
218     protected static class IoSessionIterator implements Iterator<NioSession> {
219         private final Iterator<SelectionKey> iterator;
220         
221         /**
222          * Create this iterator as a wrapper on top of the selectionKey
223          * Set.
224          * @param keys
225          */
226         private IoSessionIterator(Set<SelectionKey> keys) {
227         	iterator = keys.iterator();
228         }
229         
230         /**
231          * {@inheritDoc}
232          */
233         public boolean hasNext() {
234             return iterator.hasNext();
235         }
236 
237         /**
238          * {@inheritDoc}
239          */
240         public NioSession next() {
241             SelectionKey key = iterator.next();
242             NioSession nioSession =  (NioSession) key.attachment();
243             return nioSession;
244         }
245 
246         /**
247          * {@inheritDoc}
248          */
249         public void remove() {
250         	iterator.remove();
251         }
252     }
253 }