View Javadoc

1   /*
2    * Copyright 2012 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;
17  
18  import io.netty.util.AbstractReferenceCounted;
19  import io.netty.util.IllegalReferenceCountException;
20  import io.netty.util.internal.logging.InternalLogger;
21  import io.netty.util.internal.logging.InternalLoggerFactory;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.RandomAccessFile;
26  import java.nio.channels.FileChannel;
27  import java.nio.channels.WritableByteChannel;
28  
29  /**
30   * Default [email protected] FileRegion} implementation which transfer data from a [email protected] FileChannel} or [email protected] File}.
31   *
32   * Be aware that the [email protected] FileChannel} will be automatically closed once [email protected] #refCnt()} returns
33   * [email protected] 0}.
34   */
35  public class DefaultFileRegion extends AbstractReferenceCounted implements FileRegion {
36  
37      private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultFileRegion.class);
38      private final File f;
39      private final long position;
40      private final long count;
41      private long transferred;
42      private FileChannel file;
43  
44      /**
45       * Create a new instance
46       *
47       * @param file      the [email protected] FileChannel} which should be transfered
48       * @param position  the position from which the transfer should start
49       * @param count     the number of bytes to transfer
50       */
51      public DefaultFileRegion(FileChannel file, long position, long count) {
52          if (file == null) {
53              throw new NullPointerException("file");
54          }
55          if (position < 0) {
56              throw new IllegalArgumentException("position must be >= 0 but was " + position);
57          }
58          if (count < 0) {
59              throw new IllegalArgumentException("count must be >= 0 but was " + count);
60          }
61          this.file = file;
62          this.position = position;
63          this.count = count;
64          f = null;
65      }
66  
67      /**
68       * Create a new instance using the given [email protected] File}. The [email protected] File} will be opened lazily or
69       * explicitly via [email protected] #open()}.
70       *
71       * @param f         the [email protected] File} which should be transfered
72       * @param position  the position from which the transfer should start
73       * @param count     the number of bytes to transfer
74       */
75      public DefaultFileRegion(File f, long position, long count) {
76          if (f == null) {
77              throw new NullPointerException("f");
78          }
79          if (position < 0) {
80              throw new IllegalArgumentException("position must be >= 0 but was " + position);
81          }
82          if (count < 0) {
83              throw new IllegalArgumentException("count must be >= 0 but was " + count);
84          }
85          this.position = position;
86          this.count = count;
87          this.f = f;
88      }
89  
90      /**
91       * Returns [email protected] true} if the [email protected] FileRegion} has a open file-descriptor
92       */
93      public boolean isOpen() {
94          return file != null;
95      }
96  
97      /**
98       * Explicitly open the underlying file-descriptor if not done yet.
99       */
100     public void open() throws IOException {
101         if (!isOpen() && refCnt() > 0) {
102             // Only open if this DefaultFileRegion was not released yet.
103             file = new RandomAccessFile(f, "r").getChannel();
104         }
105     }
106 
107     @Override
108     public long position() {
109         return position;
110     }
111 
112     @Override
113     public long count() {
114         return count;
115     }
116 
117     @Deprecated
118     @Override
119     public long transfered() {
120         return transferred;
121     }
122 
123     @Override
124     public long transferred() {
125         return transferred;
126     }
127 
128     @Override
129     public long transferTo(WritableByteChannel target, long position) throws IOException {
130         long count = this.count - position;
131         if (count < 0 || position < 0) {
132             throw new IllegalArgumentException(
133                     "position out of range: " + position +
134                     " (expected: 0 - " + (this.count - 1) + ')');
135         }
136         if (count == 0) {
137             return 0L;
138         }
139         if (refCnt() == 0) {
140             throw new IllegalReferenceCountException(0);
141         }
142         // Call open to make sure fc is initialized. This is a no-oop if we called it before.
143         open();
144 
145         long written = file.transferTo(this.position + position, count, target);
146         if (written > 0) {
147             transferred += written;
148         }
149         return written;
150     }
151 
152     @Override
153     protected void deallocate() {
154         FileChannel file = this.file;
155 
156         if (file == null) {
157             return;
158         }
159         this.file = null;
160 
161         try {
162             file.close();
163         } catch (IOException e) {
164             if (logger.isWarnEnabled()) {
165                 logger.warn("Failed to close a file.", e);
166             }
167         }
168     }
169 
170     @Override
171     public FileRegion retain() {
172         super.retain();
173         return this;
174     }
175 
176     @Override
177     public FileRegion retain(int increment) {
178         super.retain(increment);
179         return this;
180     }
181 
182     @Override
183     public FileRegion touch() {
184         return this;
185     }
186 
187     @Override
188     public FileRegion touch(Object hint) {
189         return this;
190     }
191 }