View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.nio.entity;
29  
30  import java.io.File;
31  import java.io.FileInputStream;
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.io.OutputStream;
35  import java.nio.channels.FileChannel;
36  
37  import org.apache.http.annotation.NotThreadSafe;
38  import org.apache.http.entity.AbstractHttpEntity;
39  import org.apache.http.entity.ContentType;
40  import org.apache.http.nio.ContentEncoder;
41  import org.apache.http.nio.ContentEncoderChannel;
42  import org.apache.http.nio.FileContentEncoder;
43  import org.apache.http.nio.IOControl;
44  
45  /**
46   * A self contained, repeatable non-blocking entity that retrieves its content
47   * from a file. This class is mostly used to stream large files of different
48   * types, so one needs to supply the content type of the file to make sure
49   * the content can be correctly recognized and processed by the recipient.
50   *
51   * @since 4.0
52   */
53  @SuppressWarnings("deprecation")
54  @NotThreadSafe
55  public class NFileEntity extends AbstractHttpEntity
56                           implements HttpAsyncContentProducer, ProducingNHttpEntity {
57  
58      private final File file;
59      private FileChannel fileChannel;
60      private long idx = -1;
61      private boolean useFileChannels;
62  
63      /**
64       * Creates new instance of NFileEntity from the given source {@link File}
65       * with the given content type. If <code>useFileChannels</code> is set to
66       * <code>true</code>, the entity will try to use {@link FileContentEncoder}
67       * interface to stream file content directly from the file channel.
68       *
69       * @param file the source file.
70       * @param contentType the content type of the file.
71       * @param useFileChannels flag whether the direct transfer from the file
72       *   channel should be attempted.
73       *
74       * @since 4.2
75       */
76      public NFileEntity(final File file, final ContentType contentType, boolean useFileChannels) {
77          if (file == null) {
78              throw new IllegalArgumentException("File may not be null");
79          }
80          this.file = file;
81          this.useFileChannels = useFileChannels;
82          if (contentType != null) {
83              setContentType(contentType.toString());
84          }
85      }
86  
87      /**
88       * @since 4.2
89       */
90      public NFileEntity(final File file) {
91          if (file == null) {
92              throw new IllegalArgumentException("File may not be null");
93          }
94          this.file = file;
95      }
96      /**
97       * Creates new instance of NFileEntity from the given source {@link File}
98       * with the given content type.
99       *
100      * @param file the source file.
101      * @param contentType the content type of the file.
102      *
103      * @since 4.2
104      */
105     public NFileEntity(final File file, final ContentType contentType) {
106         this(file, contentType, true);
107     }
108 
109     /**
110      * @deprecated (4.2) use {@link #NFileEntity(File, ContentType, boolean)}
111      */
112     @Deprecated
113     public NFileEntity(final File file, final String contentType, boolean useFileChannels) {
114         if (file == null) {
115             throw new IllegalArgumentException("File may not be null");
116         }
117         this.file = file;
118         this.useFileChannels = useFileChannels;
119         setContentType(contentType);
120     }
121 
122     /**
123      * @deprecated (4.2) use {@link #NFileEntity(File, ContentType)}
124      */
125     @Deprecated
126     public NFileEntity(final File file, final String contentType) {
127         this(file, contentType, true);
128     }
129 
130     /**
131      * {@inheritDoc}
132      *
133      * @since 4.2
134      */
135     public void close() throws IOException {
136         FileChannel local = fileChannel;
137         fileChannel = null;
138         if (local != null) {
139             local.close();
140         }
141     }
142 
143     /**
144      * {@inheritDoc}
145      *
146      * @deprecated (4.2) use {@link #close()}
147      */
148     public void finish() throws IOException {
149         close();
150     }
151 
152     public long getContentLength() {
153         return file.length();
154     }
155 
156     public boolean isRepeatable() {
157         return true;
158     }
159 
160     public void produceContent(ContentEncoder encoder, IOControl ioctrl)
161             throws IOException {
162         if (fileChannel == null) {
163             FileInputStream in = new FileInputStream(file);
164             fileChannel = in.getChannel();
165             idx = 0;
166         }
167 
168         long transferred;
169         if (useFileChannels && encoder instanceof FileContentEncoder) {
170             transferred = ((FileContentEncoder)encoder)
171                 .transfer(fileChannel, idx, Long.MAX_VALUE);
172         } else {
173             transferred = fileChannel.
174                 transferTo(idx, Long.MAX_VALUE, new ContentEncoderChannel(encoder));
175         }
176         if (transferred > 0) {
177             idx += transferred;
178         }
179         if (idx >= fileChannel.size()) {
180             encoder.complete();
181             close();
182         }
183     }
184 
185     public boolean isStreaming() {
186         return false;
187     }
188 
189     public InputStream getContent() throws IOException {
190         return new FileInputStream(this.file);
191     }
192 
193     public void writeTo(final OutputStream outstream) throws IOException {
194         if (outstream == null) {
195             throw new IllegalArgumentException("Output stream may not be null");
196         }
197         InputStream instream = new FileInputStream(this.file);
198         try {
199             byte[] tmp = new byte[4096];
200             int l;
201             while ((l = instream.read(tmp)) != -1) {
202                 outstream.write(tmp, 0, l);
203             }
204             outstream.flush();
205         } finally {
206             instream.close();
207         }
208     }
209 
210 }