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  import io.netty.util.internal.ObjectUtil;
23  
24  import java.io.EOFException;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.OutputStream;
28  import java.nio.channels.Channels;
29  import java.nio.channels.ClosedChannelException;
30  import java.nio.channels.NotYetConnectedException;
31  import java.nio.channels.WritableByteChannel;
32  
33  /**
34   * Abstract base class for OIO Channels that are based on streams.
35   *
36   * @deprecated use NIO / EPOLL / KQUEUE transport.
37   */
38  @Deprecated
39  public abstract class OioByteStreamChannel extends AbstractOioByteChannel {
40  
41      private static final InputStream CLOSED_IN = new InputStream() {
42          @Override
43          public int read() {
44              return -1;
45          }
46      };
47  
48      private static final OutputStream CLOSED_OUT = new OutputStream() {
49          @Override
50          public void write(int b) throws IOException {
51              throw new ClosedChannelException();
52          }
53      };
54  
55      private InputStream is;
56      private OutputStream os;
57      private WritableByteChannel outChannel;
58  
59      /**
60       * Create a new instance
61       *
62       * @param parent    the parent {@link Channel} which was used to create this instance. This can be null if the
63       *                  {@link} has no parent as it was created by your self.
64       */
65      protected OioByteStreamChannel(Channel parent) {
66          super(parent);
67      }
68  
69      /**
70       * Activate this instance. After this call {@link #isActive()} will return {@code true}.
71       */
72      protected final void activate(InputStream is, OutputStream os) {
73          if (this.is != null) {
74              throw new IllegalStateException("input was set already");
75          }
76          if (this.os != null) {
77              throw new IllegalStateException("output was set already");
78          }
79          this.is = ObjectUtil.checkNotNull(is, "is");
80          this.os = ObjectUtil.checkNotNull(os, "os");
81      }
82  
83      @Override
84      public boolean isActive() {
85          InputStream is = this.is;
86          if (is == null || is == CLOSED_IN) {
87              return false;
88          }
89  
90          OutputStream os = this.os;
91          return !(os == null || os == CLOSED_OUT);
92      }
93  
94      @Override
95      protected int available() {
96          try {
97              return is.available();
98          } catch (IOException ignored) {
99              return 0;
100         }
101     }
102 
103     @Override
104     protected int doReadBytes(ByteBuf buf) throws Exception {
105         final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
106         allocHandle.attemptedBytesRead(Math.max(1, Math.min(available(), buf.maxWritableBytes())));
107         return buf.writeBytes(is, allocHandle.attemptedBytesRead());
108     }
109 
110     @Override
111     protected void doWriteBytes(ByteBuf buf) throws Exception {
112         OutputStream os = this.os;
113         if (os == null) {
114             throw new NotYetConnectedException();
115         }
116         buf.readBytes(os, buf.readableBytes());
117     }
118 
119     @Override
120     protected void doWriteFileRegion(FileRegion region) throws Exception {
121         OutputStream os = this.os;
122         if (os == null) {
123             throw new NotYetConnectedException();
124         }
125         if (outChannel == null) {
126             outChannel = Channels.newChannel(os);
127         }
128 
129         long written = 0;
130         for (;;) {
131             long localWritten = region.transferTo(outChannel, written);
132             if (localWritten == -1) {
133                 checkEOF(region);
134                 return;
135             }
136             written += localWritten;
137 
138             if (written >= region.count()) {
139                 return;
140             }
141         }
142     }
143 
144     private static void checkEOF(FileRegion region) throws IOException {
145         if (region.transferred() < region.count()) {
146             throw new EOFException("Expected to be able to write " + region.count() + " bytes, " +
147                                    "but only wrote " + region.transferred());
148         }
149     }
150 
151     @Override
152     protected void doClose() throws Exception {
153         InputStream is = this.is;
154         OutputStream os = this.os;
155         this.is = CLOSED_IN;
156         this.os = CLOSED_OUT;
157 
158         try {
159             if (is != null) {
160                 is.close();
161             }
162         } finally {
163             if (os != null) {
164                 os.close();
165             }
166         }
167     }
168 }