wt.util
Class MPInputStream

java.lang.Object
  extended byjava.io.InputStream
      extended byjava.io.FilterInputStream
          extended bywt.util.MPInputStream
All Implemented Interfaces:
MPInputStreamIfc

public class MPInputStream
extends FilterInputStream
implements MPInputStreamIfc

A MP input stream is a filter that allows a business class to read consecutive multipart data object bodies whilst alleviating the associated pain. It does this by parsing out object body headers and values, and reading the input stream for the business class whilst checking for the encapsulation boundaries. Analagous to other input streams, MP will respond to read requests as long as there is data in the present object body. Once the end of the data for said object body is reached, a negative one is returned on the next read.

The only required steps are to instantiate a new MPInputStream (passing in the HTTPRequest's input stream and CGI_MULTIPART_BOUNDARY), and to call MP's hasMoreObjectBodies method. Provided the the instantiation succeeds and the return value of the hasMoreObjectBodies method call is true, the business class is free to proceed with reading of the first object body.

Upon receipt of a negative one from a read request, said object body is finished. The return value of another call to hasMoreObjectBodies will indicate if another object body is available for reading.

Note that this input stream filter reads the object body data as bytes, and thus does not impinge any format nor conversion upon the data therein. Thus if the object body data is, for example, base64 encoded, the resultant reads of the business class will get base64 encoded data. It is in this way, that this filter can operate independant of the data enclosed in the object body. It is therefore incumbant on the business class to perform any post processing of the data that may be necessary.

Supported API: true
Extendable: false


Field Summary
private  byte[] BDelimitor
           
private  Properties bodyHeaders
           
private  Vector boundariesV
           
private  int bVindex
           
(package private) static byte CR
           
private  boolean delim_found
           
private  String Delimitor
           
private  String encoding
           
private  boolean eof
           
private  String FinalDelimitor
           
private  byte[] ibuf
           
private  int ibuf_count
           
private  int ibuf_first
           
private  int ibuf_last
           
private  int ibufd
           
private  IOException ioe
           
private  int leading_dashes_count
           
(package private) static byte LF
           
private static String RESOURCE
           
private  String temp
           
private static String versionID
           
 
Fields inherited from class java.io.FilterInputStream
in
 
Fields inherited from class java.io.InputStream
 
Constructor Summary
MPInputStream(InputStream in, String boundary)
          Creates a new MPInputStream initialized with the specified input stream and object body boundary

Supported API: true
 
Method Summary
 int available()
          Returns the number of bytes that can be read without blocking.
 boolean containsBodyHeader(String s)
          Public checker for specific Object Body Header.
private  String convert(String orig)
           
private  int fill_buf()
          This method parses out the next MIME object body binary data by looking through an internal buffer for the encapsulation boundary.
private  int fill_buf(byte[] b, int off)
          Same as no-arg fill_buf but reads directly into caller's buffer.
private  int findDelimitor(byte[] buf, int off, int len)
          Searches for the delimitor in the input buffer until it reaches the end of a buffer of the delimitor is found.
private  void genBodyHeaders()
          This is our private method to parse and load object body headers into an internal private hashtable.
 String getBodyHeader(String s)
          Public accessor to specific Object Body Header.
 Enumeration getBodyHeaders()
          Public accessor to Object Body Headers and values.
 String getEncoding()
          get the character encoding set by setEncoding method.
 String getEncoding(String encoding)
          Deprecated. 

Supported API: true
 boolean hasMoreObjectBodies()
          Setup read of next object body if one is available.
private  void initDelimitorData(String delim)
           
 int read()
          Reads a byte of data.
 int read(byte[] b)
          Reads up to b.length bytes of data from this input stream into an array of bytes.
 int read(byte[] b, int off, int len)
          Reads up to len bytes of data from this MP input stream into an array of bytes.
private  String readLn()
          Reads the next line of text from the underlying input stream.
 String readString()
          Reads the remainder of the current body part into a string.
 void setEncoding(String encoding)
          Set character encoding to be returned by getEncoding method.
 long skip(long n)
          Skips bytes of input.
 
Methods inherited from class java.io.FilterInputStream
close, mark, markSupported, reset
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

versionID

private static final String versionID
See Also:
Constant Field Values

RESOURCE

private static final String RESOURCE
See Also:
Constant Field Values

delim_found

private boolean delim_found

Delimitor

private String Delimitor

BDelimitor

private byte[] BDelimitor

leading_dashes_count

private int leading_dashes_count

FinalDelimitor

private String FinalDelimitor

bodyHeaders

private Properties bodyHeaders

boundariesV

private Vector boundariesV

bVindex

private int bVindex

temp

private String temp

ibuf

private byte[] ibuf

ibufd

private int ibufd

ibuf_count

private int ibuf_count

ibuf_first

private int ibuf_first

ibuf_last

private int ibuf_last

eof

private boolean eof

ioe

private IOException ioe

encoding

private String encoding

CR

static final byte CR
See Also:
Constant Field Values

LF

static final byte LF
See Also:
Constant Field Values
Constructor Detail

MPInputStream

public MPInputStream(InputStream in,
                     String boundary)
Creates a new MPInputStream initialized with the specified input stream and object body boundary

Supported API: true

Parameters:
in - the input stream
boundary - the encapsulation boundary string
Method Detail

setEncoding

public void setEncoding(String encoding)
Set character encoding to be returned by getEncoding method. Useful if the creator of a MPInputStream want to communicate a known character encoding to a body part processing method.

Supported API: true

Specified by:
setEncoding in interface MPInputStreamIfc
Parameters:
encoding - the character encoding

getEncoding

public String getEncoding(String encoding)
Deprecated. 

Supported API: true

get the character encoding set by setEncoding method. Returns null if not encoding has been set for this MPInputStream.

Returns:
encoding the character encoding

getEncoding

public String getEncoding()
get the character encoding set by setEncoding method. Returns null if not encoding has been set for this MPInputStream.

Supported API: true

Specified by:
getEncoding in interface MPInputStreamIfc
Returns:
encoding the character encoding

hasMoreObjectBodies

public boolean hasMoreObjectBodies()
                            throws IOException
Setup read of next object body if one is available. Accomplished by checking that the encapsulation boundary at the top of the header is what we expect, generate a hashtable of the object body headers for later retrieval, and set the stream to the top of the body data for subsequent reads.

Supported API: true

Specified by:
hasMoreObjectBodies in interface MPInputStreamIfc
Throws:
IOException - is thrown if error on reading object body header(s) or encapsulation boundary doesn't match that which was passed into the constructor, of read from the boundary object body header.

Note: this method must be called and a value of true returned prior to getBodyHeaders() and/or getBodyHeader(String s) calls.


genBodyHeaders

private void genBodyHeaders()
                     throws IOException
This is our private method to parse and load object body headers into an internal private hashtable. Access to said keys and values is through the getBodyHeaders and getBodyHeader public methods. Note: this method handles filenames with imbeded spaces.

Throws:
IOException

convert

private String convert(String orig)

getBodyHeaders

public Enumeration getBodyHeaders()
Public accessor to Object Body Headers and values.

Supported API: true

Specified by:
getBodyHeaders in interface MPInputStreamIfc

getBodyHeader

public String getBodyHeader(String s)
Public accessor to specific Object Body Header.

Supported API: true

Specified by:
getBodyHeader in interface MPInputStreamIfc
Parameters:
s - string key for which to get value.

containsBodyHeader

public boolean containsBodyHeader(String s)
Public checker for specific Object Body Header.

Supported API: true

Specified by:
containsBodyHeader in interface MPInputStreamIfc
Parameters:
s - string key for which to get value.

fill_buf

private int fill_buf()
              throws IOException
This method parses out the next MIME object body binary data by looking through an internal buffer for the encapsulation boundary. Which, of course, is the boundary specified on the content-type header, immediately preceeded by a "--" sequence, as part of the boundary. A -1 is return on next fill if delim was found to signal EOF for this body.

Throws:
IOException

fill_buf

private int fill_buf(byte[] b,
                     int off)
              throws IOException
Same as no-arg fill_buf but reads directly into caller's buffer. Max length read is identical (ibuf.length) because pushback is limited.

Throws:
IOException

initDelimitorData

private void initDelimitorData(String delim)

findDelimitor

private int findDelimitor(byte[] buf,
                          int off,
                          int len)
Searches for the delimitor in the input buffer until it reaches the end of a buffer of the delimitor is found.

This method uses the fact that the delimitor is starting from a series of dashes. It attempts to sample the buffer using number of leading dashes as a sampling interval. When a dash is found, this method switches to use a simple byte comparison algorithm. If simple algorithm fails, sampling starts again.

Returns:
return index to beginning of pattern or -1

readLn

private String readLn()
               throws IOException
Reads the next line of text from the underlying input stream. This method successively reads bytes from the underlying input stream until it reaches the end of a line of text.

A line of text is terminated by a carriage return character ('\r'), a newline character ('\n'), a carriage return character immediately followed by a newline character, or the end of the input stream. The line-terminating character(s), if any, are not returned as part of the string that is returned.

This method blocks until a newline character is read, a carriage return and the byte following it are read (to see if it is a newline), the end of the stream is detected, or an exception is thrown.

Returns:
the next line of text from this input stream.
Throws:
IOException - if an I/O error occurs.

read

public final int read()
               throws IOException
Reads a byte of data. The method will block if no input is available.

Supported API: true

Specified by:
read in interface MPInputStreamIfc
Returns:
the byte read, or -1 if the end of the stream is reached.
Throws:
IOException - If an I/O error has occurred. We are overriding this to return 0 bytes for now. Should just call read (byte[], 0, 1)...maybe?

read

public final int read(byte[] b)
               throws IOException
Reads up to b.length bytes of data from this input stream into an array of bytes.

The read method of MPInputStream calls the read method of three arguments with the arguments b, 0, and b.length.

Supported API: true

Specified by:
read in interface MPInputStreamIfc
Parameters:
b - the buffer into which the data is read.
Returns:
the total number of bytes read into the buffer, or -1 is there is no more data because the end of the stream has been reached.
Throws:
IOException - if an I/O error occurs.
Since:
JDK1.0
See Also:
InputStream.read(byte[], int, int)

read

public final int read(byte[] b,
                      int off,
                      int len)
               throws IOException
Reads up to len bytes of data from this MP input stream into an array of bytes. This method blocks until some input is available.

This read method of MPInputStream reads bytes out of an internal buffer.

Supported API: true

Specified by:
read in interface MPInputStreamIfc
Parameters:
b - the buffer into which the data is read.
off - the start offset of the data.
len - the maximum number of bytes read.
Returns:
the total number of bytes read into the buffer, or -1 if there is no more data because the end of the object body has been reached.
Throws:
IOException - if an I/O error occurs.

skip

public long skip(long n)
          throws IOException
Skips bytes of input.

Supported API: true

Specified by:
skip in interface MPInputStreamIfc
Parameters:
n - bytes to be skipped
Returns:
actual number of bytes skipped
Throws:
IOException - If an I/O error has occurred.

available

public int available()
Returns the number of bytes that can be read without blocking. Returns number of bytes body bytes already read into local buffer.

Supported API: true

Specified by:
available in interface MPInputStreamIfc
Returns:
number of bytes available

readString

public String readString()
                  throws IOException
Reads the remainder of the current body part into a string.

Supported API: true

Specified by:
readString in interface MPInputStreamIfc
Returns:
String read using the encoding set for this stream
Throws:
IOException - if an I/O error occurs.