View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.oio;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.channel.Channel;
20  import io.netty.channel.FileRegion;
21  import io.netty.channel.RecvByteBufAllocator;
22  
23  import java.io.EOFException;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.nio.channels.Channels;
28  import java.nio.channels.ClosedChannelException;
29  import java.nio.channels.NotYetConnectedException;
30  import java.nio.channels.WritableByteChannel;
31  
32  /**
33   * Abstract base class for OIO Channels that are based on streams.
34   *
35   * @deprecated use NIO / EPOLL / KQUEUE transport.
36   */
37  @Deprecated
38  public abstract class OioByteStreamChannel extends AbstractOioByteChannel {
39  
40      private static final InputStream CLOSED_IN = new InputStream() {
41          @Override
42          public int read() {
43              return -1;
44          }
45      };
46  
47      private static final OutputStream CLOSED_OUT = new OutputStream() {
48          @Override
49          public void write(int b) throws IOException {
50              throw new ClosedChannelException();
51          }
52      };
53  
54      private InputStream is;
55      private OutputStream os;
56      private WritableByteChannel outChannel;
57  
58      /**
59       * Create a new instance
60       *
61       * @param parent    the parent {@link Channel} which was used to create this instance. This can be null if the
62       *                  {@link} has no parent as it was created by your self.
63       */
64      protected OioByteStreamChannel(Channel parent) {
65          super(parent);
66      }
67  
68      /**
69       * Activate this instance. After this call {@link #isActive()} will return {@code true}.
70       */
71      protected final void activate(InputStream is, OutputStream os) {
72          if (this.is != null) {
73              throw new IllegalStateException("input was set already");
74          }
75          if (this.os != null) {
76              throw new IllegalStateException("output was set already");
77          }
78          if (is == null) {
79              throw new NullPointerException("is");
80          }
81          if (os == null) {
82              throw new NullPointerException("os");
83          }
84          this.is = is;
85          this.os = os;
86      }
87  
88      @Override
89      public boolean isActive() {
90          InputStream is = this.is;
91          if (is == null || is == CLOSED_IN) {
92              return false;
93          }
94  
95          OutputStream os = this.os;
96          return !(os == null || os == CLOSED_OUT);
97      }
98  
99      @Override
100     protected int available() {
101         try {
102             return is.available();
103         } catch (IOException ignored) {
104             return 0;
105         }
106     }
107 
108     @Override
109     protected int doReadBytes(ByteBuf buf) throws Exception {
110         final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
111         allocHandle.attemptedBytesRead(Math.max(1, Math.min(available(), buf.maxWritableBytes())));
112         return buf.writeBytes(is, allocHandle.attemptedBytesRead());
113     }
114 
115     @Override
116     protected void doWriteBytes(ByteBuf buf) throws Exception {
117         OutputStream os = this.os;
118         if (os == null) {
119             throw new NotYetConnectedException();
120         }
121         buf.readBytes(os, buf.readableBytes());
122     }
123 
124     @Override
125     protected void doWriteFileRegion(FileRegion region) throws Exception {
126         OutputStream os = this.os;
127         if (os == null) {
128             throw new NotYetConnectedException();
129         }
130         if (outChannel == null) {
131             outChannel = Channels.newChannel(os);
132         }
133 
134         long written = 0;
135         for (;;) {
136             long localWritten = region.transferTo(outChannel, written);
137             if (localWritten == -1) {
138                 checkEOF(region);
139                 return;
140             }
141             written += localWritten;
142 
143             if (written >= region.count()) {
144                 return;
145             }
146         }
147     }
148 
149     private static void checkEOF(FileRegion region) throws IOException {
150         if (region.transferred() < region.count()) {
151             throw new EOFException("Expected to be able to write " + region.count() + " bytes, " +
152                                    "but only wrote " + region.transferred());
153         }
154     }
155 
156     @Override
157     protected void doClose() throws Exception {
158         InputStream is = this.is;
159         OutputStream os = this.os;
160         this.is = CLOSED_IN;
161         this.os = CLOSED_OUT;
162 
163         try {
164             if (is != null) {
165                 is.close();
166             }
167         } finally {
168             if (os != null) {
169                 os.close();
170             }
171         }
172     }
173 }