Date: 2005-03-11T09:10:32 Editor: DakotaJack Wiki: Apache Struts Wiki Page: StrutsUpload URL: http://wiki.apache.org/struts/StrutsUpload
no comment Change Log: ------------------------------------------------------------------------------ @@ -1,78 +1,14 @@ == Overview == -Utilizing the sort of structure suggested for Struts upload below allows us to have an !ActionUpload class as follows: +Presently the Struts code does the following: (1) wrap the request in a multipart request that has to be continually unwrapped prior to use and prior to being initialized anyway; (2) parse the request inside the population of the !ActionForm, i.e. in !RequestUtils. -(This is actual code used in a working application online.) +This is excellent, since the deferment of anything substantial until !RequestUtils allows the Struts Team, should you choose to take this assignment, the opportunity to make Struts v1.3 accessible to people wanting to build upload applications. -{{{ -public class UploadAction - extends Action { - public ActionForward execute(ActionMapping mapping, - ActionForm form, - HttpServletRequest req, - HttpServletResponse res) - throws Exception { - HttpSession sess = req.getSession(); - Upload upload = (Upload)sess.getAttribute(UploadConstant.UPLOAD); - if(upload == null) { - upload = new Upload(); - sess.setAttribute(UploadConstant.UPLOAD,upload); - } - if(upload.isMultipart(req)) { - Monitor progress = (UploadMonitorProgress)sess.getAttribute(UploadConstant.MONITOR); - if(progress == null) { - progress = new UploadMonitorProgress(); - sess.setAttribute(UploadConstant.MONITOR,progress); - } - List monitors = Collections.synchronizedList(new LinkedList()); - int size = UploadConstant.MAX_FILE_SIZE; - int type = UploadConstant.DIR; - String path = LoadFileUtil.getUploadPath(type,user.getId()); - String temp = LoadFileUtil.UPLOAD_TEMP_FILES; - String code = UploadConstant.DEFAULT_ENCODING; - monitors.add(progress); - upload.process(req,monitors,code,size); - upload.store(type, path, temp); - sess.setAttribute(UploadConstant.REPORT,UploadReport.getReport(upload)); - } - return new ActionForward(...);; - } -} -}}} +As things stand, you have to change Struts to build an upload application with any sophistication. Making Struts more flexible is rather easy. Just use the following three interfaces. -The point of this presentation is not the classes given. The point is that I am would hope that the committers working on the Struts multipart processing would make some attempt to provide a basis for applications other than the Struts upload package. These classes are not meant to be that basis, other than the so-called "Framework Code" given below. +An example of how someone might want to use these interfaces is also given following the interfaces. -This is about Struts v1.2.6 and forward multipart requests. The first four classes/interfaces are suggested as a basis for allowing Struts users/developers to implement their own file upload applications. The object of suggesting these classes is to make the use of !ActionForm available to users/developers who want to do something more than the present default file upload application packaged with Struts allows but maintaining backward compatibility. I assume that those committers working on the upload package can see how these classes could be seemlessly applied to Struts without disturbing expectations of prior users. - -The last three classes following the four main classes are example implementations of the first three interfaces and the !MultipartUtil. Any comments or suggestions are welcomed. - -After the seven classes a few classes to indicate what sorts of applications/implementations the seven classes would make possible are provided. All the classes following the first four classes are not meant to be part of the framework. If the example class Upload is studied, you will see that this class is totally ignorant of the view or the data coming from the multipart form. This is good. You will also see that, if the first four classes were part of the framework, the Upload class would also be totally ignorant of the request. This would be idea. As things stand, since non-Struts upload applications have no access to the !ActionForm, the Upload application has to have some hook to the framework to get the data for the view. This is what ideally we would like to avoid. - -I do use this application and others like it, but the point here is to see the flexibility that classes like the first four classes can give us. The important classes, the first three, are interfaces with "eXtremely" (pun intended) generic methods. Please note how easy the Upload class is to use. By having the flexibility to do what we need in the setup classes, the facade, the Upload class, is a piece of cake for the developer. - -=== Framework Code === - - 1. !MultipartFile - 2. !MultipartData - 3. !MultipartHandler - -=== Framework Code Sample Implementation === - - 1. !UploadMultipartFile (implements !MultipartFile) - 2. !UploadMultipartData (implements !MultipartData) - 3. !UploadMultipartHandler (implements !MultipartHandler) - 4. !MultipartUtil - -=== Sample Application Code Pieces (without interfaces to Action class*) === - - 1. !UploadOutputStream (extends org.apache.commons.fileupload.!DeferredFileOutputStream) - 2. !UploadFileItem (implements org.apache.commons.fileupload.!FileItem) - 3. !UploadFileItemFactory (extends org.apache.commons.fileupload.!DefaultFileItemFactory) - 4. Monitor - 5. Upload - 6. !UploadParams - -== Code == +If the Struts Team wants to stay with the present idea of providing a multipart request to the Action for backwards compatibility, then this can be achieved by populating both such a request, which is really useless, and a !MultipartData class. === Framework Code === @@ -712,503 +648,7 @@ } }}} -==== Monitor ==== - -{{{ -public interface Monitor { - public void init(File tempFile, int contentLength, String contentType); - public void read(int contentLength); - public void notify(UploadParams uploadParams, MultipartFile uploadFile); -} -}}} - -==== Upload ==== - -{{{ -public class Upload { - private MultipartData data; - - private List monitors = Collections.synchronizedList(new LinkedList()); - private List history = Collections.synchronizedList(new LinkedList()); - - private List excludedExts = Collections.synchronizedList(new LinkedList()); - private List includedExts = Collections.synchronizedList(new LinkedList()); - private boolean isExcludedExts = true; - - private String storeLocation; - private int storeType = 0; - private List storeMemory = Collections.synchronizedList(new LinkedList()); - - private int maxFileNumber = UploadConstant.MAX_FILE_NUMBER; - private long maxFileSize = 0x100000000L; - - private boolean overwrite = true; - - public Upload() {} - - public int getStoreType() { return storeType; } - public List getStoreMemory() { return storeMemory; } - public String getStoreLocation() { return storeLocation; } - - public boolean isExcludedExts() { return isExcludedExts; } - public long getFileSizeLimit() { return maxFileSize; } - public boolean getOverwrite() { return overwrite; } - public int getMaxFiles() { return maxFileNumber; } - public String getSystemTempDir() { return UploadConstant.SYSTEM_TEMPDIR; } - public List getHistory() { return history; } - - public boolean isMultipart(HttpServletRequest req) { - return MultipartUtil.isMultipartFormData(req); - } - - public Iterator getParameterNames() { - return data.getParameterNames(); - } - - public void process(HttpServletRequest req, - List monitors, - String encoding, - int maxFileSize) - throws UploadException, - IOException { - this.monitors = monitors; - data = new UploadMultipartData(req,monitors,UploadConstant.DEFAULT_ENCODING,UploadConstant.MAX_FILE_SIZE); - } - - public void store(int storeType, - String storeLocation, - String tmpPath) // location null if memory - throws UploadException, - IOException { - setStore(storeType,storeLocation); - setStoreTmpDir(tmpPath); - Map files = data.getFiles(); - Iterator iter = files.keySet().iterator(); - String fileName; - MultipartFile multipartFile; - - while(iter.hasNext()) { - fileName = (String)iter.next(); - multipartFile = (MultipartFile)files.get(fileName); - - if(storeType == UploadConstant.DIR && storeLocation != null) { - folder(multipartFile); - } else if(storeType == UploadConstant.ZIP && storeLocation != null) { - zip(multipartFile); - } else if(storeType == UploadConstant.MEM && storeMemory != null) { - memory(multipartFile); - } else { - throw new UploadException(UploadConstant.STORE_NOT_SET); - } - } - } - - public void setMaxFiles(int maxFileNumber) { this.maxFileNumber = maxFileNumber; } - public void setFileSizeLimit(long maxFileSize) { this.maxFileSize = maxFileSize; } - public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; } - - public void setExcludedExts(String exts) { - StringTokenizer st = new StringTokenizer(exts, ","); - while(st.hasMoreElements()) { - excludedExts.add(st.nextElement()); - } - isExcludedExts = true; - } - - public void setIncludedExts(String exts) { - StringTokenizer st = new StringTokenizer(exts, ","); - - while(st.hasMoreElements()) { - includedExts.add(st.nextElement()); - } - - isExcludedExts = false; - } - - public String getExcludedExts() { - StringBuffer sb = new StringBuffer(); - Iterator iter = excludedExts.iterator(); - boolean first = true; - - while(iter.hasNext()) { - if(first) { - sb.append((String)iter.next()); - first = false; - } - sb.append(","); - sb.append((String)iter.next()); - } - - return sb.toString(); - } - - public String getIncludedExts() { - StringBuffer sb = new StringBuffer(); - Iterator iter = includedExts.iterator(); - boolean first = true; - - while(iter.hasNext()) { - if(first) { - sb.append((String)iter.next()); - first = false; - } - sb.append(","); - sb.append((String)iter.next()); - } - - return sb.toString(); - } - - public void clear() - throws UploadException, - IOException { - if(storeType == UploadConstant.DIR && storeLocation != null) { - File file = new File(storeLocation + UploadConstant.SEPARATOR); - - if(file.exists()) { - if(!file.canWrite()) { - throw new UploadException(UploadConstant.READ_ONLY); - } - - File files[] = file.listFiles(); - - if(files != null) { - for(int i = 0; i < files.length; i++) { - if(!files[i].delete()) { - throw new UploadException(UploadConstant.CANNOT_DELETE); - } - } - } - - setStore(UploadConstant.DIR,storeLocation); - history.clear(); - } - } else if(storeType == UploadConstant.ZIP && storeLocation != null) { - File file = new File(storeLocation); - - if(!file.delete()) { - throw new UploadException(UploadConstant.CANNOT_DELETE); - } - - setStore(UploadConstant.ZIP,storeLocation); - history.clear(); - } else if(storeType == UploadConstant.MEM && storeMemory != null) { - Iterator iter = storeMemory.iterator(); - while(iter.hasNext()) { - ((MultipartFile)iter.next()).reset(); - } - - storeMemory.clear(); - history.clear(); - } - } - - //---------------------- UTILITY METHODS ---------------------- - - private void setStore(int storeType, - String storeLocation) // location null if memory - throws UploadException, - IOException { - if(storeType == UploadConstant.MEM) { - this.storeType = storeType; - } else if(storeType == UploadConstant.DIR) { - this.storeType = storeType; - this.storeLocation = storeLocation; - File file = new File(storeLocation + UploadConstant.SEPARATOR); - if(file.exists()) { - if(!file.canWrite()) { - throw new UploadException(UploadConstant.READ_ONLY); - } - } else if(!file.mkdirs()) { - throw new UploadException(UploadConstant.CANNOT_CREATE); - } - } else if(storeType == UploadConstant.ZIP) { - this.storeType = storeType; - this.storeLocation = storeLocation; - File file = new File(storeLocation); - this.storeLocation = storeLocation; - if(!file.exists()) { - FileOutputStream fos = new FileOutputStream(storeLocation); - ZipOutputStream zos = new ZipOutputStream(fos); - zos.putNextEntry(new ZipEntry(UploadConstant.BLANK)); - zos.closeEntry(); - zos.close(); - fos.close(); - } - } else { - throw new UploadException(UploadConstant.NONEXISTING_TYPE); - } - } - private void setStoreTmpDir(String tmpPath) { - if(tmpPath != null) { - File file = new File(tmpPath); - - if(!file.exists()) { - file.mkdirs(); - } - } - } - - private void folder(MultipartFile uploadFile) - throws UploadException, - IOException { - if(uploadFile != null && - uploadFile.getName() != null && - !uploadFile.getName().equals("") && - uploadFile.getSize() >= 0L) { - if(uploadFile.getSize() > maxFileSize) { - throw new UploadException(UploadConstant.UPLOAD_FILE_SIZE_LIMIT_REACHED + " " + uploadFile.getName()); - } - - File directory = new File(getStoreLocation() + UploadConstant.SEPARATOR); - File files[] = directory.listFiles(); - int numberOfFiles = files.length; - boolean isSameName = false; - - for(int j = 0; j < numberOfFiles; j++) { - if(files[j].getName().equals(uploadFile.getName())) { - isSameName = true; - } - } - - if(maxFileNumber == UploadConstant.MAX_FILE_NUMBER || numberOfFiles < maxFileNumber) { - if(extBarred(uploadFile.getName())) { - UploadParams uploadParams = new UploadParams(uploadFile.getName(),"upload.failure", uploadFile.getSize(), uploadFile.getContentType(), "directory", null, null); - uploadFile.getInputStream().close(); - history.add(uploadParams); - notify(uploadParams, uploadFile); - } else { - FileOutputStream fos = null; - String overwriteFileName = null; - - if(!isSameName) { - fos = new FileOutputStream(getStoreLocation() + UploadConstant.SEPARATOR + uploadFile.getName()); - } else if(!overwrite) { - overwriteFileName = uploadFile.getName() + ".overwrite." + new Date().getTime(); - fos = new FileOutputStream(getStoreLocation() + UploadConstant.SEPARATOR + overwriteFileName); - } else { - fos = new FileOutputStream(getStoreLocation() + UploadConstant.SEPARATOR + uploadFile.getName()); - } - - InputStream is = uploadFile.getInputStream(); - - if(is != null) { - byte streamData [] = new byte[UploadConstant.BUFFER_SIZE]; - - for(int i = 0; (i = is.read(streamData)) != -1;) { - fos.write(streamData, 0, i); - } - } - - fos.close(); - is.close(); - UploadParams uploadParams = new UploadParams(uploadFile.getName(),"upload.success",uploadFile.getSize(), uploadFile.getContentType(), "directory", storeLocation, overwriteFileName); - history.add(uploadParams); - notify(uploadParams, uploadFile); - } - } else { - throw new UploadException(UploadConstant.UPLOAD_LIMIT_REACHED); - } - } - } - - private void zip(MultipartFile uploadFile) - throws UploadException, - IOException { - if(uploadFile.getName() != null && !uploadFile.getName().equals("") && uploadFile.getSize() >= 0L) { - if(uploadFile.getSize() > maxFileSize) { - throw new UploadException(UploadConstant.UPLOAD_FILE_SIZE_LIMIT_REACHED + " " + uploadFile.getName()); - } - if(extBarred(uploadFile.getName())) { - UploadParams uploadParams = new UploadParams(uploadFile.getName(),"upload.failure", uploadFile.getSize(), uploadFile.getContentType(), "directory", null, null); - uploadFile.getInputStream().close(); - history.add(uploadParams); - notify(uploadParams, uploadFile); - } else { - UploadStore uploadStore = UploadStore.getInstance(); - String altFileName = uploadStore.addEntry(uploadFile, overwrite, storeLocation, maxFileNumber); - UploadParams uploadParams = new UploadParams(uploadFile.getName(),"upload.success", uploadFile.getSize(), uploadFile.getContentType(), "zip", storeLocation, altFileName); - history.add(uploadParams); - notify(uploadParams, uploadFile); - } - } - } - - private void memory(MultipartFile uploadFile) - throws UploadException, - IOException { - if(uploadFile.getName() != null && !uploadFile.getName().equals("") && uploadFile.getSize() >= 0L) { - if(uploadFile.getSize() > maxFileSize) { - throw new UploadException(UploadConstant.UPLOAD_FILE_SIZE_LIMIT_REACHED + " " + uploadFile.getName()); - } - if(extBarred(uploadFile.getName())) { - UploadParams uploadParams = new UploadParams(uploadFile.getName(),"upload.failure", uploadFile.getSize(), uploadFile.getContentType(), "directory", null, null); - uploadFile.getInputStream().close(); - history.add(uploadParams); - notify(uploadParams, uploadFile); - } else if(maxFileNumber != UploadConstant.MAX_FILE_NUMBER && storeMemory.size() >= maxFileNumber) { - UploadParams uploadParams = new UploadParams(uploadFile.getName(),"upload.too_many_files", uploadFile.getSize(), uploadFile.getContentType(), "directory", null, null); - uploadFile.getInputStream().close(); - history.add(uploadParams); - notify(uploadParams, uploadFile); - } else { - storeMemory.add(uploadFile); - UploadParams uploadParams = new UploadParams(uploadFile.getName(),"upload.success", uploadFile.getSize(), uploadFile.getContentType(), "memory", UploadConstant.MEMORY, null); - history.add(uploadParams); - notify(uploadParams, uploadFile); - } - } - } - - private void notify(UploadParams uploadParams, - MultipartFile uploadFile) { - Iterator iter = monitors.iterator(); - while(iter.hasNext()) { - ((Monitor)iter.next()).notify(uploadParams,uploadFile); - } - } - - private void setStoreType(int storeType) - throws UploadException { - if(storeType == UploadConstant.MEM || - storeType == UploadConstant.DIR || - storeType == UploadConstant.ZIP) { - this.storeType = storeType; - } else { - throw new UploadException(UploadConstant.NONEXISTING_TYPE); - } - } - - private boolean extBarred(String fileName) { - if(isExcludedExts) { - return checkExcludedExts(fileName); - } - return !checkIncludedExts(fileName); - } - - private boolean checkExcludedExts(String fileName) { - boolean excluded = false; - Iterator iter = excludedExts.iterator(); - int i = fileName.lastIndexOf("."); - String extFile = null; - if(i != -1) { - extFile = fileName.substring(i + 1, fileName.length()); - while(iter.hasNext()) { - String ext = (String)iter.next(); - if(ext.equalsIgnoreCase(extFile)) { - return excluded = true; - } - } - } else { - return excluded = false; - } - return excluded = false; - } - - private boolean checkIncludedExts(String fileName) { - boolean included = false; - Iterator iter = includedExts.iterator(); - int i = fileName.lastIndexOf("."); - String extFile = null; - if(i != -1) { - extFile = fileName.substring(i + 1, fileName.length()); - while(iter.hasNext()) { - String ext = (String)iter.next(); - if(ext.equalsIgnoreCase(extFile)) { - return included = true; - } - } - } else { - return included = true; - } - return included = false; - } -} -}}} - -==== UploadParams ==== - -{{{ -public class UploadParams - implements Serializable { - - private String fileName; - private String uploadStatus; - private long fileSize; // file size - private String contentType; - private String filePath; // store location - private String storeType; // store storeType - private String overwriteFileName; - private String fileExt; - private String overwriteFileExt; - - public UploadParams(String fileName, - String uploadStatus, - long fileSize, - String contentType, - String storeType, - String filePath, - String overwriteFileName) { - this.fileName = fileName; - this.uploadStatus = uploadStatus; - this.fileSize = fileSize; - this.contentType = contentType; - this.storeType = storeType; - this.filePath = filePath; - this.overwriteFileName = overwriteFileName; - - if(fileName != null) { - int j = fileName.lastIndexOf("."); - if(j != -1) - fileExt = fileName.substring(j + 1, fileName.length()); - } - - if(overwriteFileName != null) { - int k = overwriteFileName.lastIndexOf("."); - if(k != -1) { - overwriteFileExt = overwriteFileName.substring(k + 1, overwriteFileName.length()); - } - } - } - - public String getContentType() { - return contentType; - } - - public String getFileExt() { - return fileExt; - } - - public String getFileName() { - return fileName; - } - - public String getFilePath() { - return filePath; - } - - public long getFileSize() { - return fileSize; - } - - public String getOverwriteFileExt() { - return overwriteFileExt; - } - - public String getOverwriteFileName() { - return overwriteFileName; - } - - public String getStoreType() { - return storeType; - } - - public String getUploadStatus() { - return uploadStatus; - } -} -}}} ----- --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]