PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/org.restlet/src/main/java/org/restlet/engine/io/NbChannelInputStream.java

http://github.com/restlet/restlet-framework-java
Java | 245 lines | 145 code | 37 blank | 63 comment | 33 complexity | 9c55e4950d796e316bafc291b4980976 MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, CPL-1.0, LGPL-2.1
  1. /**
  2. * Copyright 2005-2020 Talend
  3. *
  4. * The contents of this file are subject to the terms of one of the following
  5. * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
  6. * select the license that you prefer but you may not use this file except in
  7. * compliance with one of these Licenses.
  8. *
  9. * You can obtain a copy of the Apache 2.0 license at
  10. * http://www.opensource.org/licenses/apache-2.0
  11. *
  12. * You can obtain a copy of the EPL 1.0 license at
  13. * http://www.opensource.org/licenses/eclipse-1.0
  14. *
  15. * See the Licenses for the specific language governing permissions and
  16. * limitations under the Licenses.
  17. *
  18. * Alternatively, you can obtain a royalty free commercial license with less
  19. * limitations, transferable or non-transferable, directly at
  20. * https://restlet.talend.com/
  21. *
  22. * Restlet is a registered trademark of Talend S.A.
  23. */
  24. package org.restlet.engine.io;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.nio.ByteBuffer;
  28. import java.nio.channels.ReadableByteChannel;
  29. import java.nio.channels.SelectableChannel;
  30. import java.nio.channels.SelectionKey;
  31. import java.nio.channels.Selector;
  32. import java.util.logging.Level;
  33. import org.restlet.Context;
  34. import org.restlet.util.SelectionListener;
  35. import org.restlet.util.SelectionRegistration;
  36. // [excludes gwt]
  37. /**
  38. * Input stream connected to a non-blocking readable channel.
  39. *
  40. * @author Jerome Louvel
  41. */
  42. public class NbChannelInputStream extends InputStream {
  43. /** The internal byte buffer. */
  44. private final ByteBuffer byteBuffer;
  45. /** The channel to read from. */
  46. private final ReadableByteChannel channel;
  47. /** Indicates if further reads can be attempted. */
  48. private volatile boolean endReached;
  49. /** The registered selection registration. */
  50. private volatile SelectionRegistration selectionRegistration;
  51. /** The optional selectable channel to read from. */
  52. private final SelectableChannel selectableChannel;
  53. /** The optional selection channel to read from. */
  54. private final SelectionChannel selectionChannel;
  55. /**
  56. * Constructor.
  57. *
  58. * @param channel
  59. * The channel to read from.
  60. */
  61. public NbChannelInputStream(ReadableByteChannel channel) {
  62. this.channel = channel;
  63. if (channel instanceof ReadableSelectionChannel) {
  64. this.selectionChannel = (ReadableSelectionChannel) channel;
  65. this.selectableChannel = null;
  66. } else if (channel instanceof SelectableChannel) {
  67. this.selectionChannel = null;
  68. this.selectableChannel = (SelectableChannel) channel;
  69. } else if (channel instanceof SelectionChannel) {
  70. this.selectionChannel = (SelectionChannel) channel;
  71. this.selectableChannel = null;
  72. } else {
  73. this.selectionChannel = null;
  74. this.selectableChannel = null;
  75. }
  76. this.byteBuffer = ByteBuffer.allocate(IoUtils.BUFFER_SIZE);
  77. this.byteBuffer.flip();
  78. this.endReached = false;
  79. this.selectionRegistration = null;
  80. }
  81. @Override
  82. public int read() throws IOException {
  83. int result = -1;
  84. if (!this.endReached) {
  85. if (!this.byteBuffer.hasRemaining()) {
  86. // Let's refill
  87. refill();
  88. }
  89. if (!this.endReached) {
  90. // Let's return the next one
  91. result = this.byteBuffer.get() & 0xff;
  92. }
  93. }
  94. return result;
  95. }
  96. @Override
  97. public int read(byte[] b, int off, int len) throws IOException {
  98. int result = -1;
  99. if (!this.endReached) {
  100. if (!this.byteBuffer.hasRemaining()) {
  101. // Let's try to refill
  102. refill();
  103. }
  104. if (!this.endReached) {
  105. // Let's return the next ones
  106. result = Math.min(len, this.byteBuffer.remaining());
  107. this.byteBuffer.get(b, off, result);
  108. }
  109. }
  110. return result;
  111. }
  112. /**
  113. * Reads the available bytes from the channel into the byte buffer.
  114. *
  115. * @return The number of bytes read or -1 if the end of channel has been
  116. * reached.
  117. * @throws IOException
  118. */
  119. private int readChannel() throws IOException {
  120. int result = 0;
  121. this.byteBuffer.clear();
  122. result = this.channel.read(this.byteBuffer);
  123. if (result > 0) {
  124. if (Context.getCurrentLogger().isLoggable(Level.FINE)) {
  125. Context.getCurrentLogger().log(
  126. Level.FINE,
  127. "NbChannelInputStream#readChannel : " + result
  128. + " bytes read");
  129. }
  130. this.byteBuffer.flip();
  131. }
  132. return result;
  133. }
  134. /**
  135. * Refill the byte buffer by attempting to read the channel.
  136. *
  137. * @throws IOException
  138. */
  139. private void refill() throws IOException {
  140. int bytesRead = 0;
  141. while (bytesRead == 0) {
  142. bytesRead = readChannel();
  143. if (bytesRead == 0) {
  144. // No bytes were read, try to register
  145. // a select key to get more
  146. if (selectionChannel != null) {
  147. try {
  148. if (this.selectionRegistration == null) {
  149. this.selectionRegistration = this.selectionChannel
  150. .getRegistration();
  151. this.selectionRegistration
  152. .setInterestOperations(SelectionKey.OP_READ);
  153. this.selectionRegistration
  154. .setSelectionListener(new SelectionListener() {
  155. public void onSelected(
  156. SelectionRegistration registration)
  157. throws IOException {
  158. if (Context.getCurrentLogger()
  159. .isLoggable(Level.FINER)) {
  160. Context.getCurrentLogger()
  161. .log(Level.FINER,
  162. "NbChannelInputStream selected");
  163. }
  164. // Stop listening at this point
  165. selectionRegistration.suspend();
  166. // Unblock the user thread
  167. selectionRegistration.unblock();
  168. }
  169. });
  170. } else {
  171. this.selectionRegistration.resume();
  172. }
  173. // Block until new content arrives or a timeout occurs
  174. this.selectionRegistration.block();
  175. // Attempt to read more content
  176. bytesRead = readChannel();
  177. } catch (Exception e) {
  178. Context.getCurrentLogger()
  179. .log(Level.FINE,
  180. "Exception while registering or waiting for new content",
  181. e);
  182. }
  183. } else if (selectableChannel != null) {
  184. Selector selector = null;
  185. SelectionKey selectionKey = null;
  186. try {
  187. selector = SelectorFactory.getSelector();
  188. if (selector != null) {
  189. selectionKey = this.selectableChannel.register(
  190. selector, SelectionKey.OP_READ);
  191. selector.select(IoUtils.TIMEOUT_MS);
  192. }
  193. } finally {
  194. IoUtils.release(selector, selectionKey);
  195. }
  196. bytesRead = readChannel();
  197. }
  198. }
  199. }
  200. if (bytesRead == -1) {
  201. this.endReached = true;
  202. if (this.selectionRegistration != null) {
  203. this.selectionRegistration.setCanceling(true);
  204. this.selectionRegistration.setSelectionListener(null);
  205. }
  206. }
  207. }
  208. }