source: 3thparty/jupload/src/main/java/wjhk/jupload2/filedata/DefaultFileData.java @ 3951

Revision 3951, 13.1 KB checked in by alexandrecorreia, 13 years ago (diff)

Ticket #1709 - Adicao de codigo fonte java do componente jupload

Line 
1//
2// $Id: DefaultFileData.java 267 2007-06-08 13:42:02 +0000 (ven., 08 juin 2007)
3// felfert $
4//
5// jupload - A file upload applet.
6// Copyright 2007 The JUpload Team
7//
8// Created: 2006-04-21
9// Creator: etienne_sf
10// Last modified: $Date: 2010-06-28 10:20:25 -0300 (Seg, 28 Jun 2010) $
11//
12// This program is free software; you can redistribute it and/or modify it under
13// the terms of the GNU General Public License as published by the Free Software
14// Foundation; either version 2 of the License, or (at your option) any later
15// version. This program is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18// details. You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software Foundation, Inc.,
20// 675 Mass Ave, Cambridge, MA 02139, USA.
21
22package wjhk.jupload2.filedata;
23
24import java.io.File;
25import java.io.FileInputStream;
26import java.io.FileNotFoundException;
27import java.io.IOException;
28import java.io.InputStream;
29import java.security.MessageDigest;
30import java.security.NoSuchAlgorithmException;
31import java.text.SimpleDateFormat;
32import java.util.Date;
33
34import wjhk.jupload2.exception.JUploadException;
35import wjhk.jupload2.exception.JUploadExceptionTooBigFile;
36import wjhk.jupload2.exception.JUploadIOException;
37import wjhk.jupload2.policies.DefaultUploadPolicy;
38import wjhk.jupload2.policies.UploadPolicy;
39import wjhk.jupload2.upload.helper.ByteArrayEncoder;
40
41/**
42 * This class contains all data and methods for a file to upload. The current
43 * {@link wjhk.jupload2.policies.UploadPolicy} contains the necessary parameters
44 * to personalize the way files must be handled. <BR>
45 * <BR>
46 * This class is the default FileData implementation. It gives the default
47 * behaviour, and is used by {@link DefaultUploadPolicy}. It provides standard
48 * control on the files choosen for upload.
49 *
50 * @see FileData
51 * @author etienne_sf
52 */
53public class DefaultFileData implements FileData {
54
55        /**
56         * The current upload policy.
57         */
58        UploadPolicy uploadPolicy;
59
60        /**
61         * Indicates whether the file is prepared for upload or not.
62         *
63         * @see FileData#isPreparedForUpload()
64         */
65        boolean preparedForUpload = false;
66
67        private final static int BUFLEN = 4096;
68
69        // ///////////////////////////////////////////////////////////////////////////////////////////////////////
70        // /////////////////////// Protected attributes
71        // /////////////////////////////////////////////////////
72        // ///////////////////////////////////////////////////////////////////////////////////////////////////////
73
74        /**
75         * Mime type of the file. It will be written in the upload HTTP request.
76         */
77        protected String mimeType = "application/octet-stream";
78
79        // ///////////////////////////////////////////////////////////////////////////////////////////////////////
80        // /////////////////////// Private attributes
81        // ////////////////////////////////////////////////////////
82        // ///////////////////////////////////////////////////////////////////////////////////////////////////////
83
84        /**
85         * file is the file about which this FileData contains data.
86         */
87        protected File file;
88
89        /**
90         * Cached file size
91         */
92        protected long fileSize;
93
94        /**
95         * Cached file directory
96         */
97        protected String fileDir;
98
99        /**
100         * cached root of this file
101         */
102        protected String fileRoot = "";
103
104        /**
105         * Cached file modification time.
106         */
107        protected Date fileModified;
108
109        /**
110         * The md5sum for the prepared file. Calculated in the
111         * {@link #beforeUpload()}, and cleared in the {@link #afterUpload()}.
112         */
113        protected String md5sum = null;
114
115        /**
116         * Indicates whether the applet can read this file or not.
117         */
118        protected Boolean canRead = null;
119
120        /**
121         * Standard constructor
122         *
123         * @param file
124         *            The file whose data this instance will give.
125         * @param root
126         *            The directory root, to be able to calculate the result of
127         *            {@link #getRelativeDir()}
128         * @param uploadPolicy
129         *            The current upload policy.
130         */
131        public DefaultFileData(File file, File root, UploadPolicy uploadPolicy) {
132                this.file = file;
133                this.uploadPolicy = uploadPolicy;
134                this.fileSize = this.file.length();
135                this.fileDir = this.file.getAbsoluteFile().getParent();
136                this.fileModified = new Date(this.file.lastModified());
137                if (null != root) {
138                        this.fileRoot = root.getAbsolutePath();
139                        uploadPolicy.displayDebug("Creation of the DefaultFileData for "
140                                        + file.getAbsolutePath() + "(root: "
141                                        + root.getAbsolutePath() + ")", 10);
142                } else {
143                        uploadPolicy.displayDebug("Creation of the DefaultFileData for "
144                                        + file.getAbsolutePath() + "(root: null)", 10);
145                }
146
147                // Let
148                this.mimeType = this.uploadPolicy.getContext().getMimeType(
149                                getFileExtension());
150        }
151
152        /** {@inheritDoc} */
153        public void appendFileProperties(ByteArrayEncoder bae, int index)
154                        throws JUploadIOException {
155                bae.appendTextProperty("mimetype", getMimeType(), index);
156                bae.appendTextProperty("pathinfo", getDirectory(), index);
157                bae.appendTextProperty("relpathinfo", getRelativeDir(), index);
158                // To add the file date/time, we first have to format this date.
159                SimpleDateFormat dateformat = new SimpleDateFormat(this.uploadPolicy
160                                .getDateFormat());
161                String uploadFileModificationDate = dateformat
162                                .format(getLastModified());
163                bae.appendTextProperty("filemodificationdate",
164                                uploadFileModificationDate, index);
165        }
166
167        /** {@inheritDoc} */
168        public synchronized void beforeUpload() throws JUploadException {
169                if (this.preparedForUpload) {
170                        // Maybe an upload was stopped. Let's log a resume, and resume the
171                        // job.
172                        this.uploadPolicy.displayWarn("The file " + getFileName()
173                                        + " is already prepared for upload");
174                } else {
175                        // The file is now prepared for upload.
176                        this.preparedForUpload = true;
177
178                        // Should we calculate the MD5Sum for this file ?
179                        if (this.uploadPolicy.getSendMD5Sum()) {
180                                calculateMD5Sum();
181                        }
182
183                        // Default : we check that the file is smaller than the maximum
184                        // upload size.
185                        if (getUploadLength() > this.uploadPolicy.getMaxFileSize()) {
186                                throw new JUploadExceptionTooBigFile(getFileName(),
187                                                getUploadLength(), this.uploadPolicy);
188                        }
189                }
190        }
191
192        /** {@inheritDoc} */
193        public long getUploadLength() {
194                if (!this.preparedForUpload) {
195                        throw new IllegalStateException("The file " + getFileName()
196                                        + " is not prepared for upload");
197                }
198                return this.fileSize;
199        }
200
201        /** {@inheritDoc} */
202        public synchronized void afterUpload() {
203                if (!this.preparedForUpload) {
204                        throw new IllegalStateException("The file " + getFileName()
205                                        + " is not prepared for upload");
206                }
207                // Let's free resources or temporary calculation in DefaultFileData
208                this.md5sum = null;
209
210                // Then, we change the preparation status.
211                this.preparedForUpload = false;
212        }
213
214        /** {@inheritDoc} */
215        public synchronized InputStream getInputStream() throws JUploadException {
216                if (!this.preparedForUpload) {
217                        throw new IllegalStateException("The file " + getFileName()
218                                        + " is not prepared for upload");
219                }
220                // Standard FileData : we read the file.
221                try {
222                        return new FileInputStream(this.file);
223                } catch (FileNotFoundException e) {
224                        throw new JUploadIOException(e);
225                }
226        }
227
228        /** {@inheritDoc} */
229        public String getFileName() {
230                return this.file.getName();
231        }
232
233        /** {@inheritDoc} */
234        public String getFileExtension() {
235                return getExtension(this.file);
236        }
237
238        /** {@inheritDoc} */
239        public long getFileLength() {
240                return this.fileSize;
241        }
242
243        /** {@inheritDoc} */
244        public Date getLastModified() {
245                return this.fileModified;
246        }
247
248        /** {@inheritDoc} */
249        public String getDirectory() {
250                return this.fileDir;
251        }
252
253        /** {@inheritDoc} */
254        public String getMD5() throws JUploadException {
255                if (this.md5sum == null) {
256                        throw new JUploadException("The MD5Sum has not been calculated!");
257                }
258                return this.md5sum;
259        }
260
261        /**
262         * Calculate the MD5Sum for the transformed file, or the original if no
263         * transformation should be done on the file, before upload.
264         *
265         * @throws JUploadException
266         */
267        public void calculateMD5Sum() throws JUploadException {
268                StringBuffer ret = new StringBuffer();
269                MessageDigest digest = null;
270                byte md5Buffer[] = new byte[BUFLEN];
271                int nbBytes;
272
273                // Calculation of the MD5 sum. Now done before upload, to prepare the
274                // file head.
275                // This makes the file being parsed two times: once before upload, and
276                // once for the actual upload
277                InputStream md5InputStream = getInputStream();
278                try {
279                        digest = MessageDigest.getInstance("MD5");
280                        while ((nbBytes = md5InputStream.read(md5Buffer, 0, BUFLEN)) > 0) {
281                                digest.update(md5Buffer, 0, nbBytes);
282                        }
283                } catch (IOException e) {
284                        throw new JUploadIOException(e);
285                } catch (NoSuchAlgorithmException e) {
286                        throw new JUploadException(e);
287                } finally {
288                        try {
289                                md5InputStream.close();
290                        } catch (IOException e) {
291                                throw new JUploadIOException(e);
292                        }
293                }
294
295                // Now properly format the md5 sum.
296                byte md5sum[] = new byte[32];
297                if (digest != null)
298                        md5sum = digest.digest();
299                for (int i = 0; i < md5sum.length; i++) {
300                        ret.append(Integer.toHexString((md5sum[i] >> 4) & 0x0f));
301                        ret.append(Integer.toHexString(md5sum[i] & 0x0f));
302                }
303
304                this.md5sum = ret.toString();
305        }
306
307        /** {@inheritDoc} */
308        public String getMimeType() {
309                return this.mimeType;
310        }
311
312        /** {@inheritDoc} */
313        public boolean canRead() {
314                // The commented line below doesn't seems to work.
315                // return this.file.canRead();
316
317                // The canRead status is read once. This is done in this method, so that
318                // it's available for all subclasses. If it were in the constructor, we
319                // would have to initialize {@link #canRead} in all subclasses.
320
321                // Let's store the status 'readible' only once. It's
322                if (this.canRead == null) {
323                        try {
324                                InputStream is = new FileInputStream(this.file);
325                                is.close();
326                                this.canRead = Boolean.valueOf(true);
327                        } catch (IOException e) {
328                                // Can't read the file!
329                                this.canRead = Boolean.valueOf(false);
330                        }
331                }
332
333                return this.canRead.booleanValue();
334        }
335
336        /** {@inheritDoc} */
337        public File getFile() {
338                return this.file;
339        }
340
341        /** {@inheritDoc} */
342        public String getRelativeDir() {
343                if (null != this.fileRoot && (!this.fileRoot.equals(""))
344                                && (this.fileDir.startsWith(this.fileRoot))) {
345                        int skip = this.fileRoot.length();
346                        if (!this.fileRoot.endsWith(File.separator))
347                                skip++;
348                        if ((skip >= 0) && (skip < this.fileDir.length()))
349                                return this.fileDir.substring(skip);
350                }
351                return "";
352        }
353
354        // ////////////////////////////////////////////////////////
355        // UTILITIES
356        // ////////////////////////////////////////////////////////
357        /**
358         * Returns the extension of the given file. To be clear: <I>jpg</I> is the
359         * extension for the file named <I>picture.jpg</I>.
360         *
361         * @param file
362         *            the file whose the extension is wanted!
363         * @return The extension, without the point, for the given file.
364         */
365        public static String getExtension(File file) {
366                String name = file.getName();
367                return name.substring(name.lastIndexOf('.') + 1);
368        }
369
370        /**
371         * Return the 'biggest' common ancestror of the given file array. For
372         * instance, the root for the files /usr/bin/toto and /usr/titi is /usr.
373         *
374         * @param fileArray
375         * @return The common root for the given files.
376         */
377        public static File getRoot(File[] fileArray) {
378                // Let's find the common root for the dropped files.
379                // If one file has been dropped (the minimum), the path of its parent
380                // should be the root.
381                File root = fileArray[0];
382                if (root.isDirectory()) {
383                        root = root.getParentFile();
384                }
385                // Let's find the higher root level.
386                while (root != null && !root.isDirectory()) {
387                        // We have a file. Let's take it's folder.
388                        root = root.getParentFile();
389                }
390
391                if (root != null) {
392                        // root is the root for the first file. We add all directories,
393                        // and higher until the root. This will allow to find the
394                        // 'bigger' directory, which is the common root for all dropped
395                        // files.
396                        // If several files are being added, we take the common root for
397                        // them.
398                        String pathRoot = root.getAbsolutePath() + File.separator;
399                        String pathCurrentFileParentPath;
400                        File pathCurrentFileParent;
401
402                        // We start with the second item in the list, as we already
403                        // extracted the first.
404                        for (int i = 1; i < fileArray.length && root != null; i += 1) {
405                                // Let's check that all files in l are parents of the current
406                                // file.
407                                pathCurrentFileParent = fileArray[i];
408                                pathCurrentFileParentPath = pathCurrentFileParent
409                                                .getAbsolutePath()
410                                                + File.separator;
411
412                                // We loop through the parent of the file, until we find a
413                                // common root.
414                                while (pathCurrentFileParent != null
415                                                && !pathRoot.startsWith(pathCurrentFileParentPath)) {
416                                        pathCurrentFileParent = pathCurrentFileParent
417                                                        .getParentFile();
418                                        pathCurrentFileParentPath = pathCurrentFileParent
419                                                        .getAbsolutePath()
420                                                        + File.separator;
421                                }
422
423                                // Let's store the new found root (which may actually be the
424                                // same as the last one)
425                                root = pathCurrentFileParent;
426                                pathRoot = pathCurrentFileParentPath;
427                        }// for
428
429                        // pathRoot contains the path for the found root.
430                        root = new File(pathRoot);
431                }
432
433                return root;
434        }
435
436        /** {@inheritDoc} */
437        public boolean isPreparedForUpload() {
438                return this.preparedForUpload;
439        }
440}
Note: See TracBrowser for help on using the repository browser.