source: 3thparty/jupload/src/main/java/wjhk/jupload2/upload/FilePreparationThread.java @ 3951

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

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

Line 
1package wjhk.jupload2.upload;
2
3import java.util.concurrent.BlockingQueue;
4
5import javax.swing.JProgressBar;
6
7import wjhk.jupload2.exception.JUploadException;
8import wjhk.jupload2.filedata.FileData;
9import wjhk.jupload2.gui.JUploadPanel;
10import wjhk.jupload2.gui.filepanel.FilePanel;
11import wjhk.jupload2.policies.UploadPolicy;
12
13/**
14 * This thread is responsible for preparing all files for upload. It stores each
15 * prepared file in the preparedFileQueue, for further processing.
16 *
17 * @author etienne_sf
18 */
19public class FilePreparationThread extends Thread {
20
21    /**
22     * The array of files to send, from the {@link FilePanel}
23     */
24    FileData[] fileDataArray = null;
25
26    /**
27     * Number of files that are prepared for upload. A file is prepared for
28     * upload, if the {@link FileData#beforeUpload()} has been called.
29     */
30    int nbPreparedFiles = 0;
31
32    /**
33     * The total of files that must be sent. It is initialized by the total
34     * number of files in the list, and is decremented each time an error occurs
35     * during a file preparation, and the user wants to go on.
36     */
37    int nbFilesToSent = -1;
38
39    /**
40     * Sum of the length for all prepared files. This allow the calculation of
41     * the estimatedTotalLength.
42     *
43     * @see #anotherFileIsPrepared(UploadFileData)
44     */
45    long nbTotalNumberOfPreparedBytes = 0;
46
47    /**
48     * The {@link JUploadPanel} progress bar, to follow the file preparation
49     * progress.
50     */
51    JProgressBar preparationProgressBar = null;
52
53    /** A shortcut to the upload panel */
54    JUploadPanel uploadPanel = null;
55
56    /** The current upload policy. */
57    UploadPolicy uploadPolicy = null;
58
59    /** The thread which globally manages the upload */
60    FileUploadManagerThread fileUploadManagerThread = null;
61
62    /** The current file list. */
63    FilePanel filePanel = null;
64
65    /**
66     * The queue where each prepared file will be stored, for further processing
67     */
68    BlockingQueue<UploadFileData> preparedFileQueue = null;
69
70    /**
71     * @param preparedFileQueue
72     * @param fileUploadManagerThread
73     * @param uploadPolicy
74     */
75    public FilePreparationThread(
76            BlockingQueue<UploadFileData> preparedFileQueue,
77            FileUploadManagerThread fileUploadManagerThread,
78            UploadPolicy uploadPolicy) {
79        // A thread name is very useful, when debugging...
80        super("FilePreparationThread");
81
82        this.preparedFileQueue = preparedFileQueue;
83        this.fileUploadManagerThread = fileUploadManagerThread;
84        this.uploadPolicy = uploadPolicy;
85        this.uploadPanel = uploadPolicy.getContext().getUploadPanel();
86        this.filePanel = this.uploadPanel.getFilePanel();
87        this.preparationProgressBar = this.uploadPanel
88                .getPreparationProgressBar();
89
90        // Prepare the list of files to upload. We do this here, to minimize the
91        // risk of concurrency, if the user drops or pastes files on the applet
92        // while uploading.
93        this.fileDataArray = this.uploadPanel.getFilePanel().getFiles();
94
95        // We know now the total of files we should upload:
96        this.nbFilesToSent = fileDataArray.length;
97
98        this.preparationProgressBar.setMaximum(100 * fileDataArray.length);
99    }
100
101    /**
102     * The actual command to prepare files.
103     *
104     * @see java.lang.Thread#run()
105     * @see FileData#beforeUpload()
106     */
107    @Override
108    final public void run() {
109        // We loop through all files, and check before each if we should
110        // stop (for instance if an error occurs)
111
112        // numFileInCurrentUpload is the index of the file in the current index.
113        // It should be the array index. But, if a file preparation fails in
114        // error, numFileInCurrentUpload will be the array index minus 1, if 2
115        // files, it will be the array index minus 2...
116        int numFileInCurrentUpload = 0;
117
118        for (int i = 0; i < fileDataArray.length
119                && !this.fileUploadManagerThread.isUploadFinished(); i += 1) {
120            try {
121                UploadFileData uploadFileData = new UploadFileData(
122                        fileDataArray[i], numFileInCurrentUpload,
123                        this.fileUploadManagerThread, this.uploadPolicy);
124                this.uploadPolicy.displayDebug(
125                        "============== Start of file preparation ("
126                                + uploadFileData.getFileName() + ")", 30);
127
128                // Let's indicate to the user what's running on.
129                this.preparationProgressBar.setString(this.uploadPolicy
130                        .getLocalizedString("preparingFile", Integer
131                                .valueOf(i + 1), Integer
132                                .valueOf(fileDataArray.length)));
133                // We want an immediate repaint, to be sure that the new text is
134                // displayed to the user.
135                this.preparationProgressBar.repaint(0);
136
137                // Then, we work
138
139                // Let's check that everything is Ok
140                // More debug output, to understand where the applet freezes.
141                this.uploadPolicy
142                        .displayDebug(
143                                this.getClass().getName()
144                                        + ".prepareFiles(): before call to beforeUpload()",
145                                100);
146
147                try {
148                    // Let's try to prepare the upload.
149                    uploadFileData.beforeUpload();
150
151                    // If we arrive, here, it means that beforeUpload() did not
152                    // throw an exception, that is: the file is now prepared.
153                    // Next file will be ... next in the current upload.
154                    numFileInCurrentUpload += 1;
155
156                    // TODO Whe error during file preparation ask the user.
157
158                    this.uploadPolicy.displayDebug(
159                            "============== End of file preparation ("
160                                    + uploadFileData.getFileName() + ")", 30);
161                    try {
162                        anotherFileIsPrepared(uploadFileData);
163                    } catch (InterruptedException e) {
164                        // There was a problem putting the item. Let's try again
165                        // in
166                        // the next loop.
167                        i -= 1;
168                    }
169                } catch (JUploadException e) {
170                    // An error occurs during file preparation. We'll send one
171                    // file less than expected.
172                    this.nbFilesToSent -= 1;
173                    throw e;
174                }
175
176                // The file preparation is finished. Let's update the progress
177                // bar.
178                this.preparationProgressBar
179                        .setValue(this.nbPreparedFiles * 100);
180                this.preparationProgressBar.repaint();
181            } catch (JUploadException e) {
182                this.fileUploadManagerThread.setUploadException(e);
183            }
184        }// while
185
186        // All prepared files are posted on the preparedQueue. Let's send the
187        // 'End of Queue' marker.
188        try {
189            this.preparedFileQueue.put(new UploadFileDataPoisonned());
190        } catch (InterruptedException e) {
191            // We should not be interrupted here. If it happens, it should be
192            // because the upload was stopped. But, then, we may have the
193            // PacketConstructionThread blocked, waiting for this packet. So,
194            // let's log a warning.
195            this.uploadPolicy
196                    .displayWarn("Got interrupted, while posting the poisoned UploadFileData on the preparedQueue!");
197        }
198
199        // Let's clear the bar, which is no more accurate. We let the value to
200        // 100%
201        this.preparationProgressBar.setString("");
202    }
203
204    /**
205     * This method is called each time a new file is ready to upload. It
206     * calculates if a new packet of files is ready to upload. It is private, as
207     * it may be called only from this class.
208     *
209     * @throws JUploadException
210     */
211    private void anotherFileIsPrepared(UploadFileData newlyPreparedFileData)
212            throws JUploadException, InterruptedException {
213        this.nbPreparedFiles += 1;
214        this.uploadPolicy
215                .displayDebug(
216                        this.getClass().getName()
217                                + ".anotherFileIsReady(): before call(1) to newlyPreparedFileData.getUploadLength()",
218                        100);
219        this.uploadPolicy
220                .displayDebug(
221                        this.getClass().getName()
222                                + ".checkIfNextPacketIsReady(): before call(2) to currentFileData.getUploadLength()",
223                        100);
224        this.nbTotalNumberOfPreparedBytes += newlyPreparedFileData
225                .getUploadLength();
226
227        this.preparedFileQueue.put(newlyPreparedFileData);
228    }
229
230    /**
231     * Returns the total number of bytes to upload. This takes into account only
232     * the prepared file content. It ignores the possible head and tails of the
233     * request (for instance: http headers...). This gives a good idea of the
234     * total amount to send, and allows is suffisiant to properly manage the
235     * upload progress bar.<BR>
236     * The total number of bytes can only be calculated when all files are
237     * prepared. When this method is called before this, an estimation is done
238     * for non prepared files, based on the average size of the already prepared
239     * files.
240     *
241     * @return The real or estimated total number of bytes to send
242     */
243    public double getTotalFileBytesToSend() {
244        double totalFileBytesToSend;
245
246        // Let's estimate the total, or calculate it, of all files are
247        // prepared
248        if (this.nbPreparedFiles == this.fileDataArray.length) {
249            // All files are prepared: it's no more an estimation !
250            totalFileBytesToSend = this.nbTotalNumberOfPreparedBytes;
251        } else {
252            // We sum the total number of prepared bytes, and we estimate
253            // the size of the files that are not prepared yet
254            totalFileBytesToSend = this.nbTotalNumberOfPreparedBytes
255                    +
256                    // And we sum it with the average amount per file
257                    // prepared for the others
258                    (this.fileDataArray.length - this.nbPreparedFiles)
259                    * this.nbTotalNumberOfPreparedBytes / this.nbPreparedFiles;
260        }
261
262        return totalFileBytesToSend;
263    }
264
265    /**
266     * @return the nbPreparedFiles
267     */
268    public int getNbPreparedFiles() {
269        return nbPreparedFiles;
270    }
271
272    /**
273     * @return the nbFilesToSent
274     */
275    public int getNbFilesToSent() {
276        return nbFilesToSent;
277    }
278
279    /**
280     * @return the nbTotalNumberOfPreparedBytes
281     */
282    public long getNbTotalNumberOfPreparedBytes() {
283        return nbTotalNumberOfPreparedBytes;
284    }
285}
Note: See TracBrowser for help on using the repository browser.