// // $Id: DefaultFileData.java 267 2007-06-08 13:42:02 +0000 (ven., 08 juin 2007) // felfert $ // // jupload - A file upload applet. // Copyright 2007 The JUpload Team // // Created: 2006-04-21 // Creator: etienne_sf // Last modified: $Date: 2008-04-16 00:58:02 -0700 (Wed, 16 Apr 2008) $ // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 2 of the License, or (at your option) any later // version. This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, Inc., // 675 Mass Ave, Cambridge, MA 02139, USA. package wjhk.jupload2.filedata; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.text.NumberFormat; import java.util.Date; import java.util.Properties; import java.util.regex.Pattern; import java.util.regex.Matcher; import wjhk.jupload2.exception.JUploadException; import wjhk.jupload2.exception.JUploadExceptionTooBigFile; import wjhk.jupload2.exception.JUploadIOException; import wjhk.jupload2.policies.DefaultUploadPolicy; import wjhk.jupload2.policies.UploadPolicy; import wjhk.jupload2.upload.helper.ByteArrayEncoder; /** * This class contains all data and methods for a file to upload. The current * {@link wjhk.jupload2.policies.UploadPolicy} contains the necessary parameters * to personalize the way files must be handled. <BR> * <BR> * This class is the default FileData implementation. It gives the default * behaviour, and is used by {@link DefaultUploadPolicy}. It provides standard * control on the files choosen for upload. * * @see FileData * @author etienne_sf */ public class DefaultFileData implements FileData { /* keep track of all of the files we've seen */ private static int numberOfFileData = 0; /** * The current upload policy. */ UploadPolicy uploadPolicy; /** * the mime type list, coming from: http://www.mimetype.org/ Thanks to them! */ public static Properties mimeTypes = null; // /////////////////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////// Protected attributes // ///////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Mime type of the file. It will be written in the upload HTTP request. */ protected String mimeType = "application/octet-stream"; // /////////////////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////// Private attributes // //////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////////////////// /** * file is the file about which this FileData contains data. */ private File file; /** * Cached file size */ private long fileSize; /** * Cached file directory */ private String fileDir; /** * cached root of this file */ private String fileRoot = ""; /** * Cached file modification time. */ private Date fileModified; /** * Indicates whether the applet can read this file or not. */ private Boolean canRead = null; private int ext_index = 0; private String ext_id = ""; /* * status for the file, set by methods using the file */ private int status = 0; public int status() { return this.status; } public int setStatus(int mstatus) { this.status = mstatus; return this.status; } /** * Standard constructor * * @param file The file whose data this instance will give. * @param root The directory root, to be able to calculate the result of * {@link #getRelativeDir()} * @param uploadPolicy The current upload policy. */ public DefaultFileData(File file, File root, UploadPolicy uploadPolicy) { this.file = file; this.uploadPolicy = uploadPolicy; this.fileSize = this.file.length(); this.fileDir = this.file.getAbsoluteFile().getParent(); this.fileModified = new Date(this.file.lastModified()); this.status = 0; this.ext_index = DefaultFileData.numberOfFileData; this.ext_id = "File_"+this.ext_index; DefaultFileData.numberOfFileData++; if (null != root) { this.fileRoot = root.getAbsolutePath(); uploadPolicy.displayDebug("Creation of the DefaultFileData for " + file.getAbsolutePath() + "(root: " + root.getAbsolutePath() + ")", 20); } else { uploadPolicy.displayDebug("Creation of the DefaultFileData for " + file.getAbsolutePath() + "(root: null)", 20); } // Let's load the mime types list. if (mimeTypes == null) { mimeTypes = new Properties(); final String mimetypePropertiesFilename = "/conf/mimetypes.properties"; try { /* * mimeTypes.load(getClass().getResourceAsStream( * mimetypePropertiesFilename)); */ mimeTypes.load(Class.forName("wjhk.jupload2.JUploadApplet") .getResourceAsStream(mimetypePropertiesFilename)); uploadPolicy.displayDebug("Mime types list loaded Ok (" + mimetypePropertiesFilename + ")", 50); } catch (Exception e) { uploadPolicy.displayWarn("Unable to load the mime types list (" + mimetypePropertiesFilename + "): " + e.getClass().getName() + " (" + e.getMessage() + ")"); } } // Let this.mimeType = mimeTypes.getProperty(getFileExtension().toLowerCase()); if (this.mimeType == null) { this.mimeType = "application/octet-stream"; } } public static String human_readable_file_size(long fsize) { String suffix; double val; val = fsize; suffix = " bytes."; if (fsize<1024) { suffix = " Bytes"; val = (double)fsize; } else if (fsize <1024*1024) { suffix = " KB"; val = (double)fsize/1024; } else if (fsize < 1024*1024*1024) { suffix = " MB"; val = (double)fsize/(1024*1024); } else if (fsize < 1024*1024*1024) { suffix = " GB"; val = (double)fsize/(1024*1024*1024); } String s = Double.toString(val); int n1 = s.indexOf('.'); int n2 = s.length() - n1 - 1; if (n2>2 && n1>0) s = s.substring(0,n1+2+1); return s + suffix; } /** {@inheritDoc} */ public void appendFileProperties(ByteArrayEncoder bae) throws JUploadIOException { bae.appendFileProperty("mimetype[]", getMimeType()); bae.appendFileProperty("pathinfo[]", getDirectory()); bae.appendFileProperty("relpathinfo[]", getRelativeDir()); // To add the file datetime, we first have to format this date. SimpleDateFormat dateformat = new SimpleDateFormat(uploadPolicy .getDateFormat()); String uploadFileModificationDate = dateformat .format(getLastModified()); bae.appendFileProperty("filemodificationdate[]", uploadFileModificationDate); } /** {@inheritDoc} */ public void beforeUpload() throws JUploadException { // Default : we check that the file is smaller than the maximum upload // size. String cmd; if (getUploadLength() > this.uploadPolicy.getMaxFileSize()) { // TODO do the error callback here // uploadError(-110, "File size is too large (Maximum:"+human_readable_file_size(this.uploadPolicy.getMaxFileSize())+")"); throw new JUploadExceptionTooBigFile(getFileName(), getUploadLength(), this.uploadPolicy); } } public String external_id() { return this.ext_id; } public int external_index() { return this.ext_index; } /** {@inheritDoc} */ public long getUploadLength() throws JUploadException { return this.fileSize; } /** {@inheritDoc} */ public void afterUpload() { // Nothing to do here } /* fire the uploadComplete back to Javascript */ public void uploadStart() { String cmd; if (null != (cmd = this.uploadPolicy.getCallBackString(UploadPolicy.PROP_CALLBACK_FILE_UPLOAD_START))) { // callback to javascript... String cmd_string = cmd; this.uploadPolicy.displayWarn("uploadStart - CMD - " + cmd_string); try { String[] args = { this.getJSON() }; this.uploadPolicy.performCallback(cmd_string,args,true); // instance call } catch (JUploadException e) { this.uploadPolicy.displayErr(e); } } } public void uploadComplete() { String cmd; if (null != (cmd = this.uploadPolicy.getCallBackString(UploadPolicy.PROP_CALLBACK_FILE_UPLOAD_COMPLETE))) { // callback to javascript... String cmd_string = cmd; this.uploadPolicy.displayWarn("uploadComplete - CMD - " + cmd_string); try { String[] args = { this.getJSON() }; this.uploadPolicy.performCallback(cmd_string,args,true); // instance call } catch (JUploadException e) { this.uploadPolicy.displayErr(e); } } } public void uploadProgress(Long bytes_complete, Long total_bytes) { String cmd; if (null != (cmd = this.uploadPolicy.getCallBackString(UploadPolicy.PROP_CALLBACK_FILE_UPLOAD_PROGRESS))) { // callback to javascript... String cmd_string = cmd; this.uploadPolicy.displayWarn("uploadProgress - CMD - " + cmd_string); try { String[] args = { this.getJSON(), bytes_complete.toString(), total_bytes.toString() }; this.uploadPolicy.performCallback(cmd_string,args,true); // instance call } catch (JUploadException e) { this.uploadPolicy.displayErr(e); } } } /* fire upload Success back to javascript */ public void uploadSuccess(String server_response) { String cmd; if (null != (cmd = this.uploadPolicy.getCallBackString(UploadPolicy.PROP_CALLBACK_FILE_UPLOAD_SUCCESS))) { // callback to javascript... String cmd_string = cmd; this.uploadPolicy.displayWarn("uploadSuccess callback - CMD - " + cmd_string); try { String[] args = { this.getJSON(), '"'+server_response+'"' }; this.uploadPolicy.performCallback(cmd_string,args,true); // instance call } catch (JUploadException e) { this.uploadPolicy.displayErr(e); } } } /* fire upload error back to javascript */ public void uploadError(Integer error_code, String message) { String cmd; if (null != (cmd = this.uploadPolicy.getCallBackString(UploadPolicy.PROP_CALLBACK_FILE_UPLOAD_ERROR))) { // callback to javascript... String cmd_string = cmd; this.uploadPolicy.displayWarn("uploadError callback - CMD - " + cmd_string); try { String[] args = { this.getJSON(), error_code.toString(), '"'+message+'"' }; this.uploadPolicy.performCallback(cmd_string,args,true); // instance call } catch (JUploadException e) { this.uploadPolicy.displayErr(e); } } } /** {@inheritDoc} */ public InputStream getInputStream() throws JUploadException { // Standard FileData : we read the file. try { return new FileInputStream(this.file); } catch (FileNotFoundException e) { throw new JUploadIOException(e); } } /** {@inheritDoc} */ public String getFileName() { return this.file.getName(); } /** {@inheritDoc} */ public String getFileExtension() { return getExtension(this.file); } /** {@inheritDoc} */ public long getFileLength() { return this.fileSize; } /** {@inheritDoc} */ public Date getLastModified() { return this.fileModified; } /** {@inheritDoc} */ public String getDirectory() { return this.fileDir; } /** {@inheritDoc} */ public String getMimeType() { return this.mimeType; } /** * {@inheritDoc} */ private String sanitize(String str){ String s,patt="[\\p{Cntrl}]"; Pattern r = Pattern.compile(patt); Matcher m = r.matcher(str); s = m.replaceAll("_"); return s.replaceAll("'", "\\\\'"); /* single quote gets prefixed with slash */ } public String getJSON() { String json_obj; String reldir = this.getRelativeDir().replaceAll("\\\\", "/"); // normalize to forward slash... /* TODO creation_date, modification_date, filestatus */ json_obj = "{ id : '" + this.ext_id + "', " + " index : " + this.ext_index + ", " + " name : '" + sanitize(this.getFileName()) + "'," + " size : " + this.fileSize + "," + " type : '" + sanitize(this.getFileExtension()) + "'," + " relative_path : '" + sanitize(reldir) + "'," + " filestatus : "+ this.status + " } "; return json_obj; } /** {@inheritDoc} */ public boolean canRead() { // The commented line below doesn't seems to work. // return this.file.canRead(); // The canRead status is read once. This is done in this method, so that // it's available for all subclasses. If it were in the constructor, we // would have to initialize {@link #canRead} in all subclasses. // Let's store the status 'readible' only once. It's if (canRead == null) { try { InputStream is = new FileInputStream(this.file); is.close(); canRead = new Boolean(true); } catch (IOException e) { // Can't read the file! canRead = new Boolean(false); } } return canRead.booleanValue(); } /** {@inheritDoc} */ public File getFile() { return this.file; } /** {@inheritDoc} */ public String getRelativeDir() { if (null != this.fileRoot && (!this.fileRoot.equals("")) && (this.fileDir.startsWith(this.fileRoot))) { int skip = this.fileRoot.length(); if (!this.fileRoot.endsWith(File.separator)) skip++; if ((skip >= 0) && (skip < this.fileDir.length())) return this.fileDir.substring(skip); } return ""; } // //////////////////////////////////////////////////////// // UTILITIES // //////////////////////////////////////////////////////// /** * Returns the extension of the given file. To be clear: <I>jpg</I> is the * extension for the file named <I>picture.jpg</I>. * * @param file the file whose the extension is wanted! * @return The extension, without the point, for the given file. */ public static String getExtension(File file) { String name = file.getName(); return name.substring(name.lastIndexOf('.') + 1); } }