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: 671827 $, $Date: 2008-06-26 10:49:48 +0200 (jeu, 26 jun 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 boolean select(int timeout) throws Exception {
69          return selector.select(timeout) > 0;
70      }
71  
72      @Override
73      protected boolean isSelectorEmpty() {
74          return selector.keys().isEmpty();
75      }
76  
77      @Override
78      protected void wakeup() {
79          selector.wakeup();
80      }
81  
82      @Override
83      protected Iterator<NioSession> allSessions() {
84          return new IoSessionIterator(selector.keys());
85      }
86  
87      @Override
88      protected Iterator<NioSession> selectedSessions() {
89          return new IoSessionIterator(selector.selectedKeys());
90      }
91  
92      @Override
93      protected void init(NioSession session) throws Exception {
94          SelectableChannel ch = (SelectableChannel) session.getChannel();
95          ch.configureBlocking(false);
96          session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
97      }
98  
99      @Override
100     protected void destroy(NioSession session) throws Exception {
101         ByteChannel ch = session.getChannel();
102         SelectionKey key = session.getSelectionKey();
103         if (key != null) {
104             key.cancel();
105         }
106         ch.close();
107     }
108 
109     @Override
110     protected SessionState state(NioSession session) {
111         SelectionKey key = session.getSelectionKey();
112         if (key == null) {
113             return SessionState.PREPARING;
114         }
115 
116         return key.isValid()? SessionState.OPEN : SessionState.CLOSED;
117     }
118 
119     @Override
120     protected boolean isReadable(NioSession session) {
121         SelectionKey key = session.getSelectionKey();
122         return key.isValid() && key.isReadable();
123     }
124 
125     @Override
126     protected boolean isWritable(NioSession session) {
127         SelectionKey key = session.getSelectionKey();
128         return key.isValid() && key.isWritable();
129     }
130 
131     @Override
132     protected boolean isInterestedInRead(NioSession session) {
133         SelectionKey key = session.getSelectionKey();
134         return key.isValid() && (key.interestOps() & SelectionKey.OP_READ) != 0;
135     }
136 
137     @Override
138     protected boolean isInterestedInWrite(NioSession session) {
139         SelectionKey key = session.getSelectionKey();
140         return key.isValid() && (key.interestOps() & SelectionKey.OP_WRITE) != 0;
141     }
142 
143     @Override
144     protected void setInterestedInRead(NioSession session, boolean value) throws Exception {
145         SelectionKey key = session.getSelectionKey();
146         int oldInterestOps = key.interestOps();
147         int newInterestOps;
148         if (value) {
149             newInterestOps = oldInterestOps | SelectionKey.OP_READ;
150         } else {
151             newInterestOps = oldInterestOps & ~SelectionKey.OP_READ;
152         }
153         if (oldInterestOps != newInterestOps) {
154             key.interestOps(newInterestOps);
155         }
156     }
157 
158     @Override
159     protected void setInterestedInWrite(NioSession session, boolean value) throws Exception {
160         SelectionKey key = session.getSelectionKey();
161         int oldInterestOps = key.interestOps();
162         int newInterestOps;
163         if (value) {
164             newInterestOps = oldInterestOps | SelectionKey.OP_WRITE;
165         } else {
166             newInterestOps = oldInterestOps & ~SelectionKey.OP_WRITE;
167         }
168         if (oldInterestOps != newInterestOps) {
169             key.interestOps(newInterestOps);
170         }
171     }
172 
173     @Override
174     protected int read(NioSession session, IoBuffer buf) throws Exception {
175         return session.getChannel().read(buf.buf());
176     }
177 
178     @Override
179     protected int write(NioSession session, IoBuffer buf, int length) throws Exception {
180         if (buf.remaining() <= length) {
181             return session.getChannel().write(buf.buf());
182         } else {
183             int oldLimit = buf.limit();
184             buf.limit(buf.position() + length);
185             try {
186                 return session.getChannel().write(buf.buf());
187             } finally {
188                 buf.limit(oldLimit);
189             }
190         }
191     }
192 
193     @Override
194     protected int transferFile(NioSession session, FileRegion region, int length) throws Exception {
195         try {
196             return (int) region.getFileChannel().transferTo(region.getPosition(), length, session.getChannel());
197         } catch (IOException e) {
198             // Check to see if the IOException is being thrown due to
199             // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103988
200             String message = e.getMessage();
201             if (message != null && message.contains("temporarily unavailable")) {
202                 return 0;
203             } else {
204                 throw e;
205             }
206         }
207     }
208 
209     protected static class IoSessionIterator implements Iterator<NioSession> {
210         private final Iterator<SelectionKey> i;
211         private IoSessionIterator(Set<SelectionKey> keys) {
212             i = keys.iterator();
213         }
214         public boolean hasNext() {
215             return i.hasNext();
216         }
217 
218         public NioSession next() {
219             SelectionKey key = i.next();
220             return (NioSession) key.attachment();
221         }
222 
223         public void remove() {
224             i.remove();
225         }
226     }
227 }