When you click the Upload button (see Figure 1 again), the form
will be sent. This includes the file called abisco.html. This form is
submitted to the Jsp1.jsp file. This JSP file itself does
not return any response to the browser. However, it creates a file
called Demo.out.

In brief, the entity body of the HTTP request contains all the form
input, including the uploaded file. Those input values are separated
from each other by a delimiter. Sometimes called a boundary, this
delimiter consists of a few dozen dash characters followed by a random
number. In the example above, the delimiter is the following line.

-----------------------------7d15340138

The last delimiter ends the entity body with two more dashes.

For an input value that comes from a non-file element, the
delimiter is follows by the following line.

Content-Disposition: form-data; name=inputName

where inputName is the name of the form element.

For example:

Content-Disposition: form-data; name="Author"

Two sequences of carriage return linefeed characters and the
element value follow the line.

For the file, two lines follow the delimiter. The first contains
the name of the FILE input element and the complete path
of the file in the user's computer. From the HTTP request above, this
line is as follows.

It states that the FILE input element is called Filename and the
file path is C:\123data\abisco.html. Note that Windows
browsers include the file path, but Unix/Linux and Mac browsers only
send the filename.

The second line contains the content type of the file. Therefore,
its value depends on the file being uploaded. For this example, the
value is text/html.

Content-Type: text/html

Like the non-File input element, the content starts after two
sequences of carriage return linefeed characters.

That's all you need to know to write a File Upload Bean.

Brainy FileUpload Bean

Some file upload code is written as part of a bigger
application. Often the piece of code that does the extraction of the
uploaded file is integrated with the other pieces as a whole, making
it unusable for other applications. The solution here gives you the
file upload function in a Bean, which we all know is a component in
the Java platform. As such, this Bean is portable and can be used in
any application that requires file upload.

I call this Bean Brainy FileUploadBean. The complete code is given
in Listing 1. This section gives you the detailed
descriptions of what the code does, so that you can extend the
functionality if you so desire.

The first line of code is the package information. When I wrote the
Bean, it was part of the package called com.brainysoftware.web. You
probably don't want to use the same name for the package; therefore
you should change the first line of the code.

package com.brainysoftware.web;

Alternatively, you can remove this line entirely if you don't want
the class to be a member of any package.

Next are the import statements that tell you what classes or
interfaces are used in the Bean. Of special interest are the
HttpServletRequest interface from the
javax.servlet.http package and the abstract class
ServletInputStream from the javax.servlet
package. This class is a subclass of
java.io.InputStream.

Also imported are Dictionary and Hashtable from the
java.util package and PrintWriter, BufferedWriter,
FileWriter, and IOException from the java.io package.

Then comes the class, FileUploadBean. The class has 5 private
fields, 6 public methods and 2 private methods.

The FileUploadBean Class's Fields

The five fields of the FileUploadBean class are all private. They
are as follows.

private String savePath This field
specifies the path where the uploaded file should be saved on the
server. You set the value of savePath using the setSavePath
method. You should set this value prior to calling the doUpload
method. If not set, the uploaded file will be saved in the default
directory on the server.

private String filepath This field specifies
the complete path of the uploaded file on the client side. The value
of this field is specified by the doUpload method. You can obtain this
field's value using the getFilepath method from your JSP page or
Servlet. For non-Windows browsers, this value is the same as filename.

private String filename This field specifies
the name of the uploaded file. This field is set by the setFilename
method and retrieved from the filepath value. You can get the filename
from your Servlet or JSP page using the getFilename value.

private String contentType This field specifies
the type of the uploaded file content. Set by the doUpload method, you
can get the value of this field using the getContentType method.

private Dictionary fields This Dictionary
stores the name/value pairs of the HTML form's input elements at the
client side. You can then obtain the value of an input element by
calling the getFieldValue method.

The FileUploadBean Class's Methods

The first four public methods are used to return the FileUploadBean
object's private fields. They are getFilepath, getFilename,
getContentType and getFieldValue.

public String getFilepath()
This method returns the value of the filepath private field.

public String getFilename()
This method returns the value of the filename private field.

public String getContentType()
This method returns the value of the contentType private field.

public String getFieldValue(String fieldName)
This method returns the value of the HTML form element whose name is specified by fieldName.

public void setSavePath(String savePath)
Use this method to specify the name of the directory where the uploaded file should be saved on the server.

>public void doUpload(HttpServletRequest request) throws IOException
This is the most important method in the FileUploadBean class. This
method does two things. First, it extracts the field names and values
from the HTML form. All the field name-value pairs are stored in the
fields Hashtable object which is upcast to a Dictionary. The second
thing the doUpload method does is extract the uploaded file and save
it to the directory specified by savePath and assign the file's name,
path and content type to filename, filepath, and contentType
respectively.

You pass the HttpServletRequest object created by the Servlet/JSP
container to the doUpload method. This object represents the HTTP
request that you need to process to extract the HTML form's element
names-values and the uploaded file. The method starts by obtaining the
ServletInputStream object using the getInputStream method of the
HttpServletRequest object.

As explained before, each form element is separated by the boundary
and a sequence of carriage return line feed characters. Therefore, you
can read the content of the HttpServletRequest object line by
line. The following line of code defines a byte array called line.

byte[] line = new byte[128];

You then use the readLine method of ServletInputStream to read the
first line of the HttpServletRequest object's content.

int i = in.readLine(line, 0, 128);

The first line should be the boundary, and its length, if no error
has occurred, should be much longer than 3. Therefore, a length of
less than three can be assumed erroneous and the doUpload method
should exit.

if (i < 3)
return;

The boundary and the length of the boundary are important values,
as you will see later. The boundary is terminated by a sequence of
carriage return linefeed characters. Therefore the actual length is
two less than the number of bytes returned by the readLine method.

int boundaryLength = i - 2;

The boundary is retrieved from the byte array line by discarding
the last two carriage return linefeed characters.

String boundary = new String(line, 0, boundaryLength);

The field fields is then instantiated with a Hashtable object. This
Hashtable object is used to store the HTML form element name/value
pairs.

fields = new Hashtable();

Having the boundary you can then start extracting the form element
value by reading the HttpServletRequest object's content line by line
using the while loop, until it reaches the end of it when the readLine
method returns -1. All HTML form elements start with a boundary
followed by the content-disposition line that starts with the
following characters.

Content-Disposition: form-data; name=

There are two types of form elements: file and non-file (normal
form elements such as TEXT or HIDDEN elements). The difference between
the two is based on the file element, which contains the following
string.

filename="filename"

Therefore, you can use this information to distinguish the file
from the non-file input elements using the following two if
statements.

Now, let's a look at the code to extract the file content
first. Afterwards, we have a look at the code to extract non-file form
elements.

The filepath is contained in the content-disposition. To retrieve
the file path and the filename, the doUpload method calls
the setFilename private method. This method will be
discussed in the next section but it is sufficient to say that
setFilename extracts the file path and the filename information and
assign them to the filepath and filename fields.

After the setFilename method call, filename should not
be null. Otherwise, an error has occurred and the
doUpload method returns entirely.

if (filename==null)
return;

The next line after the content-disposition line is the content
type line. So call the readLine method again and call the
setContentType private method. This method is similar to
setFilename. It retrieves the content type of the
uploaded file from the raw bytes and assign it contentType.

The next line after the line that contains the file content type is
a blank line. Therefore, call the readLine method again.

i = in.readLine(line, 0, 128);

Then, begins the actual file content. We should be ready to write
the file to the disk, using a PrinterWriter object.

Where the file should be saved to depends on whether the
savePath field has been set. If the savePath
was not set, its value is null, and the file should be saved in the
default directory. If the savePath field has been set,
its value will not be null so the uploaded file must be uploaded to
this directory.

We can then extract the file content by using a while loop that
reads one line at a time and writes it to disk using the write method
of the PrintWriter. However, we know that the last line of the file
includes two carriage return line feed characters. Therefore, the
bytes saved to the disk must not include these two characters. So if
the line read is not the last line of the file, write all the bytes
read to the disk. If it is, write all the bytes read minus the last
two characters.

However, we do not know the size of the file. What we know is that
the next line after the file content is another boundary. Or, if the
file is the last HTML form element, the next line is the boundary plus
two dash characters. Therefore, by checking whether or not the next
line is a boundary we will know how to exit from the while loop. This
is the reason why I said the boundary value was important. We need the
boundary value for this.

We could read the next line and use the startsWith
method to check if the next line is a boundary. However, string
manipulation is expensive. To avoid string manipulation, we compare
the length of the byte array read by readLine. The latter
should be equal to boundaryLength + 2. Or, if it is the last line in
the HttpServletRequest object, it should be equal to
boundaryLength + 4 because of the last two dash characters. Because a
line could also be as long as a boundary without being a boundary, we
compare it with the boundary when the length matches. Now you know why
the boundaryLength value is also important.