Index: FilePart.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v
retrieving revision 1.2
diff -u -r1.2 FilePart.java
--- FilePart.java 11 Oct 2002 05:16:32 -0000 1.2
+++ FilePart.java 17 Oct 2002 01:06:09 -0000
@@ -64,6 +64,7 @@
import java.io.File;
import java.io.FileInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileNotFoundException;
@@ -82,6 +83,7 @@
*
* @author Matthew Albright
* @author Jeff Dever
+ * @author Adrian Sutton
*
* @since 2.0
*
@@ -91,12 +93,17 @@
//TODO: make this configurable
static int MAX_BUFF_SIZE = 1 * 1024 * 1024; // 1 MiBs
+ private File file;
private InputStream fileStream;
private String fileName;
private long fileLength;
private String name;
private int buff_size;
+
+ private byte[] dataBuf = null;
+ private boolean bufferData = true;
+ private boolean markSupported = false;
/**
* Constructor.
@@ -110,7 +117,8 @@
public FilePart(String name, File file)
throws FileNotFoundException {
- this( name, new FileInputStream(file), file.getName(), file.length() );
+ // We create the input stream straight from the file later on.
+ this( name, null, file.getName(), file.length() );
if (! file.isFile()) {
throw new FileNotFoundException("File is not a normal file.");
@@ -119,16 +127,24 @@
if (! file.canRead()) {
throw new FileNotFoundException("File is not readable.");
}
+
+ this.file = file;
+ this.bufferData = false;
}
/**
- * FilePart Constructor.
+ * FilePart Constructor. This constructor should generally be
+ * avoided in favour of FilePart(String, java.io.File) as
+ * using an InputStream requires data to be buffered in RAM in case
+ * it needs to be resent.
*
* @param name the name for this part
* @param fileInputStream an input stream for reading the file content
* @param fileName the name of the file
* @param fileLength the number of bytes contained in the file
+ * @see #getBufferData()
+ * @see #setBufferData(boolean)
*/
public FilePart(
String name,
@@ -145,7 +161,12 @@
this.fileStream = fileInputStream;
this.fileName = fileName;
this.fileLength = fileLength;
-
+ // We need to cast fileLength to an int to call mark(int) on the
+ // input stream, so we must ensure that the file length will fit
+ // into an int before trying to use mark and reset.
+ this.markSupported = fileInputStream.markSupported() &&
+ fileLength <= Integer.MAX_VALUE;
+ this.bufferData = !markSupported;
}
protected void sendHeader(OutputStream out)
@@ -190,18 +211,65 @@
buff = new byte[(new Long(lengthOfData())).intValue()];
}
- int len;
-
- while ((len = fileStream.read(buff)) != -1)
- {
- out.write(buff, 0, len);
+ InputStream is = fileStream;
+ if (markSupported) {
+ fileStream.mark((int)fileLength);
+ }
+ if (file != null) {
+ is = new FileInputStream(file);
+ }
+ if (dataBuf != null) {
+ // Send the buffered data from a previous send.
+ out.write(dataBuf, 0, dataBuf.length);
+ } else {
+ int len;
+ ByteArrayOutputStream bufferStream = null;
+ if (bufferData) {
+ bufferStream = new ByteArrayOutputStream();
+ }
+ while ((len = is.read(buff)) != -1) {
+ out.write(buff, 0, len);
+ if (bufferData) {
+ bufferStream.write(buff, 0, len);
+ }
+ }
+ if (bufferData) {
+ dataBuf = bufferStream.toByteArray();
+ }
+ if (markSupported) {
+ fileStream.reset();
+ }
}
-
}
protected long lengthOfData()
throws IOException {
return fileLength;
}
+
+ /**
+ * Sets whether or not to buffer the data from the input stream so
+ * that it can be resent if nessecary during the connection. Note
+ * that this has no effect if this FilePart was constructed from a
+ * File object as a new FileInputStream will always be opened for
+ * each request.
+ *
+ * @param bufferData true if the data should be buffered in memory.
+ * @see #getBufferData()
+ */
+ public void setBufferData(boolean bufferData) {
+ this.bufferData = bufferData;
+ }
+
+ /**
+ * Returns whether or not data from the input stream is buffered in
+ * memory for this FilePart.
+ *
+ * @return true if the data will be buffered in memory.
+ * @see #setBufferData(boolean)
+ */
+ public boolean getBufferData() {
+ return bufferData && file == null;
+ }
}