Hi, Mike,
I respond to your thoughts within. I am not creating a proposal, perhaps I should say. I am just trying to find a clean way to implement a file upload application.
Mike Stanley wrote:
UploadFileItem merely decorates FileItem. All I needed was that. I add the I do use DiskFileUpload to parse, which is a pre-existing commons extension of the FileUploadBase. The parsing in DiskFileUpload, utilizing FileUploadBase, returns an ArrayList of FileItems. Further, DefaultFileItem and DefaultFileItemFactory already provide the implementations needed by FileUploadBase. Notice too that, when you get FileItem, you get a choice of calling either get or getInputStream, depending on whether you want to process the whole file in ram or to process the file incrementally. UploadFileItem reads the input stream into a buffered input stream and, if UploadFileItem were an extension of FileItem instances (is that what you mean?), how would you do:Hi Michael,
I don't understand you're proposal. FileItem (from commons upload) is
an interface with a factory. FileUploadBase (the parser) is abstract
with different implementations. Why would you wrap the interface
instead of simply creating a new concrete implementation of the above
mentioned classes?
* public InputStream getInputStream() { if(fi == null) { return null; }
InputStream is = null; try { is = new BufferedInputStream(fi.getInputStream()); } catch (IOException ioe) { StdOut.log("log.error",ioe.getMessage()); } return is; } * Am I reading you right here?
Commons upload does suit my needs. The difficulty I have is that Struts provides its own implementation of commons upload which then is welded to ActionForm, leaving other implementations cut off from using ActionForm, because, if you use ActionForm, you automatically have to buy into the Struts upload application in the sense that you at least have to implement the interface MultipartRequestHandler. Since I want an implementation of a handler that incorporates not only HttpServletRequest but also a vector of upload listeners, the file size limit, various parameters, a hashtable to hold the files, a temporary folder path for the files, and an encoding, how this can be jury-rigged or made to work is not clear.In addition, I'm not sure I understand the dilemma of any of this. If commons-upload didn't suite your needs, you could easy create an abstract Action for multipart forms that is similar to the following:
public abstract MyMultipartActionSupport extends Action
{
public final execute(mapping, form, request, response)
{ // parse request into MyFileItems
List items = MyParser.parse(request);
executeWithFileItems(mapping, form, request, response, items);
}
public abstract executeWithFileItems(mapping, form, request, response, items);
}
This allows you to still use Struts Actions and use anything you want to
parse the multipart form. Remember the FileItem / Upload packages are
convenience wrappers around parsing this stuff from the request. You
could even get crazy and add the special "file upload parser"
implementation class name to your action config parameter, giving you
all the flexibility you dreamed.
What you suggest with Action is clearly possible. This means, however, that I won't be able to use the ActionForm without either rewriting ActionForm to decouple the multipart request handling or to figure out how to rewrite my application with a jury-rigged MultipartRequestHandler interface. I have been considering looking into whether or not I can use an adaptor that just shuts off any use of the MultipartRequestHandler, so that the upload file data is not grabbed. Then, if this is feasible, I can implement my application through my ActionForm subclass. I don't think this will work, but I am looking into the possibility. If so, that might be okay.
I don't want to do anything that commons file upload does not give me in terms of the basic functionality, other than buffering the input stream, of course. I do have an Upload class that manages an UploadData class that utilizes UploadFileItem and UploadParser. I also have an UploadBin class that lets me implement various respository solutions (folders, files, zips, xml, etc.) for files. I also have an UploadMonitor class that lets me incorporate file listening.But perhaps I'm missing something.
- Mike
P.S. What would you want to do that the commons file upload doesn't give you?
I hope this answers your question. Perhaps Struts 1.3 will offer a design that will allow alternative parsing designs to utilize ActionForm without these machinations.
Michael McGrady
On Tue, 2004-10-05 at 03:20, Michael McGrady wrote:
For anyone interested in an option, what I would like to do is given below. Anyone have any suggestions on the best way to do this and still use ActionForm, short of rewriting ActionForm? Thanks for any assistance. (The UploadFileItem is just a simple Serialized wrapper of commons' FileItem. This wrapper utilizes a buffered input stream.)
public class UploadParser {
public UploadParser() { }
public void parse(HttpServletRequest req, Vector uploadListeners, int fileSizeLimit, Hashtable parameters, Hashtable files, String tmpFolder, String encoding) throws IOException { DiskFileUpload dfu = new DiskFileUpload(); dfu.setSizeMax(fileSizeLimit); dfu.setSizeThreshold(UploadConstant.MEMORY_BUFFER_SIZE); dfu.setRepositoryPath(tmpFolder); if(encoding != null) { dfu.setHeaderEncoding(encoding); } List list = null; try { list = dfu.parseRequest(req); } catch(FileUploadException fue) { throw new IOException(fue.getMessage()); } Object obj = null; for(Iterator iter = list.iterator(); iter.hasNext();) { FileItem fi = (FileItem)iter.next(); String fieldName = fi.getFieldName(); if(fi.isFormField()) { String holder = null; if(encoding != null) { holder = fi.getString(encoding); } else { holder = fi.getString(); } Vector params = (Vector)parameters.get(fieldName); if(params == null) { params = new Vector(); parameters.put(fieldName, params); } params.addElement(holder); } else { String fin = fi.getName();
if(fin != null) { UploadFileItem ufi = new UploadFileItem(fi); fin = fin.replace('\\', '/'); int j = fin.lastIndexOf("/"); if(j != -1) { fin = fin.substring(j + 1, fin.length()); } ufi.setFileName(fin); ufi.setContentType(fi.getContentType()); ufi.setFileSize(fi.getSize()); files.put(fieldName, ufi); } } } } }
public class UploadFileItem implements Serializable { private FileItem fi; private String contentType; private String fileName; private long fileSize;
public UploadFileItem() { this.fi = null; } public UploadFileItem(FileItem fi) { this.fi = fi; }
public FileItem getFileItem() { return fi; } public long getFileSize() { return fileSize; } public String getFileName() { return fileName; } public String getContentType() { return contentType; }
public void setFileSize(long fileSize) { this.fileSize = fileSize; } public void setFileName(String fileName) { this.fileName = fileName; } public void setContentType(String contentType) { this.contentType = contentType; }
public InputStream getInputStream() { if(fi == null) { return null; }
InputStream is = null; try { is = new BufferedInputStream(fi.getInputStream()); } catch (IOException ioe) { StdOut.log("log.error",ioe.getMessage()); } return is; }
public byte[] getData() { InputStream is = getInputStream(); if(is != null) { int i = (int)getFileSize(); if(i > 0) { byte data[] = new byte[i]; try { is.read(data); is.close(); } catch(IOException ioe) { } return data; } else { return null; } } else { return null; } }
public void reset() {
if(fi != null) {
fi.delete();
}
}
}