View Javadoc
1   //
2   // $Id: DefaultUploadPolicy.java 289 2007-06-19 10:04:46 +0000 (mar., 19 juin
3   // 2007) etienne_sf $
4   //
5   // jupload - A file upload juploadContext.
6   // Copyright 2007 The JUpload Team
7   //
8   // Created: 2006-05-04
9   // Creator: etienne_sf
10  // Last modified: $Date: 2015-03-14 15:13:43 +0100 (sam., 14 mars 2015) $
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  
22  package wjhk.jupload2.policies;
23  
24  import java.awt.BorderLayout;
25  import java.awt.Cursor;
26  import java.awt.GridLayout;
27  import java.awt.SystemColor;
28  import java.awt.dnd.DropTargetDropEvent;
29  import java.io.BufferedReader;
30  import java.io.ByteArrayOutputStream;
31  import java.io.File;
32  import java.io.FileOutputStream;
33  import java.io.FileReader;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.PrintStream;
37  import java.io.UnsupportedEncodingException;
38  import java.net.MalformedURLException;
39  import java.net.URL;
40  import java.net.URLEncoder;
41  import java.nio.charset.Charset;
42  import java.nio.charset.UnsupportedCharsetException;
43  import java.util.IllegalFormatException;
44  import java.util.Iterator;
45  import java.util.Locale;
46  import java.util.ResourceBundle;
47  import java.util.Vector;
48  import java.util.regex.Matcher;
49  import java.util.regex.Pattern;
50  import java.util.regex.PatternSyntaxException;
51  
52  import javax.swing.BorderFactory;
53  import javax.swing.BoxLayout;
54  import javax.swing.Icon;
55  import javax.swing.JButton;
56  import javax.swing.JLabel;
57  import javax.swing.JOptionPane;
58  import javax.swing.JPanel;
59  import javax.swing.JProgressBar;
60  import javax.swing.UIManager;
61  import javax.swing.UnsupportedLookAndFeelException;
62  import javax.swing.border.BevelBorder;
63  
64  import wjhk.jupload2.context.JUploadContext;
65  import wjhk.jupload2.exception.JUploadException;
66  import wjhk.jupload2.exception.JUploadExceptionStopAddingFiles;
67  import wjhk.jupload2.exception.JUploadExceptionUploadFailed;
68  import wjhk.jupload2.exception.JUploadExceptionUploadFailedSuccessNotFound;
69  import wjhk.jupload2.exception.JUploadIOException;
70  import wjhk.jupload2.filedata.DefaultFileData;
71  import wjhk.jupload2.filedata.FileData;
72  import wjhk.jupload2.gui.JUploadFileChooser;
73  import wjhk.jupload2.gui.JUploadFileFilter;
74  import wjhk.jupload2.gui.JUploadPanel;
75  import wjhk.jupload2.gui.filepanel.FilePanel.FileListViewMode;
76  import wjhk.jupload2.upload.helper.ByteArrayEncoder;
77  import wjhk.jupload2.upload.helper.ByteArrayEncoderHTTP;
78  import wjhk.jupload2.upload.helper.HTTPConnectionHelper;
79  import wjhk.jupload2.upload.helper.HttpProtocolFinderThread;
80  import wjhk.jupload2.upload.helper.InteractiveTrustManager;
81  
82  /**
83   * This class implements all {@link wjhk.jupload2.policies.UploadPolicy} methods. Its way of working is he same as the
84   * JUpload version 1. <BR>
85   * The simplest way to use this policy is given in the presentation of {@link UploadPolicy}. The DefaultUploadPolicy is
86   * used when no <I>uploadPolicy</I> parameter is given to the juploadContext, or this parameter has
87   * 'DefaultUploadPolicy' as a value. <BR>
88   * <P>
89   * The <U>default behavior</U> is representated below. It can be overridden by adding parameters to the juploadContext.
90   * All available parameters are shown in the presentation of {@link UploadPolicy}.
91   * </P>
92   * <UL>
93   * <LI>Default implementation for all {@link wjhk.jupload2.policies.UploadPolicy} methods.
94   * <LI>Files are uploaded all in one HTTP request.
95   * <LI>No handling for particular kind of files: files are transmitted without any transformation.
96   * <LI>The file are transmitted to the server with the navigator cookies, userAgent and Protocol (see also the
97   * readCookieFromNavigator and serverProtocol juploadContext parameter). This make upload occurs within the current user
98   * session on the server. So, it allows right management and context during the management of uploaded files, on the
99   * server.
100  * </UL>
101  * 
102  * @author etienne_sf
103  * @version $Revision: 1718 $
104  */
105 
106 public class DefaultUploadPolicy implements UploadPolicy {
107 
108     /**
109      * Maximum number of characters allowed for a message that is displayed in a DialogBox
110      */
111     public final static int DIALOG_MESSAGE_MAX_LINE_LENGTH = 80;
112 
113     // //////////////////////////////////////////////////////////////////////////////////////////////
114     // /////////////////// APPLET PARAMETERS
115     // ///////////////////////////////////////////////////
116     // //////////////////////////////////////////////////////////////////////////////////////////////
117 
118     /**
119      * juploadContext contains the reference of the Applet. It's useful to interact with it. <BR>
120      * It also allows access to the navigator properties, if the html tag MAYSCRIPT is put in the APPLET tag. This
121      * allows this class to get the cookie, userAgent and protocol, to upload files in the current user session on the
122      * server. <BR>
123      * Default : no default value
124      */
125     JUploadContext juploadContext = null;
126 
127     /**
128      * Contains the applet parameter of the same name. If a valid URL is given here, the navigator will get redirected
129      * to this page, after a successful upload.
130      */
131     private String afterUploadURL = UploadPolicy.DEFAULT_AFTER_UPLOAD_URL;
132 
133     /**
134      * Contains the allowedFileExtensions applet parameter.
135      */
136     private boolean allowHttpPersistent = UploadPolicy.DEFAULT_ALLOW_HTTP_PERSISTENT;
137 
138     /**
139      * Contains the allowedFileExtensions applet parameter.
140      */
141     private String allowedFileExtensions = UploadPolicy.DEFAULT_ALLOWED_FILE_EXTENSIONS;
142 
143     /**
144      * Indicate whether the log window is shown or not to the user. In all cases it remains in memory, and stores all
145      * debug information. This allows a log information, in case of an error occurs.
146      * 
147      * @see #urlToSendErrorTo
148      */
149     private String showLogWindow = UploadPolicy.DEFAULT_SHOW_LOGWINDOW;
150 
151     private boolean showStatusbar = UploadPolicy.DEFAULT_SHOW_STATUSBAR;
152 
153     private String specificHeaders = null;
154 
155     /** Indicates the directory in which the file chooser is to be opened */
156     private File currentBrowsingDirectory = null;
157 
158     /**
159      * This parameter controls whether the applet generates a debug file or not. If true, this file contains the full
160      * debug output, whatever the current debugLevel is.
161      */
162     private boolean debugGenerateFile = true;
163 
164     /**
165      * The current debug level. This control the details of information that is written in the log part of the applet.
166      */
167     private int debugLevel = UploadPolicy.DEFAULT_DEBUG_LEVEL;
168 
169     /**
170      * Stored value for the fileChooserIconFromFileContent applet property.
171      * 
172      * @see UploadPolicy#PROP_FILE_CHOOSER_ICON_FROM_FILE_CONTENT
173      */
174     private int fileChooserIconFromFileContent = UploadPolicy.DEFAULT_FILE_CHOOSER_ICON_FROM_FILE_CONTENT;
175 
176     /**
177      * Stored value for the fileChooserIconSize applet property.
178      * 
179      * @see UploadPolicy#PROP_FILE_CHOOSER_ICON_SIZE
180      */
181     private int fileChooserIconSize = UploadPolicy.DEFAULT_FILE_CHOOSER_ICON_SIZE;
182 
183     /** Stored value for the {@link UploadPolicy#PROP_FILE_FILTER_NAME} */
184     private String fileFilterName = UploadPolicy.DEFAULT_FILE_FILTER_NAME;
185 
186     /** Stored value for the {@link UploadPolicy#PROP_FILE_LIST_VIEW_MODE} */
187     private FileListViewMode fileListViewMode = UploadPolicy.DEFAULT_FILE_LIST_VIEW_MODE;
188 
189     /**
190      * This String contains the filenameEncoding parameter. All details about the available applet parameters are
191      * displayed in the <a href="UploadPolicy.html@parameters">Upload Policy javadoc page</a>.
192      */
193     private String filenameEncoding = UploadPolicy.DEFAULT_FILENAME_ENCODING;
194 
195     /**
196      * Default value for the ftpCreateDirectoryStructure applet parameter
197      */
198     private boolean ftpCreateDirectoryStructure = UploadPolicy.DEFAULT_FTP_CREATE_DIRECTORY_STRUCTURE;
199 
200     /**
201      * Default value for the ftpCreateDirectoryStructure applet parameter
202      */
203     private boolean ftpTransfertBinary = UploadPolicy.DEFAULT_FTP_TRANSFERT_BINARY;
204 
205     /**
206      * Default value for the ftpCreateDirectoryStructure applet parameter
207      */
208     private boolean ftpTransfertPassive = UploadPolicy.DEFAULT_FTP_TRANSFERT_PASSIVE;
209 
210     /** Default value for the httpUploadParameterName applet parameter */
211     protected String httpUploadParameterName = UploadPolicy.DEFAULT_HTTP_UPLOAD_PARAMETER_NAME;
212 
213     /** Default value for the httpUploadParameterType applet parameter */
214     protected String httpUploadParameterType = UploadPolicy.DEFAULT_HTTP_UPLOAD_PARAMETER_TYPE;
215 
216     /**
217      * The lang parameter, given to the applet.
218      */
219     private String lang = UploadPolicy.DEFAULT_LANG;
220 
221     /**
222      * The current Locale. If the lang parameter is given and value, this supersede the default locale.
223      */
224     private Locale locale = Locale.getDefault();
225 
226     /**
227      * Contains the last exception that occurs in the applet.
228      * 
229      * @see #displayErr(String, Exception)
230      */
231     private JUploadException lastException = null;
232 
233     /**
234      * The look and feel is used as a parameter of the UIManager.setLookAndFeel(String) method. See the parameters list
235      * on the {@link UploadPolicy} page.
236      */
237     private String lookAndFeel = UploadPolicy.DEFAULT_LOOK_AND_FEEL;
238 
239     /**
240      * The applet will do as may HTTP requests to upload all files, with the number as a maximum number of files for
241      * each HTTP request. <BR>
242      * Default : -1
243      */
244     private int nbFilesPerRequest = UploadPolicy.DEFAULT_NB_FILES_PER_REQUEST;
245 
246     /**
247      * Current value (or default value) of the maxChunkSize applet parameter. <BR>
248      * Default : Long.MAX_VALUE
249      */
250     private long maxChunkSize = UploadPolicy.DEFAULT_MAX_CHUNK_SIZE;
251 
252     /**
253      * Current value (or default value) of the maxFileSize applet parameter. <BR>
254      * Default : Long.MAX_VALUE
255      */
256     private long maxFileSize = UploadPolicy.DEFAULT_MAX_FILE_SIZE;
257 
258     /**
259      * The URL where files should be posted. <BR>
260      * Default : no default value. (mandatory)
261      */
262     private String postURL = UploadPolicy.DEFAULT_POST_URL;
263 
264     /** @see UploadPolicy#getReadCookieFromNavigator() */
265     private boolean readCookieFromNavigator = UploadPolicy.DEFAULT_READ_COOKIE_FROM_NAVIGATOR;
266 
267     /** @see UploadPolicy#getReadUserAgentFromNavigator() */
268     private boolean readUserAgentFromNavigator = UploadPolicy.DEFAULT_READ_USER_AGENT_FROM_NAVIGATOR;
269 
270     /** @see UploadPolicy#getRetryMaxNumberOf() */
271     private int retryMaxNumberOf = UploadPolicy.DEFAULT_RETRY_MAX_NUMBER_OF;
272 
273     /** @see UploadPolicy#getRetryNbSecondsBetween() */
274     private int retryNbSecondsBetween = UploadPolicy.DEFAULT_RETRY_NB_SECONDS_BETWEEN;
275 
276     /** @see UploadPolicy#getSendMD5Sum() */
277     private boolean sendMD5Sum = UploadPolicy.DEFAULT_SEND_MD5_SUM;
278 
279     /** @see UploadPolicy#getServerProtocol() */
280     private String serverProtocol = UploadPolicy.DEFAULT_SERVER_PROTOCOL;
281 
282     /**
283      * @see UploadPolicy#getStringUploadError()
284      */
285     private String stringUploadError = UploadPolicy.DEFAULT_STRING_UPLOAD_ERROR;
286 
287     /**
288      * @see UploadPolicy#getStringUploadSuccess()
289      */
290     private String stringUploadSuccess = UploadPolicy.DEFAULT_STRING_UPLOAD_SUCCESS;
291 
292     /**
293      * @see UploadPolicy#getStringUploadWarning()
294      */
295     private String stringUploadWarning = UploadPolicy.DEFAULT_STRING_UPLOAD_WARNING;
296 
297     /**
298      * If an error occurs during upload, and this attribute is not null, the applet asks the user if wants to send the
299      * debug ouput to the administrator. If yes, the full debug information is POSTed to this URL. It's a little
300      * development on the server side to send a mail to the webmaster, or just log this error into a log file.
301      * 
302      * @see UploadPolicy#sendDebugInformation(String, Exception)
303      */
304     private String urlToSendErrorTo = UploadPolicy.DEFAULT_URL_TO_SEND_ERROR_TO;
305 
306     /**
307      * Optional name of a form (in the same document like the applet) which is used to populate POST parameters.
308      */
309     private String formData = UploadPolicy.DEFAULT_FORMDATA;
310 
311     private String afterUploadTarget = UploadPolicy.DEFAULT_AFTER_UPLOAD_TARGET;
312 
313     private String lastResponseBody = null;
314 
315     protected String lastResponseMessage = null;
316 
317     private int sslVerifyCert = InteractiveTrustManager.NONE;
318 
319     private final String CRLF = System.getProperty("line.separator");
320 
321     // //////////////////////////////////////////////////////////////////////////////////////////////
322     // /////////////////// INTERNAL ATTRIBUTE
323     // ///////////////////////////////////////////////////
324     // //////////////////////////////////////////////////////////////////////////////////////////////
325 
326     /**
327      * This Vector contains headers that will be added for each upload. It may contains specific cookies, for instance.
328      * 
329      * @see #onAppendHeader(ByteArrayEncoder)
330      */
331     private Vector<String> headers = new Vector<String>();
332 
333     /**
334      * The resourceBundle contains all localized String (and others ??)
335      */
336     private ResourceBundle resourceBundle = null;
337 
338     /**
339      * This stream is used to store all information that could be useful, in case a problem occurs. Is content can then
340      * be sent to the webmaster.
341      */
342     protected PrintStream debugOut = null;
343 
344     /**
345      * The actual file, used for the debug log.
346      * 
347      * @see #debugGenerateFile
348      */
349     protected File debugFile = null;
350 
351     /**
352      * This flag prevents endless repeats of opening the debug log, if that failed for some reason.
353      */
354     protected boolean debugOk = true;
355 
356     /**
357      * Same as {@link #patternSuccess}, but for the error message. If found, then the upload was accepted by the remote
358      * HTTP server, but rejected by the remote application. This pattern should also find the error message in the first
359      * matching string.
360      */
361     protected Pattern patternError = Pattern.compile(UploadPolicy.DEFAULT_STRING_UPLOAD_ERROR);
362 
363     /**
364      * The regexp pattern that is used to find the success string in the HTTP response. If found, the upload is
365      * considered to be a success: it has been accepted by the remote server and the remote application.
366      */
367     protected Pattern patternSuccess = Pattern.compile(UploadPolicy.DEFAULT_STRING_UPLOAD_SUCCESS);
368 
369     /**
370      * Same as {@link #patternSuccess}, but for the warning message. Each time it is found, a message is displayed to
371      * the user.
372      */
373     protected Pattern patternWarning = Pattern.compile(UploadPolicy.DEFAULT_STRING_UPLOAD_WARNING);
374 
375     // //////////////////////////////////////////////////////////////////////////////////////////////
376     // /////////////////// CONSTRUCTORS
377     // //////////////////////////////////////////////////////////////////////////////////////////////
378 
379     /**
380      * The main constructor : use default values, and the given postURL.
381      * 
382      * @param juploadContext The current juploadContext. As the reference to the current upload policy exists almost
383      *            everywhere, this parameter allows any access to anyone on the juploadContext... including reading the
384      *            applet parameters.
385      * @throws JUploadException If an applet parameter is invalid
386      */
387     public DefaultUploadPolicy(JUploadContext juploadContext) throws JUploadException {
388         // Call default constructor for all default initialization;.
389         this.juploadContext = juploadContext;
390         displayInfo("JUpload juploadContext started, with " + this.getClass().getName() + " upload policy");
391 
392         // get the debug level. This control the level of debug messages that
393         // are written in the log window (see displayDebugMessage). In all
394         // cases, the full output is written in the debugBufferString (see also
395         // urlToSendErrorTo)
396         setDebugLevel(juploadContext.getParameter(PROP_DEBUG_LEVEL, DEFAULT_DEBUG_LEVEL), false);
397 
398         // Get resource file. This must be the very first parameter to be set,
399         // because during initialization, translations may be needed.
400         setLang(juploadContext.getParameter(PROP_LANG, DEFAULT_LANG));
401 
402         // Force the look and feel of the current system. This must be the
403         // second
404         // first parameter to be set, because during initialization, dialogs can
405         // appear.
406         setLookAndFeel(juploadContext.getParameter(PROP_LOOK_AND_FEEL, DEFAULT_LOOK_AND_FEEL));
407 
408         // This must be set before any URL's because these might trigger an
409         // connection attempt.
410         setSslVerifyCert(juploadContext.getParameter(PROP_SSL_VERIFY_CERT, DEFAULT_SSL_VERIFY_CERT));
411 
412         // get the afterUploadURL juploadContext parameter.
413         setAfterUploadURL(juploadContext.getParameter(PROP_AFTER_UPLOAD_URL, DEFAULT_AFTER_UPLOAD_URL));
414 
415         // FTP: whether or not to create subfolders on the server side.
416         setFtpCreateDirectoryStructure(juploadContext.getParameter(PROP_FTP_CREATE_DIRECTORY_STRUCTURE,
417                 DEFAULT_FTP_CREATE_DIRECTORY_STRUCTURE));
418         // FTP transfert mode
419         setFtpTransfertBinary(juploadContext.getParameter(PROP_FTP_TRANSFERT_BINARY, DEFAULT_FTP_TRANSFERT_BINARY));
420         // FTP connection mode
421         setFtpTransfertPassive(juploadContext.getParameter(PROP_FTP_TRANSFERT_PASSIVE, DEFAULT_FTP_TRANSFERT_PASSIVE));
422 
423         // get the fileChooser parameters
424         setAllowedFileExtensions(juploadContext.getParameter(PROP_ALLOWED_FILE_EXTENSIONS,
425                 DEFAULT_ALLOWED_FILE_EXTENSIONS));
426         setFileFilterName(juploadContext.getParameter(PROP_FILE_FILTER_NAME, DEFAULT_FILE_FILTER_NAME));
427         setFileListViewMode(juploadContext.getParameter(PROP_FILE_LIST_VIEW_MODE, DEFAULT_FILE_LIST_VIEW_MODE));
428 
429         setAllowHttpPersistent(juploadContext.getParameter(PROP_ALLOW_HTTP_PERSISTENT, DEFAULT_ALLOW_HTTP_PERSISTENT));
430 
431         setShowStatusbar(juploadContext.getParameter(PROP_SHOW_STATUSBAR, DEFAULT_SHOW_STATUSBAR));
432 
433         setShowLogWindow(juploadContext.getParameter(PROP_SHOW_LOGWINDOW, DEFAULT_SHOW_LOGWINDOW));
434 
435         // set the fileChooser relative stuff.
436         setFileChooserIconFromFileContent(juploadContext.getParameter(PROP_FILE_CHOOSER_ICON_FROM_FILE_CONTENT,
437                 DEFAULT_FILE_CHOOSER_ICON_FROM_FILE_CONTENT));
438         setFileChooserIconSize(juploadContext.getParameter(PROP_FILE_CHOOSER_ICON_SIZE, DEFAULT_FILE_CHOOSER_ICON_SIZE));
439         setCurrentBrowsingDirectory(juploadContext.getParameter(PROP_BROWSING_DIRECTORY, DEFAULT_BROWSING_DIRECTORY));
440         // get the filenameEncoding. If not null, it should be a valid argument for the URLEncoder.encode method.
441         // DEPRECATED.
442         setFilenameEncoding(juploadContext.getParameter(PROP_FILENAME_ENCODING, DEFAULT_FILENAME_ENCODING));
443 
444         // Read parameters about the HTTP upload request.
445         setNbFilesPerRequest(juploadContext.getParameter(PROP_NB_FILES_PER_REQUEST, DEFAULT_NB_FILES_PER_REQUEST));
446         setHttpUploadParameterName(juploadContext.getParameter(PROP_HTTP_UPLOAD_PARAMETER_NAME,
447                 DEFAULT_HTTP_UPLOAD_PARAMETER_NAME));
448         setHttpUploadParameterType(juploadContext.getParameter(PROP_HTTP_UPLOAD_PARAMETER_TYPE,
449                 DEFAULT_HTTP_UPLOAD_PARAMETER_TYPE));
450         // get the maximum size of a file on one HTTP request (indicates if the
451         // file must be splitted before upload, see UploadPolicy comment).
452         setMaxChunkSize(juploadContext.getParameter(PROP_MAX_CHUNK_SIZE, DEFAULT_MAX_CHUNK_SIZE));
453         // get the maximum size of an uploaded file.
454         setMaxFileSize(juploadContext.getParameter(PROP_MAX_FILE_SIZE, DEFAULT_MAX_FILE_SIZE));
455         // retry management
456         setRetryMaxNumberOf(juploadContext.getParameter(PROP_RETRY_MAX_NUMBER_OF, DEFAULT_RETRY_MAX_NUMBER_OF));
457         setRetryNbSecondsBetween(juploadContext.getParameter(PROP_RETRY_NB_SECONDS_BETWEEN,
458                 DEFAULT_RETRY_NB_SECONDS_BETWEEN));
459 
460         // get the URL where files must be posted.
461         setPostURL(juploadContext.getParameter(PROP_POST_URL, DEFAULT_POST_URL));
462 
463         // get any additional headers.
464         setReadCookieFromNavigator(juploadContext.getParameter(PROP_READ_COOKIE_FROM_NAVIGATOR,
465                 DEFAULT_READ_COOKIE_FROM_NAVIGATOR));
466         setReadUserAgentFromNavigator(juploadContext.getParameter(PROP_READ_USER_AGENT_FROM_NAVIGATOR,
467                 DEFAULT_READ_USER_AGENT_FROM_NAVIGATOR));
468         setSendMD5Sum(juploadContext.getParameter(PROP_SEND_MD5_SUM, DEFAULT_SEND_MD5_SUM));
469         setSpecificHeaders(juploadContext.getParameter(PROP_SPECIFIC_HEADERS, DEFAULT_SPECIFIC_HEADERS));
470         setStringUploadError(juploadContext.getParameter(PROP_STRING_UPLOAD_ERROR, DEFAULT_STRING_UPLOAD_ERROR));
471         setStringUploadSuccess(juploadContext.getParameter(PROP_STRING_UPLOAD_SUCCESS, DEFAULT_STRING_UPLOAD_SUCCESS));
472         setStringUploadWarning(juploadContext.getParameter(PROP_STRING_UPLOAD_WARNING, DEFAULT_STRING_UPLOAD_WARNING));
473 
474         // get the URL where the full debug output can be sent when an error
475         // occurs.
476         setUrlToSendErrorTo(juploadContext.getParameter(PROP_URL_TO_SEND_ERROR_TO, DEFAULT_URL_TO_SEND_ERROR_TO));
477         this.formData = juploadContext.getParameter(PROP_FORMDATA, DEFAULT_FORMDATA);
478         this.afterUploadTarget = juploadContext.getParameter(PROP_AFTER_UPLOAD_TARGET, DEFAULT_AFTER_UPLOAD_TARGET);
479 
480         // We let the UploadPolicyFactory call the displayParameterStatus
481         // method, so that the initialization is finished, including for classes
482         // which inherit from DefaultUploadPolicy.
483         displayDebug("[DefaultUploadPolicy] end of constructor (serverProtocol has not been set)", 30);
484     }
485 
486     // //////////////////////////////////////////////////////////////////////////////////////////////
487     // /////////////////// UploadPolicy methods
488     // //////////////////////////////////////////////////////////////////////////////////////////////
489 
490     /** @see UploadPolicy#start() */
491     public void start() {
492         // The current context may add any specific headers.
493         if (getReadCookieFromNavigator()) {
494             this.juploadContext.readCookieFromNavigator(this.headers);
495         }
496         if (getReadUserAgentFromNavigator()) {
497             this.juploadContext.readUserAgentFromNavigator(this.headers);
498         }
499 
500         // Let's touch the server, to test that everything is Ok. Take care,
501         // this is the only place where we override the default value, by null:
502         // the default value will be used by the HttpConnect.getProtocol()
503         // method.
504         // Also, in FTP mode, there can be no default value.
505         //
506         // Must be done AFTER reading the cookie and the userAgent.
507         //
508         HttpProtocolFinderThread.computeServerProtocol(this,
509                 juploadContext.getParameter(PROP_SERVER_PROTOCOL, (String) null));
510     }
511 
512     // getters and setters are sorted below
513 
514     /**
515      * @see wjhk.jupload2.policies.UploadPolicy#addHeader(java.lang.String)
516      */
517     public void addHeader(String header) {
518         this.headers.add(header);
519     }
520 
521     /**
522      * The default behavior (see {@link DefaultUploadPolicy}) is to check that the stringUploadSuccess applet parameter
523      * is present in the response from the server. The return is tested, in the order below: <DIR> <LI>False, if the
524      * stringUploadError is found. An error message is then displayed. <LI>True, if the stringUploadSuccess is null or
525      * empty (no test at all). <LI>True, if the stringUploadSuccess string is present in the serverOutputBody. <LI>True,
526      * If previous condition is not filled, but the HTTP header "HTTP(.*)200OK$" is present: the test is currently non
527      * blocking, because I can not test all possible HTTP configurations.<BR> <LI>False if the previous conditions are
528      * not fullfilled. </DIR> <BR>
529      * This method also looks for the stringUploadWarning regular expression. Each time it is matched, the found message
530      * is displayed to the user.
531      * 
532      * @param status The HTTP response code
533      * @param msg The status message from the first line of the response (e.g. "200 OK").
534      * @param body The body of the HTTP answer.
535      * @return True or False, indicating if the upload is a success or not.
536      * @see UploadPolicy#checkUploadSuccess(int, String, String)
537      */
538     public boolean checkUploadSuccess(int status, String msg, String body) throws JUploadException {
539         boolean bReturn = false;
540 
541         if (getDebugLevel() > 100) {
542             // Let's have a little time to check the upload messages written on
543             // the progress bar.
544             try {
545                 Thread.sleep(300);
546             } catch (InterruptedException e) {
547             }
548         }
549 
550         this.lastResponseBody = body;
551         this.lastResponseMessage = msg;
552         displayDebug("HTTP status: " + msg, 30);
553         // HTTP-100 correction, thanks to Marc Reidy
554         if ((status != 200) && (status != 100))
555             throw new JUploadExceptionUploadFailed("Received HTTP status " + msg);
556 
557         // HTTP-100 "continue", in case we're uploading
558         // to an ASP.NET development server. We should
559         // continue sending...
560         if (status == 100)
561             return true;
562 
563         // Let's analyze the body returned, line by line. The end of line
564         // character may be CR, LF, or CRLF. We navigate through the body, and
565         // replace any end of line character by a uniform CRLF.
566         Matcher matcherError, matcherWarning;
567         String line;
568         Pattern p = Pattern.compile("[\\r\\n]", Pattern.MULTILINE);
569         String[] lines = p.split(body);
570         StringBuffer sbBodyWithUniformCRLF = new StringBuffer(body.length());
571         for (int i = 0; i < lines.length; i += 1) {
572             line = lines[i];
573             sbBodyWithUniformCRLF.append(line).append("\r\n");
574 
575             // FIXME some empty lines are given by the server
576             // Let's remove the empty line: with the p pattern, a multiline is
577             // generated each time a \r\n is received, that is: for each line.
578             if (line == null || line.equals("")) {
579                 // An empty line. Let's go the next line.
580                 continue;
581             }
582 
583             // Check if this is a success
584             // The success string should be in the http body
585             if (getStringUploadSuccess() != null && !getStringUploadSuccess().equals("")) {
586                 if (this.patternSuccess.matcher(line).matches()) {
587                     // We go on. There may be some WARNING message, hereafter.
588                     bReturn = true;
589                 }
590             }
591 
592             // Check if this is an error
593             if (getStringUploadError() != null && !getStringUploadError().equals("")) {
594                 matcherError = this.patternError.matcher(line);
595                 if (matcherError.matches()) {
596                     String errmsg = "An error occurs during upload (but the applet couldn't find the error message)";
597                     if (matcherError.groupCount() > 0) {
598                         if (!matcherError.group(1).equals("")) {
599                             // Let's do a (very simple) formatting: one line to
600                             // 100 characters
601                             errmsg = formatMessage(matcherError.group(1));
602                         }
603                     }
604                     this.lastResponseMessage = errmsg;
605                     throw new JUploadExceptionUploadFailed(errmsg);
606                 }
607             }// getStringUploadError
608 
609             // Check if this is an warning
610             if (getStringUploadWarning() != null && !getStringUploadWarning().equals("")) {
611                 matcherWarning = this.patternWarning.matcher(line);
612                 if (matcherWarning.matches()) {
613                     String warnmsg = "A warning occurs during upload (but the applet couldn't find the warning message)";
614                     if (matcherWarning.groupCount() > 0) {
615                         if (!matcherWarning.group(1).equals("")) {
616                             warnmsg = formatMessage(matcherWarning.group(1));
617                         }
618                     }
619                     this.lastResponseMessage = warnmsg;
620                     displayWarn(warnmsg);
621                     alertStr(warnmsg);
622                 }
623             }// getStringUploadWarning
624 
625         }// while(st.hasMoreTokens())
626 
627         if (bReturn) {
628             return true;
629         }
630 
631         // We found no stringUploadSuccess nor stringUploadError
632         if (getStringUploadSuccess() == null || getStringUploadSuccess().equals("")) {
633             // No chance to check the correctness of this upload. -> Assume Ok
634             return true;
635         }
636 
637         // stringUploadSuccess was defined but we did not find it.
638         // This is most certainly an error as http-status 200 does *not* refer
639         // to the correctness of the content. It merely means that the protocol
640         // handling was ok. -> throw an exception
641         throw new JUploadExceptionUploadFailedSuccessNotFound(getClass().getName()
642                 + ".checkUploadSuccess(): The regexp string \"" + getStringUploadSuccess()
643                 + "\" was not found in the response body");
644     } // checkUploadSuccess
645 
646     /**
647      * Generation of a formatted error message, so that it can be displayed in a DialogBox. That is: each line that
648      * contains more than {@link #DIALOG_MESSAGE_MAX_LINE_LENGTH} is truncated to DIALOG_MESSAGE_MAX_LINE_LENGTH.
649      * 
650      * @param msg
651      * @return
652      */
653     protected String formatMessage(String msg) {
654         StringBuffer sbMsg = new StringBuffer();
655         String[] lines = msg.split("\\\\n");
656         for (int i = 0; i < lines.length; i += 1) {
657             // For each line, we truncate it, if it's too long.
658             String line = lines[i];
659             for (int j = 0, remaining = line.length(); remaining > 0; remaining -= DIALOG_MESSAGE_MAX_LINE_LENGTH, j += 1) {
660                 if (remaining <= DIALOG_MESSAGE_MAX_LINE_LENGTH) {
661                     // It's the last loop.
662                     sbMsg.append(line.substring(j * DIALOG_MESSAGE_MAX_LINE_LENGTH));
663                 } else {
664                     sbMsg.append(line.substring(j * DIALOG_MESSAGE_MAX_LINE_LENGTH, (j + 1)
665                             * DIALOG_MESSAGE_MAX_LINE_LENGTH));
666                     sbMsg.append("\n");
667                 }
668             }
669             // End we add the EOL characters, for all lines, but the last one.
670             if (i < lines.length - 1) {
671                 sbMsg.append("\n");
672             }
673         }
674 
675         return sbMsg.toString();
676     }
677 
678     /**
679      * @see wjhk.jupload2.policies.UploadPolicy#afterUpload(Exception, String)
680      */
681     public void afterUpload(Exception e, String serverOutput) throws JUploadException {
682         // If there was no error, and afterUploadURL is defined, let's try to go
683         // to this URL.
684         String url = getAfterUploadURL();
685         if (url != null) {
686             this.juploadContext.displayURL(url, e == null);
687         }
688     }
689 
690     /** @see UploadPolicy#alertStr(String) */
691     public void alertStr(String str) {
692         String str2 = str.replaceAll("\\\\n", "\n");
693         JOptionPane.showMessageDialog(null, str2, "Alert", JOptionPane.WARNING_MESSAGE);
694     }
695 
696     /** @see UploadPolicy#confirmDialogStr(String, int) */
697     public int confirmDialogStr(String str, int optionTypes) {
698         String str2 = str.replaceAll("\\\\n", "\n");
699         return JOptionPane.showConfirmDialog(getContext().getUploadPanel().getJComponent().getParent(), str2, "Alert",
700                 optionTypes);
701     }
702 
703     /** @see UploadPolicy#alert(String) */
704     public void alert(String key) {
705         alertStr(getLocalizedString(key));
706     }
707 
708     /**
709      * The DefaultUpload accepts all file types: we just return an instance of FileData, without any test.
710      * 
711      * @exception JUploadExceptionStopAddingFiles If the users choosed to stop adding. This occurs when the
712      *                {@link #fileFilterAccept(File)} method returns false, and the user then choose to stop adding
713      *                files.
714      * @see UploadPolicy#createFileData(File, File)
715      */
716     public FileData createFileData(File file) throws JUploadExceptionStopAddingFiles {
717         if (!fileFilterAccept(file)) {
718             String msg = file.getName() + " : " + getLocalizedString("errForbiddenExtension");
719             displayWarn(msg);
720             if (confirmDialogStr(msg, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) {
721                 // The user want to stop to add files to the list. For instance,
722                 // when he/she added a whole directory, and it contains a lot of
723                 // files that don't match the allowed file extension.
724                 throw new JUploadExceptionStopAddingFiles("Stopped by the user");
725             }
726             return null;
727         } else if (!file.canRead()) {
728             displayInfo("Can't read file " + file.getName() + ". No DefaultFileData creation.");
729             return null;
730         } else {
731             return new DefaultFileData(file, this);
732         }
733     }
734 
735     /**
736      * Default implementation of
737      * {@link wjhk.jupload2.policies.UploadPolicy#createTopPanel(JButton, JButton, JButton, JUploadPanel)} . IT creates
738      * a JPanel, containing the three given JButton. It creates the same panel as the original JUpload.
739      * 
740      * @see wjhk.jupload2.policies.UploadPolicy#createTopPanel(JButton, JButton, JButton, JUploadPanel)
741      */
742     public JPanel createTopPanel(JButton browse, JButton remove, JButton removeAll, JUploadPanel jUploadPanel) {
743         JPanel jPanel = new JPanel();
744 
745         jPanel.setLayout(new GridLayout(1, 3, 10, 5));
746         jPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
747         jPanel.add(browse);
748         jPanel.add(removeAll);
749         jPanel.add(remove);
750 
751         jUploadPanel.getJComponent().setBorder(BorderFactory.createLineBorder(SystemColor.controlDkShadow));
752 
753         return jPanel;
754     }
755 
756     /**
757      * @see wjhk.jupload2.policies.UploadPolicy#createProgressPanel(JProgressBar, JProgressBar, JButton, JButton,
758      *      JUploadPanel)
759      */
760     public JPanel createProgressPanel(JProgressBar preparationProgressBar, JProgressBar uploadProgressBar,
761             JButton uploadButton, JButton stopButton, JUploadPanel mainPanel) {
762 
763         // There may be two progress bar: one for preparation progress of files
764         // (preparation before upload) and one to follow the actual upload.
765         JPanel jProgressBarPanel = new JPanel();
766         jProgressBarPanel.setLayout(new BorderLayout(10, 1));
767         jProgressBarPanel.add(preparationProgressBar, BorderLayout.NORTH);
768         jProgressBarPanel.add(uploadProgressBar, BorderLayout.SOUTH);
769 
770         JPanel jProgressPanel = new JPanel();
771         jProgressPanel.setLayout(new BorderLayout(10, 0));
772         jProgressPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
773         jProgressPanel.add(uploadButton, BorderLayout.LINE_START);
774         jProgressPanel.add(jProgressBarPanel, BorderLayout.CENTER);
775         jProgressPanel.add(stopButton, BorderLayout.LINE_END);
776         return jProgressPanel;
777     }
778 
779     /**
780      * @see wjhk.jupload2.policies.UploadPolicy#createStatusBar(javax.swing.JLabel, JUploadPanel)
781      */
782     public JPanel createStatusBar(JLabel content, JUploadPanel mainPanel) {
783         if (this.showStatusbar) {
784             JPanel pstatus = new JPanel();
785             pstatus.setLayout(new BorderLayout());
786             pstatus.add(content, BorderLayout.CENTER);
787             pstatus.setBorder(new BevelBorder(BevelBorder.LOWERED));
788             return pstatus;
789         }
790         return null;
791     }
792 
793     /**
794      * This methods allow the upload policy to override the default disposition of the components on the applet.
795      * 
796      * @see UploadPolicy#addComponentsToJUploadPanel(JUploadPanel)
797      */
798     public void addComponentsToJUploadPanel(JUploadPanel jUploadPanel) {
799         // Set the global layout of the panel.
800         jUploadPanel.getJComponent().setLayout(new BoxLayout(jUploadPanel.getJComponent(), BoxLayout.Y_AXIS));
801 
802         // The top panel is the upper part of the applet: above the file
803         // list.
804         // JPanel topPanel = new JPanel();
805         JPanel topPanel = createTopPanel(jUploadPanel.getBrowseButton(), jUploadPanel.getRemoveButton(),
806                 jUploadPanel.getRemoveAllButton(), jUploadPanel);
807         if (topPanel != null) {
808             jUploadPanel.getJComponent().add(topPanel);
809             topPanel.addMouseListener(jUploadPanel.getMouseListener());
810         }
811 
812         // Then, we add the file list.
813         jUploadPanel.getJComponent().add(jUploadPanel.getFilePanel().getDropComponent());
814 
815         // The progress panel contains the progress bar, and the upload and stop
816         // buttons.
817         JPanel progressPanel = createProgressPanel(jUploadPanel.getPreparationProgressBar(),
818                 jUploadPanel.getUploadProgressBar(), jUploadPanel.getUploadButton(), jUploadPanel.getStopButton(),
819                 jUploadPanel);
820         jUploadPanel.getJComponent().add(progressPanel);
821         jUploadPanel.getJComponent().addMouseListener(jUploadPanel.getMouseListener());
822 
823         // Now, we add the log window.
824         jUploadPanel.showOrHideLogWindow();
825         jUploadPanel.getJComponent().add(jUploadPanel.getJLogWindowPane());
826 
827         // And, to finish with: the status bar.
828         JPanel p = createStatusBar(jUploadPanel.getStatusLabel(), jUploadPanel);
829         if (null != p) {
830             jUploadPanel.getJComponent().add(p);
831             p.addMouseListener(jUploadPanel.getMouseListener());
832         }
833     }
834 
835     /** {@inheritDoc} */
836     public void updateButtonState(int executionStatus) {
837         // First step: check the parameter.
838         if (executionStatus != UploadPolicy.EXEC_STATUS_READY && executionStatus != UploadPolicy.EXEC_STATUS_UPLOADING) {
839             throw new java.lang.IllegalArgumentException("Unknow value for executionStatus: " + executionStatus);
840         }
841 
842         // Then ... nothing to do! This class has no specific GUI item.
843     }
844 
845     /** @see UploadPolicy#displayErr(Exception) */
846     public void displayErr(Exception e) {
847         displayErr(e.getMessage(), e);
848     }
849 
850     /** @see UploadPolicy#displayErr(String) */
851     public void displayErr(String err) {
852         displayErr(err, null);
853     }
854 
855     /**
856      * Logs a stack trace for the given exception.
857      * 
858      * @param throwable
859      */
860     private void displayStackTrace(Throwable throwable) {
861         if (throwable != null) {
862             ByteArrayOutputStream bs = new ByteArrayOutputStream();
863             PrintStream ps = new PrintStream(bs);
864             throwable.printStackTrace(ps);
865             ps.close();
866             displayMsg("", bs.toString());
867 
868             // If there is a cause, let's be sure its stack trace is displayed.
869             if (throwable.getCause() != null) {
870                 displayMsg("", "Caused by:");
871                 displayStackTrace(throwable.getCause());
872             }
873         }
874     }
875 
876     /**
877      * This method just logs an error.
878      * 
879      * @param errorText
880      * @param exception
881      */
882     private void logErr(String errorText, Exception exception) {
883         if (exception == null) {
884             setLastException(new JUploadException("errorText"));
885         } else if (exception instanceof JUploadException) {
886             setLastException((JUploadException) exception);
887         } else {
888             setLastException(new JUploadException(exception));
889         }
890 
891         // Default behavior: if debugLevel is 0, and an error occurs, we force
892         // the debug level to 1: this makes the log window become visible, if it
893         // was hidden.
894         if (getDebugLevel() == 0)
895             setDebugLevel(1);
896 
897         String exceptionMsg = null;
898         String exceptionClassName = null;
899         String logMsg = errorText;
900 
901         // First, we construct the exception class name.
902         if (exception == null) {
903             exceptionClassName = "";
904         } else if (exception instanceof JUploadException) {
905             exceptionClassName = "[" + ((JUploadException) exception).getClassNameAndClause() + "] ";
906         } else {
907             exceptionClassName = "[" + exception.getClass().getName() + "] ";
908         }
909 
910         // Then, the message body can be completed by the exception message.
911         if (exception != null) {
912             // Ok, we have an exception.
913             if (exception.getCause() != null) {
914                 exceptionMsg = exception.getCause().getMessage();
915             } else {
916                 exceptionMsg = exception.getMessage();
917             }
918             logMsg = exceptionMsg + " (" + errorText + ")";
919         }
920 
921         // Add the message to the log window
922         displayMsg("[ERROR]", exceptionClassName + logMsg);
923         // Let's display the stack trace, if relevant.
924         displayStackTrace(exception);
925 
926         // Then we copy the debug output to the clipboard, and say it to the
927         // current user.
928         if (this.juploadContext.getUploadPanel() != null && getDebugLevel() >= 99) {
929             // Ok, the applet has been fully built.
930             this.juploadContext.getUploadPanel().copyLogWindow();
931             alert("messageLogWindowCopiedToClipboard");
932         }
933 
934     }
935 
936     /**
937      * If debug is off, the log window may not be visible. We switch the debug to on, to be sure that some information
938      * will be displayed to the user. <BR>
939      * If debug is -1, the log window remains hidden.
940      * 
941      * @see wjhk.jupload2.policies.UploadPolicy#displayErr(java.lang.String, java.lang.Exception, int)
942      */
943     public int displayErr(String errorText, Exception exception, int optionTypes) {
944         // Then, we display it to the user.
945         String alertMsg = errorText;
946         // Then, the message body can be completed by the exception message.
947         if (exception != null && (errorText == null || errorText.equals(""))) {
948             // Ok, we have an exception.
949             if (exception.getCause() != null) {
950                 alertMsg = exception.getCause().getMessage();
951             } else {
952                 alertMsg = exception.getMessage();
953             }
954         }
955 
956         // The message displayed depend on the debug level:
957         if (getDebugLevel() >= 30 && exception != null) {
958             alertMsg = exception.getClass().getName() + ": " + alertMsg;
959         }
960 
961         // Display the message to the user. The kind of alert box depends on the
962         // given options:
963         int buttonClicked = 0;
964         switch (optionTypes) {
965             case -1:
966                 // Standard message box.
967                 alertStr(alertMsg);
968                 buttonClicked = JOptionPane.OK_OPTION;
969                 break;
970             case JOptionPane.OK_CANCEL_OPTION:
971             case JOptionPane.YES_NO_CANCEL_OPTION:
972             case JOptionPane.YES_NO_OPTION:
973                 buttonClicked = confirmDialogStr(alertMsg, optionTypes);
974                 break;
975             default:
976                 // This is a problem. Let's display it to the user as a standard
977                 // alert box.
978                 alertStr(alertMsg);
979                 buttonClicked = JOptionPane.OK_OPTION;
980                 // Then, we log this new problem.
981                 String msg = "Unknown optionType in displayErr(String, Exception, int)";
982                 alertStr(msg);
983                 logErr(msg, null);
984         }
985 
986         // First, we log the error.
987         logErr(errorText, exception);
988 
989         return buttonClicked;
990     }
991 
992     /**
993      * If debug is off, the log window may not be visible. We switch the debug to on, to be sure that some information
994      * will be displayed to the user. <BR>
995      * If debug is -1, the log window remains hidden.
996      * 
997      * @see wjhk.jupload2.policies.UploadPolicy#displayErr(java.lang.String, java.lang.Exception)
998      */
999     public void displayErr(String errorText, Exception exception) {
1000         displayErr(errorText, exception, -1);
1001     }
1002 
1003     /**
1004      * @see UploadPolicy#displayInfo(String)
1005      */
1006     public void displayInfo(String info) {
1007         displayMsg("[INFO]", info);
1008     }
1009 
1010     /**
1011      * @see UploadPolicy#displayWarn(String)
1012      */
1013     public void displayWarn(String warn) {
1014         displayMsg("[WARN]", warn);
1015     }
1016 
1017     /**
1018      * @see UploadPolicy#displayDebug(String, int)
1019      */
1020     public void displayDebug(String debug, int minDebugLevel) {
1021         final String tag = "[DEBUG]";
1022         if (this.debugLevel >= minDebugLevel) {
1023             // displayMsg will add the message to the debugStrignBuffer.
1024             displayMsg(tag, debug);
1025         } else if (this.debugGenerateFile) {
1026             // We have to write the message to the debug file, whatever the
1027             // debugLevel is.
1028             addMsgToDebugLog(tag + debug);
1029         }
1030     }
1031 
1032     /** @see UploadPolicy#getLocalizedString(String, Object...) */
1033     public String getLocalizedString(String key, Object... args) {
1034         String ret = this.resourceBundle.getString(key);
1035         try {
1036             // We have to recreate the correct call to String.format
1037             switch (args.length) {
1038                 case 0:
1039                     return String.format(ret);
1040                 case 1:
1041                     return String.format(ret, args[0]);
1042                 case 2:
1043                     return String.format(ret, args[0], args[1]);
1044                 case 3:
1045                     return String.format(ret, args[0], args[1], args[2]);
1046                 case 4:
1047                     return String.format(ret, args[0], args[1], args[2], args[3]);
1048                 case 5:
1049                     return String.format(ret, args[0], args[1], args[2], args[3], args[4]);
1050                 case 6:
1051                     return String.format(ret, args[0], args[1], args[2], args[3], args[4], args[5]);
1052                 case 7:
1053                     return String.format(ret, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
1054                 default:
1055                     throw new IllegalArgumentException(
1056                             "DefaultUploadPolicy.getLocalizedString accepts up to 7 variable parameters ("
1057                                     + args.length + " values were given for the 'args' argument");
1058             }
1059         } catch (IllegalFormatException ife) {
1060             displayErr(ife.getClass().getName() + " (" + ife.getMessage() + ")when managing this string: " + ret);
1061             throw ife;
1062         }
1063     }
1064 
1065     /**
1066      * @see UploadPolicy#getUploadFilename(FileData, int)
1067      */
1068     public String getUploadFilename(FileData fileData, int index) throws JUploadException {
1069         return getEncodedFilename(fileData.getFileName());
1070     }
1071 
1072     /**
1073      * returns the filename and encodes it, if necessary
1074      * 
1075      * @param filename the original filename
1076      * @return filename (encoded, if necessary)
1077      * @throws JUploadException
1078      */
1079     protected final String getEncodedFilename(String filename) throws JUploadException {
1080         if (this.filenameEncoding == null || this.filenameEncoding.equals("")) {
1081             return filename;
1082         }
1083         try {
1084             return URLEncoder.encode(filename, this.filenameEncoding);
1085         } catch (UnsupportedEncodingException e) {
1086             throw new JUploadException(e);
1087         }
1088     }
1089 
1090     /** @see UploadPolicy#getUploadName(FileData, int) */
1091     public String getUploadName(FileData fileData, int index) throws JUploadException {
1092         if (this.httpUploadParameterType.equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ARRAY)) {
1093             return this.httpUploadParameterName + "[]";
1094         } else if (this.httpUploadParameterType.equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ITERATION)) {
1095             return this.httpUploadParameterName + index;
1096         } else if (this.httpUploadParameterType.equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ONE_FILE)) {
1097             // Only valid if nbFilesPerRequest is 1. Let's check it.
1098             if (getNbFilesPerRequest() == 1) {
1099                 return this.httpUploadParameterName;
1100             } else {
1101                 throw new JUploadException(UploadPolicy.PROP_HTTP_UPLOAD_PARAMETER_TYPE + " value '"
1102                         + this.httpUploadParameterType + "' is only valid when '"
1103                         + UploadPolicy.PROP_NB_FILES_PER_REQUEST + " is 1.");
1104             }
1105         } else {
1106             throw new JUploadException(UploadPolicy.PROP_HTTP_UPLOAD_PARAMETER_TYPE + " '"
1107                     + this.httpUploadParameterType + "' is not implemented.");
1108         }
1109     }
1110 
1111     /** @see UploadPolicy#getHttpUploadParameterName() */
1112     public String getHttpUploadParameterName() {
1113         return this.httpUploadParameterName;
1114     }
1115 
1116     /**
1117      * Setter for the {@link #httpUploadParameterName}. This value is used by the {@link #getUploadName(FileData, int)}
1118      * method, to generate the name of the upload parameter that will contain the uploaded file.<BR>
1119      * The name must begin by a letter, then contain letter or numbers
1120      * 
1121      * @throws JUploadException When the given value is invalid (null, empty string, or contains other characters than
1122      *             letters and/or numbers)
1123      */
1124     protected void setHttpUploadParameterName(String httpUploadParameterName) throws JUploadException {
1125         // Some useful checks.
1126         if (httpUploadParameterName == null || httpUploadParameterName.equals("")) {
1127             throw new JUploadException("httpUploadParameterName may not be null");
1128         }
1129         // Control the parameter name content.
1130         if (!httpUploadParameterName.matches("^[a-zA-Z0-9][a-zA-Z0-9_]*$")) {
1131             throw new JUploadException(
1132                     "httpUploadParameterName may only contain letters (lowercase or uppercase) and numbers.");
1133         }
1134 
1135         // Ok, we're happy with the given value. Let's store it.
1136         this.httpUploadParameterName = httpUploadParameterName;
1137     }
1138 
1139     /** @see UploadPolicy#getHttpUploadParameterType() */
1140     public String getHttpUploadParameterType() {
1141         return this.httpUploadParameterType;
1142     }
1143 
1144     /**
1145      * Setter for the {@link #httpUploadParameterType}. This value is used by the {@link #getUploadName(FileData, int)}
1146      * method, to generate the name of the upload parameter that will contain the uploaded file. Depending on this
1147      * value, the parameter will be an iteration or an array.
1148      * 
1149      * @throws JUploadException
1150      */
1151     protected void setHttpUploadParameterType(String httpUploadParameterType) throws JUploadException {
1152         // Some useful checks.
1153         if (httpUploadParameterType == null) {
1154             throw new JUploadException("httpUploadParameterType may not be null");
1155         }
1156 
1157         // Check against the list of allowed values
1158         if (!httpUploadParameterType.equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ARRAY)
1159                 && !httpUploadParameterType.equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ITERATION)
1160                 && !httpUploadParameterType.equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ONE_FILE)) {
1161             throw new JUploadException("'" + httpUploadParameterType
1162                     + "' is not an allowed value for httpUploadParameterType.");
1163         }
1164 
1165         // OneFile is only valid ... when we upload file per file !
1166         if (httpUploadParameterType.equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ONE_FILE)) {
1167             if (getNbFilesPerRequest() != 1) {
1168                 throw new JUploadException("'" + httpUploadParameterType
1169                         + "' is only valid when nbFilesPerRequest is 1.");
1170             }
1171         }
1172 
1173         // Ok, we're happy. Let's store the value !
1174         this.httpUploadParameterType = httpUploadParameterType;
1175     }
1176 
1177     /** @see wjhk.jupload2.policies.UploadPolicy#beforeUpload() */
1178     public boolean beforeUpload() {
1179         // Default : nothing to do before upload, so we're ready.
1180         return true;
1181     }
1182 
1183     /** @see UploadPolicy#onAppendHeader(ByteArrayEncoder) */
1184     public ByteArrayEncoder onAppendHeader(ByteArrayEncoder bae) throws JUploadIOException {
1185         Iterator<String> it = this.headers.iterator();
1186         String header;
1187         displayDebug("[onAppendHeader] Start", 80);
1188         while (it.hasNext()) {
1189             header = it.next();
1190             if (header == null || header.equals("")) {
1191                 displayWarn("[onAppendHeader] Found one empty header. Ignoring it.");
1192             } else {
1193                 bae.append(header).append("\r\n");
1194                 displayDebug("[onAppendHeader] Header appended; " + header, 80);
1195             }
1196         }
1197         displayDebug("[onAppendHeader] End", 80);
1198         return bae;
1199     }// appendHeader
1200 
1201     /**
1202      * Default implementation of the
1203      * {@link wjhk.jupload2.policies.UploadPolicy#onFileSelected(wjhk.jupload2.filedata.FileData)} . Nothing's done.
1204      */
1205     public void onFileSelected(FileData fileData) {
1206         // Default implementation : no action
1207     }
1208 
1209     /**
1210      * Default implementation of the {@link wjhk.jupload2.policies.UploadPolicy#onFileDoubleClicked(FileData)} .
1211      * Nothing's done.
1212      */
1213     public void onFileDoubleClicked(FileData fileData) {
1214         // Default implementation : no action
1215     }
1216 
1217     /** @see UploadPolicy#sendDebugInformation(String, Exception) */
1218     public void sendDebugInformation(String description, Exception exception) {
1219         try {
1220             if (null == getUrlToSendErrorTo()) {
1221                 displayInfo("getUrlToSendErrorTo is null. No debug information is sent.");
1222                 if (exception == null) {
1223                     displayInfo("  No exception was stored!");
1224                 } else {
1225                     displayInfo("  The exception was: " + exception.getClass().getName() + exception.getMessage());
1226                 }
1227             } else {
1228                 displayInfo("Sending debug information to " + getUrlToSendErrorTo());
1229                 if (JOptionPane.showConfirmDialog(null, getLocalizedString("questionSendMailOnError"),
1230                         getLocalizedString("Confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
1231                     displayDebug("[sendDebugInformation] Within response == true", 30);
1232 
1233                     String action = null;
1234                     String line;
1235                     HTTPConnectionHelper connectionHelper = null;
1236                     boolean localDebugOk = this.debugOk;
1237 
1238                     try {
1239                         URL url = new URL(this.urlToSendErrorTo);
1240                         connectionHelper = new HTTPConnectionHelper(this);
1241                         connectionHelper.initRequest(url, "POST", false, true);
1242 
1243                         ByteArrayEncoder baeContent = new ByteArrayEncoderHTTP(this, connectionHelper
1244                                 .getByteArrayEncoder().getBoundary(), connectionHelper.getByteArrayEncoder()
1245                                 .getEncoding());
1246                         // The message is written in English, as it is not sure
1247                         // that
1248                         // the webmaster speaks the same language as the current
1249                         // user.
1250                         baeContent.appendTextProperty("description", "An error occured during upload, in JUpload.", -1);
1251                         String exceptionClass = null;
1252                         String exceptionCause = null;
1253                         String exceptionStackTrace = null;
1254                         if (exception != null) {
1255                             exceptionClass = exception.getClass().getName();
1256                             if (exception.getCause() != null) {
1257                                 exceptionCause = exception.getCause().getClass().getName();
1258                             }
1259                             StackTraceElement[] elements = exception.getStackTrace();
1260                             ByteArrayEncoderHTTP baeStackTrace = new ByteArrayEncoderHTTP(this, connectionHelper
1261                                     .getByteArrayEncoder().getBoundary(), connectionHelper.getByteArrayEncoder()
1262                                     .getEncoding());
1263                             for (int i = 0; i < elements.length; i += 1) {
1264                                 baeStackTrace.append(" at ");
1265                                 baeStackTrace.append(elements[i].getClassName());
1266                                 baeStackTrace.append(".");
1267                                 baeStackTrace.append(elements[i].getMethodName());
1268                                 baeStackTrace.append("() [line ");
1269                                 baeStackTrace.append(Integer.toString(elements[i].getLineNumber()));
1270                                 baeStackTrace.append("]\r\n");
1271                             }
1272                             baeStackTrace.close();
1273                             exceptionStackTrace = baeStackTrace.getString();
1274                         }
1275                         baeContent.appendTextProperty("exceptionClass", exceptionClass, -1);
1276                         baeContent.appendTextProperty("exceptionCause", exceptionCause, -1);
1277                         baeContent.appendTextProperty("exceptionStackTrace", exceptionStackTrace, -1);
1278 
1279                         String baeBound = connectionHelper.getByteArrayEncoder().getBoundary();
1280                         String baeEncoding = connectionHelper.getByteArrayEncoder().getEncoding();
1281                         ByteArrayEncoder baeDebug = new ByteArrayEncoderHTTP(this, baeBound, baeEncoding);
1282                         if (this.debugGenerateFile) {
1283                             // During debug output, we need to make sure that
1284                             // the debug log is not changed, so we set debugOk
1285                             // to false temporarily. -> Everything goes to
1286                             // stdout.
1287                             action = "flush (debugGenerateFile=true)";
1288                             synchronized (this) {
1289                                 this.debugOut.flush();
1290                                 this.debugOk = false;
1291                                 // First, calculate the size of the strings we
1292                                 // will
1293                                 // send.
1294                                 action = "read debug file (debugGenerateFile=true)";
1295                                 BufferedReader debugIn = new BufferedReader(new FileReader(this.debugFile));
1296                                 while ((line = debugIn.readLine()) != null) {
1297                                     baeDebug.append(line).append("\r\n");
1298                                 }
1299                                 debugIn.close();
1300 
1301                                 // We are done with the debug log, so re-enable
1302                                 // it.
1303                                 this.debugOk = localDebugOk;
1304                             }// synchronized(this)
1305                         }// if (this.debugGenerateFile)
1306                         else {
1307                             action = "read debug file (debugGenerateFile=false)";
1308                             baeDebug.append(this.juploadContext.getLogWindow().getText());
1309                         }
1310                         action = "baeDebug.close()";
1311                         baeDebug.close();
1312 
1313                         baeContent.appendTextProperty("debugOutput", baeDebug.getString(), -1);
1314                         baeContent.appendEndPropertyList();
1315                         // The content has been built.
1316                         baeContent.close();
1317 
1318                         // byteArrayEncoder
1319                         // .append("Content-type:
1320                         // application/x-www-form-urlencoded\r\n");
1321                         action = "send request";
1322                         connectionHelper.append("Content-Type: multipart/form-data; boundary=")
1323                                 .append(connectionHelper.getBoundary().substring(2)).append("\r\n");
1324                         connectionHelper.append("Content-length: ")
1325                                 .append(String.valueOf(baeContent.getEncodedLength())).append("\r\n");
1326 
1327                         // Let's send the headers (without baeDescription) ...
1328                         connectionHelper.sendRequest();
1329                         // Blank line (end of header)
1330                         connectionHelper.append("\r\n");
1331                         connectionHelper.append(baeContent);
1332 
1333                         action = "connectionHelper.readHttpResponse()";
1334                         int status = connectionHelper.readHttpResponse();
1335 
1336                         displayDebug(
1337                                 "========================================================================================",
1338                                 90);
1339                         displayDebug(
1340                                 "==================      sendDebugInformation [start]   =================================",
1341                                 90);
1342                         displayDebug(
1343                                 "========================================================================================",
1344                                 90);
1345                         displayDebug("[sendDebugInformation] Sent to server: \r\n"
1346                                 + connectionHelper.getByteArrayEncoder().getString(), 90);
1347                         displayDebug(
1348                                 "========================================================================================",
1349                                 90);
1350                         displayDebug("[sendDebugInformation] Body received: \r\n" + connectionHelper.getResponseBody(),
1351                                 90);
1352                         displayDebug(
1353                                 "========================================================================================",
1354                                 90);
1355                         displayDebug(
1356                                 "==================      sendDebugInformation [end]     =================================",
1357                                 90);
1358                         displayDebug(
1359                                 "========================================================================================",
1360                                 90);
1361 
1362                         // Is our upload a success ?
1363                         if (!checkUploadSuccess(status, connectionHelper.getResponseMsg(),
1364                                 connectionHelper.getResponseBody())) {
1365                             throw new JUploadExceptionUploadFailed(getLocalizedString("errHttpResponse"));
1366                         }
1367 
1368                         displayInfo("debug information sent correctly");
1369                     } catch (MalformedURLException e) {
1370                         throw new JUploadIOException("Malformed URL Exception for " + this.urlToSendErrorTo, e);
1371                     } catch (Exception e) {
1372                         this.debugOk = localDebugOk;
1373                         displayErr(getLocalizedString("errDuringLogManagement") + " (" + action + ")", e);
1374                     } finally {
1375                         this.debugOk = localDebugOk;
1376                     }
1377                 }
1378             }
1379         } catch (JUploadIOException e) {
1380             displayErr("Could not send debug information", e);
1381         }
1382     }// sendDebugInformation
1383 
1384     /**
1385      * This method manages all applet parameters. It allows javascript to update their value, for instance after the
1386      * user chooses a value in a list ...
1387      * 
1388      * @throws JUploadException
1389      * @see wjhk.jupload2.policies.UploadPolicy#setProperty(java.lang.String, java.lang.String)
1390      */
1391     public void setProperty(String prop, String value) throws JUploadException {
1392 
1393         displayDebug("[DefaultUploadPolicy] Call of setProperty: " + prop + " => " + value, 30);
1394 
1395         if (prop.equals(PROP_AFTER_UPLOAD_URL)) {
1396             setAfterUploadURL(value);
1397         } else if (prop.equals(PROP_ALLOW_HTTP_PERSISTENT)) {
1398             setAllowHttpPersistent(Boolean.parseBoolean(value));
1399         } else if (prop.equals(PROP_ALLOWED_FILE_EXTENSIONS)) {
1400             setAllowedFileExtensions(value);
1401         } else if (prop.equals(PROP_DEBUG_LEVEL)) {
1402             setDebugLevel(this.juploadContext.parseInt(value, this.debugLevel));
1403         } else if (prop.equals(PROP_FILE_CHOOSER_ICON_FROM_FILE_CONTENT)) {
1404             setFileChooserIconFromFileContent(this.juploadContext.parseInt(value, getFileChooserIconFromFileContent()));
1405         } else if (prop.equals(PROP_FILE_CHOOSER_ICON_SIZE)) {
1406             setFileChooserIconSize(this.juploadContext.parseInt(value, getFileChooserIconSize()));
1407         } else if (prop.equals(PROP_FILE_FILTER_NAME)) {
1408             setFileFilterName(value);
1409         } else if (prop.equals(PROP_FILENAME_ENCODING)) {
1410             setFilenameEncoding(value);
1411         } else if (prop.equals(PROP_LANG)) {
1412             setLang(value);
1413         } else if (prop.equals(PROP_LOOK_AND_FEEL)) {
1414             setLookAndFeel(value);
1415         } else if (prop.equals(PROP_MAX_CHUNK_SIZE)) {
1416             setMaxChunkSize(this.juploadContext.parseLong(value, this.maxChunkSize));
1417         } else if (prop.equals(PROP_MAX_FILE_SIZE)) {
1418             setMaxFileSize(this.juploadContext.parseLong(value, this.maxFileSize));
1419         } else if (prop.equals(PROP_NB_FILES_PER_REQUEST)) {
1420             setNbFilesPerRequest(this.juploadContext.parseInt(value, this.nbFilesPerRequest));
1421         } else if (prop.equals(PROP_POST_URL)) {
1422             setPostURL(value);
1423         } else if (prop.equals(PROP_SERVER_PROTOCOL)) {
1424             // No specific action: the computeServerProtocol() is called once everything is initialized,
1425             // and the applet is ready for the user. This allows to give the 'hand' to the user quicker.
1426             // HttpProtocolFinderThread.computeServerProtocol(this, value);
1427         } else if (prop.equals(PROP_STRING_UPLOAD_SUCCESS)) {
1428             setStringUploadSuccess(value);
1429         } else if (prop.equals(PROP_SSL_VERIFY_CERT)) {
1430             setSslVerifyCert(value);
1431         } else if (prop.equals(PROP_URL_TO_SEND_ERROR_TO)) {
1432             setUrlToSendErrorTo(value);
1433         } else {
1434             displayWarn("Unknown applet parameter: " + prop + " (in DefaultUploadPolicy.setProperty)");
1435         }
1436     }
1437 
1438     /**
1439      * This method displays the applet parameter list, according to the current debugLevel. It is called by the
1440      * {@link #setDebugLevel(int)} method. It should be override by any subclasses, that should display its own
1441      * parameters, then call <I>super.displayParameterStatus()</I>.
1442      * 
1443      * @see UploadPolicy#displayParameterStatus()
1444      */
1445     public void displayParameterStatus() {
1446         displayDebug("=======================================================================", 30);
1447         displayDebug("======= Parameters managed by DefaultUploadPolicy", 30);
1448         // /////////////////////////////////////////////////////////////////////////////
1449         // Let's display some information to the user, about the received
1450         // parameters.
1451         displayInfo("JUpload applet, version " + this.juploadContext.getDetailedVersionMessage() + " (compiled: "
1452                 + this.juploadContext.getBuildDate() + "), available at http://jupload.sourceforge.net/");
1453         displayDebug("Java version: " + System.getProperty("java.version"), 30);
1454 
1455         displayDebug("List of all applet parameters:", 30);
1456         displayDebug("  language: " + this.resourceBundle.getLocale().getLanguage(), 30);
1457         displayDebug("  country: " + this.resourceBundle.getLocale().getCountry(), 30);
1458 
1459         displayDebug(PROP_AFTER_UPLOAD_URL + ": " + getAfterUploadURL(), 30);
1460         displayDebug(PROP_ALLOW_HTTP_PERSISTENT + ": " + getAllowHttpPersistent(), 30);
1461         displayDebug(PROP_ALLOWED_FILE_EXTENSIONS + ": " + getAllowedFileExtensions(), 30);
1462         displayDebug(PROP_BROWSING_DIRECTORY + " (current value): " + getCurrentBrowsingDirectory(), 30);
1463         displayDebug(PROP_DEBUG_LEVEL + ": " + this.debugLevel, 1);
1464         synchronized (this) {
1465             if (this.debugGenerateFile) {
1466                 displayDebug("  (debugfile: " + this.debugFile.getAbsolutePath() + ")", 1);
1467             }
1468         }
1469         displayDebug(PROP_FILE_CHOOSER_ICON_FROM_FILE_CONTENT + ": " + getFileChooserIconFromFileContent(), 30);
1470         displayDebug(PROP_FILE_CHOOSER_ICON_SIZE + ": " + getFileChooserIconSize(), 30);
1471         displayDebug(PROP_FILE_FILTER_NAME + ": " + getFileFilterName(), 30);
1472         displayDebug(PROP_FILE_LIST_VIEW_MODE + ": " + getFileListViewMode(), 30);
1473         displayDebug(PROP_FILENAME_ENCODING + ": " + getFilenameEncoding(), 30);
1474         displayDebug(PROP_FORMDATA + ": " + getFormdata(), 30);
1475         displayDebug(PROP_FTP_CREATE_DIRECTORY_STRUCTURE + ": " + getFtpCreateDirectoryStructure(), 30);
1476         displayDebug(PROP_FTP_TRANSFERT_BINARY + ": " + getFtpTransfertBinary(), 30);
1477         displayDebug(PROP_FTP_TRANSFERT_PASSIVE + ": " + getFtpTransfertPassive(), 30);
1478         displayDebug(PROP_HTTP_UPLOAD_PARAMETER_NAME + ": " + getHttpUploadParameterName(), 30);
1479         displayDebug(PROP_HTTP_UPLOAD_PARAMETER_TYPE + ": " + getHttpUploadParameterType(), 30);
1480         displayDebug("lang: " + this.lang, 30);
1481         displayDebug(PROP_MAX_CHUNK_SIZE + ": " + getMaxChunkSize(), 30);
1482         if (this.maxFileSize == Long.MAX_VALUE) {
1483             // If the maxFileSize was not given, we display its value only
1484             // in debug mode.
1485             displayDebug(PROP_MAX_FILE_SIZE + ": " + getMaxFileSize(), 30);
1486         } else {
1487             // If the maxFileSize was given, we always inform the user.
1488             displayInfo(PROP_MAX_FILE_SIZE + ": " + getMaxFileSize());
1489         }
1490         displayDebug(PROP_NB_FILES_PER_REQUEST + ": " + getNbFilesPerRequest(), 30);
1491         displayDebug(PROP_POST_URL + ": " + this.postURL, 30);
1492         displayDebug(PROP_READ_COOKIE_FROM_NAVIGATOR + ": " + this.readCookieFromNavigator, 30);
1493         displayDebug(PROP_READ_USER_AGENT_FROM_NAVIGATOR + ": " + this.readUserAgentFromNavigator, 30);
1494         displayDebug(PROP_RETRY_MAX_NUMBER_OF + ": " + this.retryMaxNumberOf, 30);
1495         displayDebug(PROP_RETRY_NB_SECONDS_BETWEEN + ": " + this.retryNbSecondsBetween, 30);
1496         displayDebug(PROP_SEND_MD5_SUM + ": " + getSendMD5Sum(), 30);
1497         displayDebug(PROP_SERVER_PROTOCOL + ": " + getServerProtocol(), 30);
1498         displayDebug(PROP_SHOW_LOGWINDOW + ": " + getShowLogWindow(), 30);
1499         displayDebug(PROP_SHOW_STATUSBAR + ": " + this.showStatusbar, 30);
1500         displayDebug(PROP_SPECIFIC_HEADERS + ": " + getSpecificHeaders(), 30);
1501 
1502         displayDebug("Headers that will be added to the POST request: ", 30);
1503         for (Iterator<String> it = this.headers.iterator(); it.hasNext();) {
1504             displayDebug(it.next() + "\n", 30);
1505         }
1506         displayDebug(PROP_STRING_UPLOAD_ERROR + ": " + getStringUploadError(), 30);
1507         displayDebug(PROP_STRING_UPLOAD_SUCCESS + ": " + getStringUploadSuccess(), 30);
1508         displayDebug(PROP_STRING_UPLOAD_WARNING + ": " + getStringUploadWarning(), 30);
1509         displayDebug(PROP_URL_TO_SEND_ERROR_TO + ": " + getUrlToSendErrorTo(), 30);
1510         displayDebug("", 30);
1511     }
1512 
1513     // //////////////////////////////////////////////////////////////////////////////////////////////
1514     // /////////////////// getters / setters
1515     // ///////////////////////////////////////////////////
1516     // //////////////////////////////////////////////////////////////////////////////////////////////
1517 
1518     /** @see UploadPolicy#getAfterUploadURL() */
1519     public String getAfterUploadURL() {
1520         return this.afterUploadURL;
1521     }
1522 
1523     /**
1524      * Set the {@link #afterUploadURL}
1525      * 
1526      * @param afterUploadURL The URL to use.
1527      * @throws JUploadException
1528      */
1529     protected void setAfterUploadURL(String afterUploadURL) throws JUploadException {
1530         if (null == afterUploadURL)
1531             return;
1532         if (afterUploadURL.toLowerCase().startsWith("javascript:")) {
1533             this.afterUploadURL = afterUploadURL;
1534         } else
1535             this.afterUploadURL = this.juploadContext.normalizeURL(afterUploadURL);
1536     }
1537 
1538     /**
1539      * @see wjhk.jupload2.policies.UploadPolicy#getAllowHttpPersistent()
1540      */
1541     public boolean getAllowHttpPersistent() {
1542         return this.allowHttpPersistent;
1543     }
1544 
1545     /** @see UploadPolicy#getAllowedFileExtensions() */
1546     public String getAllowedFileExtensions() {
1547         return this.allowedFileExtensions;
1548     }
1549 
1550     /**
1551      * @param allowedFileExtensions the allowedFileExtensions to set
1552      */
1553     protected void setAllowedFileExtensions(String allowedFileExtensions) {
1554         if (allowedFileExtensions == null || allowedFileExtensions.equals("")) {
1555             this.allowedFileExtensions = null;
1556         } else {
1557             this.allowedFileExtensions = (allowedFileExtensions.startsWith("/") ? "" : "/")
1558                     + allowedFileExtensions.toLowerCase() + (allowedFileExtensions.endsWith("/") ? "" : "/");
1559         }
1560     }
1561 
1562     protected void setAllowHttpPersistent(boolean value) {
1563         this.allowHttpPersistent = value;
1564     }
1565 
1566     /** @see UploadPolicy#getContext() */
1567     public JUploadContext getContext() {
1568         return this.juploadContext;
1569     }
1570 
1571     /** {@inheritDoc} */
1572     public void setCurrentBrowsingDirectory(File currentBrowsingDirectoryParam) {
1573         try {
1574             if (currentBrowsingDirectoryParam.isDirectory()) {
1575                 this.currentBrowsingDirectory = currentBrowsingDirectoryParam;
1576             } else {
1577                 displayWarn("DefaultUploadPolicy.setCurrentBrowsingDirectory(): " + currentBrowsingDirectoryParam
1578                         + " doesn't exist.");
1579             }
1580         } catch (SecurityException se) {
1581             displayWarn(se.getClass().getName() + " in DefaultUploadPolicy.setCurrentBrowsingDirectory(): "
1582                     + currentBrowsingDirectoryParam + " is ignored.");
1583         }
1584     }
1585 
1586     /**
1587      * @param currentBrowsingDirectoryParam The name of the directory that should be the current one.
1588      * @see UploadPolicy#setCurrentBrowsingDirectory(String)
1589      */
1590     public void setCurrentBrowsingDirectory(String currentBrowsingDirectoryParam) {
1591         try {
1592             if (currentBrowsingDirectoryParam == null) {
1593                 this.currentBrowsingDirectory = null;
1594             } else {
1595                 // Apparently, Java deosn't manage path beginning by ~. folder
1596                 // is actually ... ~!
1597                 // Let's manager this.
1598                 if (currentBrowsingDirectoryParam.startsWith("~")) {
1599                     // Let's keep the part of this path that is after the ~
1600                     currentBrowsingDirectoryParam = System.getProperty("user.home")
1601                             + currentBrowsingDirectoryParam.substring(1);
1602                 }
1603 
1604                 this.currentBrowsingDirectory = new File(currentBrowsingDirectoryParam);
1605 
1606                 // Let's check that we have a folder.
1607                 if (this.currentBrowsingDirectory != null && !this.currentBrowsingDirectory.isDirectory()) {
1608                     displayWarn("DefaultUploadPolicy.setCurrentBrowsingDirectory(): <" + currentBrowsingDirectoryParam
1609                             + "> doesn't exist or is not a directory.");
1610                     this.currentBrowsingDirectory = null;
1611                 }
1612             }
1613         } catch (SecurityException se) {
1614             displayWarn(se.getClass().getName() + " in DefaultUploadPolicy.setCurrentBrowsingDirectory(): "
1615                     + currentBrowsingDirectoryParam + " is ignored.");
1616         }
1617     }
1618 
1619     /** @see UploadPolicy#getCurrentBrowsingDirectory() */
1620     public File getCurrentBrowsingDirectory() {
1621         return this.currentBrowsingDirectory;
1622     }
1623 
1624     /** @see UploadPolicy#getDateFormat() */
1625     public String getDateFormat() {
1626         return UploadPolicy.DEFAULT_DATE_FORMAT;
1627     }
1628 
1629     /** @see UploadPolicy#getDebugLevel() */
1630     public int getDebugLevel() {
1631         return this.debugLevel;
1632     }
1633 
1634     /** @see UploadPolicy#setDebugLevel(int) */
1635     public void setDebugLevel(int debugLevel) {
1636         setDebugLevel(debugLevel, true);
1637     }
1638 
1639     /**
1640      * Set the debug level.
1641      * 
1642      * @param debugLevel The new debuglevel.
1643      * @param displayAppletParameterList Flag. If set to true, the applet's parameters are shown.
1644      */
1645     public synchronized void setDebugLevel(int debugLevel, boolean displayAppletParameterList) {
1646         // If the debugLevel was previously set, we inform the user of this
1647         // change.
1648         if (this.debugLevel >= 0) {
1649             displayInfo("Debug level set to " + debugLevel);
1650             if (this.debugGenerateFile) {
1651                 displayInfo("Current debug output file: " + this.debugFile.getAbsolutePath());
1652             }
1653         }
1654         this.debugLevel = debugLevel;
1655 
1656         // Let's display the current applet parameters.
1657         if (displayAppletParameterList) {
1658             displayParameterStatus();
1659         }
1660     }
1661 
1662     /**
1663      * Getter for fileChooserIconFromFileContent.
1664      * 
1665      * @return Current value for fileChooserIconFromFileContent
1666      * @see UploadPolicy#PROP_FILE_CHOOSER_ICON_FROM_FILE_CONTENT
1667      */
1668     public int getFileChooserIconFromFileContent() {
1669         return this.fileChooserIconFromFileContent;
1670     }
1671 
1672     /**
1673      * Setter for fileChooserIconFromFileContent. Current allowed values are: -1, 0, 1. Default value is 0.
1674      * 
1675      * @param fileChooserIconFromFileContent Value to be set. If the value is not allowed (not -1, 0 or 1), the current
1676      *            value is unchangeed.
1677      * @exception java.lang.IllegalArgumentException When a value not in -1, 0 1 is given.
1678      * @see UploadPolicy#PROP_FILE_CHOOSER_ICON_FROM_FILE_CONTENT
1679      */
1680     public void setFileChooserIconFromFileContent(int fileChooserIconFromFileContent) {
1681         if (fileChooserIconFromFileContent != -1 && fileChooserIconFromFileContent != 0
1682                 && fileChooserIconFromFileContent != 1) {
1683             throw new java.lang.IllegalArgumentException("fileChooserIconFromFileContent must be one of -1, 0, 1");
1684         }
1685         this.fileChooserIconFromFileContent = fileChooserIconFromFileContent;
1686     }
1687 
1688     /**
1689      * Getter for fileChooserIconSize.
1690      * 
1691      * @return Current value for fileChooserIconSize
1692      * @see UploadPolicy#PROP_FILE_CHOOSER_ICON_SIZE
1693      */
1694     public int getFileChooserIconSize() {
1695         return this.fileChooserIconSize;
1696     }
1697 
1698     /**
1699      * Setter for fileChooserIconSize.
1700      * 
1701      * @param fileChooserIconSize Value to be set.
1702      * @exception java.lang.IllegalArgumentException When a negative value is given.
1703      * @see UploadPolicy#PROP_FILE_CHOOSER_ICON_SIZE
1704      */
1705     public void setFileChooserIconSize(int fileChooserIconSize) {
1706         if (fileChooserIconSize <= 0) {
1707             throw new java.lang.IllegalArgumentException("fileChooserIconSize must be more than 0");
1708         }
1709         this.fileChooserIconSize = fileChooserIconSize;
1710     }
1711 
1712     /** @see wjhk.jupload2.policies.UploadPolicy#setLang(String) */
1713     public void setLang(String lang) {
1714         this.lang = lang;
1715         if (lang == null) {
1716             displayInfo("lang = null, taking default language");
1717             locale = Locale.getDefault();
1718         } else {
1719             // If we have a 5 characters lang string, then it should look like
1720             // ll_CC, where ll is the language code
1721             // and CC is the Country code.
1722             if (lang.length() == 5 && (lang.substring(2, 3).equals("_") || lang.substring(2, 3).equals("-"))) {
1723                 String language = lang.substring(0, 2);
1724                 String country = lang.substring(3, 5);
1725                 displayDebug("setLang - language read: " + language, 50);
1726                 displayDebug("setLang - country read: " + country, 50);
1727                 locale = new Locale(language, country.toUpperCase());
1728             } else {
1729                 locale = new Locale(lang);
1730                 displayDebug("setLang - language read (no country): " + lang, 50);
1731             }
1732         }
1733 
1734         /*
1735          * Patch given by Patrick Use of a specific class loader. The standard ResourceBundle checks first for a class
1736          * that has the name of the resource bundle. Since there is no such class in the jar file, the AppletClassLoader
1737          * makes a http request to the server, which will end with a 404 since there is no such class either. To avoid
1738          * this unnecessary lookup we use a class loader that throws directly a ClassNotFoundException. After looking
1739          * for a class (which is unsuccessful) ResourceBundle looks finally for a properties file. Therefore we delegate
1740          * that lookup to the original class loader since this is in the jar file.
1741          */
1742         this.resourceBundle = ResourceBundle.getBundle("lang.lang", locale,
1743         // Special class loader, see description above
1744                 new ClassLoader(this.getClass().getClassLoader()) {
1745                     /** {@inheritDoc} */
1746                     @Override
1747                     public Class<?> loadClass(String name) throws ClassNotFoundException {
1748                         throw new ClassNotFoundException();
1749                     }
1750 
1751                     /** {@inheritDoc} */
1752                     @Override
1753                     public InputStream getResourceAsStream(String name) {
1754                         return this.getClass().getClassLoader().getResourceAsStream(name);
1755                     }
1756                 });
1757     }
1758 
1759     /** {@inheritDoc} */
1760     public Locale getLocale() {
1761         return this.locale;
1762     }
1763 
1764     /**
1765      */
1766     protected String getLookAndFeel() {
1767         return this.lookAndFeel;
1768     }
1769 
1770     /**
1771      * @param lookAndFeel the lookAndFeel to set
1772      */
1773     protected void setLookAndFeel(String lookAndFeel) {
1774         try {
1775             this.lookAndFeel = lookAndFeel;
1776             if (lookAndFeel != null && !lookAndFeel.equals("") && !lookAndFeel.equals("java")) {
1777                 // We try to call the UIManager.setLookAndFeel() method. We
1778                 // catch
1779                 // all possible exceptions, to prevent
1780                 // that the applet is blocked.
1781                 if (!lookAndFeel.equals("system")) {
1782                     // Correction given by Fritz. Thanks to him.
1783                     UIManager.setLookAndFeel(lookAndFeel);
1784                 } else {
1785                     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1786                 }
1787             } else {
1788                 this.lookAndFeel = "java";
1789                 UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
1790             }
1791         } catch (Exception e) {
1792             displayErr(e);
1793             try {
1794                 this.lookAndFeel = "java";
1795                 UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
1796             } catch (UnsupportedLookAndFeelException e1) {
1797                 displayErr(e1);
1798                 // Hum, hum: we should not arrive here... We not a 'dummy' one.
1799                 this.lookAndFeel = null;
1800             }
1801         }
1802     }
1803 
1804     /** @see wjhk.jupload2.policies.UploadPolicy#getMaxChunkSize() */
1805     public long getMaxChunkSize() {
1806         return this.maxChunkSize;
1807     }
1808 
1809     /**
1810      * If the given value is less or equals to 0, it is set back to Long_MAX_VALUE.
1811      * 
1812      * @param maxChunkSize the maxChunkSize to set
1813      */
1814     protected void setMaxChunkSize(long maxChunkSize) {
1815         if (maxChunkSize <= 0) {
1816             displayDebug("maxChunkSize<=0 which is invalid. Switched to the default value (Long.MAX_VALUE)", 1);
1817             maxChunkSize = Long.MAX_VALUE;
1818         }
1819         this.maxChunkSize = maxChunkSize;
1820     }
1821 
1822     /** @see wjhk.jupload2.policies.UploadPolicy#getMaxFileSize() */
1823     public long getMaxFileSize() {
1824         return this.maxFileSize;
1825     }
1826 
1827     /**
1828      * @param maxFileSize the maxFileSize to set
1829      */
1830     protected void setMaxFileSize(long maxFileSize) {
1831         if (maxFileSize <= 0) {
1832             displayDebug("maxFileSize<=0 which is invalid. Switched to the default value (Long.MAX_VALUE)", 1);
1833             maxFileSize = Long.MAX_VALUE;
1834         }
1835         this.maxFileSize = maxFileSize;
1836     }
1837 
1838     /** @see wjhk.jupload2.policies.UploadPolicy#getNbFilesPerRequest() */
1839     public int getNbFilesPerRequest() {
1840         return this.nbFilesPerRequest;
1841     }
1842 
1843     /**
1844      * @param nbFilesPerRequest the nbFilesPerRequest to set
1845      * @throws JUploadException
1846      */
1847     protected void setNbFilesPerRequest(int nbFilesPerRequest) throws JUploadException {
1848         // If httpUploadParameterType is oneFile,
1849         if (getHttpUploadParameterType().equals(UploadPolicy.HTTPUPLOADPARAMETERTYPE_ONE_FILE)
1850                 && nbFilesPerRequest != 1) {
1851             throw new JUploadException("nbFilesPerRequest must be 1, when httpUploadParameterType is oneFile");
1852         }
1853 
1854         if (nbFilesPerRequest < 1) {
1855             displayDebug("nbFilesPerRequest <1 : switched to the 'unlimited' value (Integer.MAX_VALUE)", 1);
1856             this.nbFilesPerRequest = Integer.MAX_VALUE;
1857         } else {
1858             this.nbFilesPerRequest = nbFilesPerRequest;
1859         }
1860     }
1861 
1862     /** @see UploadPolicy#getFileListViewMode() */
1863     public FileListViewMode getFileListViewMode() {
1864         return fileListViewMode;
1865     }
1866 
1867     /** @see UploadPolicy#getFileListViewMode() */
1868     public void setFileListViewMode(FileListViewMode fileListViewMode) {
1869         this.fileListViewMode = fileListViewMode;
1870     }
1871 
1872     /** @see UploadPolicy#getFilenameEncoding() */
1873     @Deprecated
1874     public String getFilenameEncoding() {
1875         return this.filenameEncoding;
1876     }
1877 
1878     /** @see UploadPolicy#getFileFilterName() */
1879     public String getFileFilterName() {
1880         return this.fileFilterName;
1881     }
1882 
1883     /**
1884      * @param fileFilterName The new name for the fileFilter
1885      * @see UploadPolicy#PROP_FILE_FILTER_NAME
1886      */
1887     protected void setFileFilterName(String fileFilterName) {
1888         this.fileFilterName = fileFilterName;
1889     }
1890 
1891     /**
1892      * @param filenameEncoding the filenameEncoding to set
1893      */
1894     protected void setFilenameEncoding(String filenameEncoding) {
1895         if (filenameEncoding != null && filenameEncoding.equals("")) {
1896             filenameEncoding = null;
1897         }
1898         if (filenameEncoding != null && !Charset.isSupported(filenameEncoding)) {
1899             throw new UnsupportedCharsetException("non supported charset (" + filenameEncoding + ")");
1900         }
1901         this.filenameEncoding = filenameEncoding;
1902     }
1903 
1904     /** @see UploadPolicy#getFtpCreateDirectoryStructure() */
1905     public boolean getFtpCreateDirectoryStructure() {
1906         return this.ftpCreateDirectoryStructure;
1907     }
1908 
1909     /**
1910      * @param ftpCreateDirectoryStructure the ftpCreateDirectoryStructure to set
1911      */
1912     protected void setFtpCreateDirectoryStructure(boolean ftpCreateDirectoryStructure) {
1913         this.ftpCreateDirectoryStructure = ftpCreateDirectoryStructure;
1914     }
1915 
1916     /** @see UploadPolicy#getFtpTransfertBinary() */
1917     public boolean getFtpTransfertBinary() {
1918         return this.ftpTransfertBinary;
1919     }
1920 
1921     /**
1922      * @param ftpTransfertBinary the ftpTransfertBinary to set
1923      */
1924     protected void setFtpTransfertBinary(boolean ftpTransfertBinary) {
1925         this.ftpTransfertBinary = ftpTransfertBinary;
1926     }
1927 
1928     /** @see UploadPolicy#getFtpTransfertPassive() */
1929     public boolean getFtpTransfertPassive() {
1930         return this.ftpTransfertPassive;
1931     }
1932 
1933     /**
1934      * @param ftpTransfertPassive the ftpTransfertPassive to set
1935      */
1936     protected void setFtpTransfertPassive(boolean ftpTransfertPassive) {
1937         this.ftpTransfertPassive = ftpTransfertPassive;
1938     }
1939 
1940     /** @see wjhk.jupload2.policies.UploadPolicy#getPostURL() */
1941     public String getPostURL() {
1942         return this.postURL;
1943     }
1944 
1945     /**
1946      * @throws JUploadException
1947      * @see wjhk.jupload2.policies.UploadPolicy#setPostURL(String)
1948      */
1949     public void setPostURL(String postURL) throws JUploadException {
1950         // Be more forgiving about postURL:
1951         // - If none is specified, use the original DocumentBase of the
1952         // applet.
1953         // - If a non-absolute URI (an URI without protocol and server) is
1954         // specified,
1955         // prefix it with "http://servername"
1956         // - If a relative URI is specified, prefix it with the DocumentBase's
1957         // parent
1958         this.postURL = this.juploadContext.normalizeURL(postURL);
1959     }
1960 
1961     /** @see wjhk.jupload2.policies.UploadPolicy#getReadCookieFromNavigator() */
1962     public boolean getReadCookieFromNavigator() {
1963         return this.readCookieFromNavigator;
1964     }
1965 
1966     /** @see wjhk.jupload2.policies.UploadPolicy#getReadCookieFromNavigator() */
1967     protected void setReadCookieFromNavigator(boolean readCookieFromNavigator) {
1968         this.readCookieFromNavigator = readCookieFromNavigator;
1969     }
1970 
1971     /** @see wjhk.jupload2.policies.UploadPolicy#getReadUserAgentFromNavigator() */
1972     public boolean getReadUserAgentFromNavigator() {
1973         return this.readUserAgentFromNavigator;
1974     }
1975 
1976     /** @see wjhk.jupload2.policies.UploadPolicy#getReadUserAgentFromNavigator() */
1977     protected void setReadUserAgentFromNavigator(boolean readUserAgentFromNavigator) {
1978         this.readUserAgentFromNavigator = readUserAgentFromNavigator;
1979     }
1980 
1981     /** @see UploadPolicy#getRetryMaxNumberOf() */
1982     public int getRetryMaxNumberOf() {
1983         return this.retryMaxNumberOf;
1984     }
1985 
1986     /**
1987      * @param retryMaxNumberOf New value to set for the retryMaxNumberOf applet parameter
1988      * @exception IllegalArgumentException If retryMaxNumberOf is less than 0.
1989      * @see UploadPolicy#getRetryMaxNumberOf()
1990      */
1991     public void setRetryMaxNumberOf(int retryMaxNumberOf) {
1992         if (retryMaxNumberOf < 0) {
1993             throw new IllegalArgumentException("retryMaxNumberOf must be 0 or more");
1994         }
1995         this.retryMaxNumberOf = retryMaxNumberOf;
1996     }
1997 
1998     /** @see UploadPolicy#getRetryNbSecondsBetween() */
1999     public int getRetryNbSecondsBetween() {
2000         return this.retryNbSecondsBetween;
2001     }
2002 
2003     /**
2004      * @param retryNbSecondsBetween New value to set for the retryNbSecondsBetween applet parameter
2005      * @exception IllegalArgumentException If retryNbSecondsBetween is less than 0.
2006      * @see UploadPolicy#getRetryNbSecondsBetween()
2007      */
2008     public void setRetryNbSecondsBetween(int retryNbSecondsBetween) {
2009         if (retryNbSecondsBetween < 0) {
2010             throw new IllegalArgumentException("retryNbSecondsBetween must be 0 or more");
2011         }
2012         this.retryNbSecondsBetween = retryNbSecondsBetween;
2013     }
2014 
2015     /** @see wjhk.jupload2.policies.UploadPolicy#getServerProtocol() */
2016     public String getServerProtocol() {
2017         if (this.serverProtocol == null) {
2018             return DEFAULT_SERVER_PROTOCOL;
2019         } else {
2020             return this.serverProtocol;
2021         }
2022     }
2023 
2024     /** @see UploadPolicy#setServerProtocol(String) */
2025     public void setServerProtocol(String serverProtocol) {
2026         this.serverProtocol = serverProtocol;
2027     }
2028 
2029     /** @see wjhk.jupload2.policies.UploadPolicy#getSendMD5Sum() */
2030     public boolean getSendMD5Sum() {
2031         return this.sendMD5Sum;
2032     }
2033 
2034     /** @see UploadPolicy#setSendMD5Sum(boolean) */
2035     public void setSendMD5Sum(boolean sendMD5Sum) {
2036         this.sendMD5Sum = sendMD5Sum;
2037     }
2038 
2039     /** @see wjhk.jupload2.policies.UploadPolicy#getShowLogWindow() */
2040     public String getShowLogWindow() {
2041         return this.showLogWindow;
2042     }
2043 
2044     /** {@inheritDoc} */
2045     public void setShowLogWindow(String showLogWindow) {
2046         if (showLogWindow.equals(SHOWLOGWINDOW_TRUE) || showLogWindow.equals(SHOWLOGWINDOW_FALSE)
2047                 || showLogWindow.equals(SHOWLOGWINDOW_ONERROR)) {
2048             this.showLogWindow = showLogWindow;
2049             // The log window may become visible or hidden, depending on this
2050             // parameter.
2051             if (this.juploadContext.getUploadPanel() != null) {
2052                 this.juploadContext.getUploadPanel().showOrHideLogWindow();
2053             }
2054         } else {
2055             displayWarn("[setShowLogWindow] Unallowed value: " + showLogWindow + " (showLogWindow is left unchanged)");
2056         }
2057     }
2058 
2059     /** @see wjhk.jupload2.policies.UploadPolicy#getSpecificHeaders() */
2060     public String getSpecificHeaders() {
2061         return this.specificHeaders;
2062     }
2063 
2064     /**
2065      * Set all specific headers defined in the specificHeaders applet parameter. This string is splitted, so that each
2066      * header is added to the headers Vector. These headers are added to the headers list during applet initialization.
2067      * There is currently no automatic way to remove the headers coming from specificHeaders, after initialization.
2068      * 
2069      * @param specificHeaders
2070      */
2071     protected void setSpecificHeaders(String specificHeaders) {
2072         this.specificHeaders = specificHeaders;
2073         if (specificHeaders != null) {
2074             // Let's add each header in specificHeaders to the headers list. In
2075             // specificHeaders, each header is separated by the \n string (two
2076             // characters: \ then n, not the \n character).
2077             // The regexp to find the \n string (not the \n character) is: \\n
2078             // We then double each \ character:
2079             String[] headerArray = specificHeaders.split("\\\\n");
2080             for (int x = 0; x < headerArray.length; x++) {
2081                 addHeader(headerArray[x]);
2082             }
2083         }
2084     }
2085 
2086     /**
2087      * @see wjhk.jupload2.policies.UploadPolicy#getSslVerifyCert()
2088      */
2089     public int getSslVerifyCert() {
2090         return this.sslVerifyCert;
2091     }
2092 
2093     protected void setSslVerifyCert(String mode) throws JUploadException {
2094         int val = -1;
2095         if (mode.toLowerCase().equals("none"))
2096             val = InteractiveTrustManager.NONE;
2097         if (mode.toLowerCase().equals("server"))
2098             val = InteractiveTrustManager.SERVER;
2099         if (mode.toLowerCase().equals("client"))
2100             val = InteractiveTrustManager.CLIENT;
2101         if (mode.toLowerCase().equals("strict"))
2102             val = InteractiveTrustManager.STRICT;
2103         if (val == -1)
2104             throw new JUploadException("Invalid parameter sslVerifyCert (" + mode + ")");
2105         this.sslVerifyCert = val;
2106     }
2107 
2108     /**
2109      * @param show the new showStatusbar value
2110      */
2111     protected void setShowStatusbar(boolean show) {
2112         this.showStatusbar = show;
2113     }
2114 
2115     /** @see wjhk.jupload2.policies.UploadPolicy#getStringUploadError() */
2116     public String getStringUploadError() {
2117         return this.stringUploadError;
2118     }
2119 
2120     /** @see wjhk.jupload2.policies.UploadPolicy#getStringUploadSuccess() */
2121     public String getStringUploadSuccess() {
2122         return this.stringUploadSuccess;
2123     }
2124 
2125     /** @see wjhk.jupload2.policies.UploadPolicy#getStringUploadWarning() */
2126     public String getStringUploadWarning() {
2127         return this.stringUploadWarning;
2128     }
2129 
2130     /**
2131      * @param stringUploadError the stringUploadError to set
2132      * @throws JUploadException
2133      */
2134     protected void setStringUploadError(String stringUploadError) throws JUploadException {
2135         this.stringUploadError = stringUploadError;
2136         if (stringUploadError != null) {
2137             try {
2138                 this.patternError = Pattern.compile(stringUploadError);
2139             } catch (PatternSyntaxException e) {
2140                 throw new JUploadException("Invalid regex in parameter stringUploadError");
2141             }
2142         }
2143     }
2144 
2145     /**
2146      * @param stringUploadSuccess the stringUploadSuccess to set
2147      * @throws JUploadException
2148      */
2149     protected void setStringUploadSuccess(String stringUploadSuccess) throws JUploadException {
2150         this.stringUploadSuccess = stringUploadSuccess;
2151         if (stringUploadSuccess != null) {
2152             try {
2153                 this.patternSuccess = Pattern.compile(stringUploadSuccess);
2154             } catch (PatternSyntaxException e) {
2155                 throw new JUploadException("Invalid regex in parameter stringUploadSuccess");
2156             }
2157         }
2158     }
2159 
2160     /**
2161      * @param stringUploadWarning the stringUploadWarning to set
2162      * @throws JUploadException
2163      */
2164     protected void setStringUploadWarning(String stringUploadWarning) throws JUploadException {
2165         this.stringUploadWarning = stringUploadWarning;
2166         if (stringUploadWarning != null) {
2167             try {
2168                 this.patternWarning = Pattern.compile(stringUploadWarning);
2169             } catch (PatternSyntaxException e) {
2170                 throw new JUploadException("Invalid regex in parameter stringUploadWarning");
2171             }
2172         }
2173     }
2174 
2175     /** @see wjhk.jupload2.policies.UploadPolicy#getUrlToSendErrorTo() */
2176     public String getUrlToSendErrorTo() {
2177         return this.urlToSendErrorTo;
2178     }
2179 
2180     /** {@inheritDoc} */
2181     public void setUrlToSendErrorTo(String urlToSendErrorTo) throws JUploadException {
2182         if (null == urlToSendErrorTo)
2183             return;
2184         String tmp = this.juploadContext.normalizeURL(urlToSendErrorTo);
2185         if (tmp.startsWith("ftp://")) {
2186             throw new JUploadException("urlToSendErrorTo: ftp scheme not supported.");
2187         }
2188         this.urlToSendErrorTo = tmp;
2189     }
2190 
2191     /** @see wjhk.jupload2.policies.UploadPolicy#getFormdata() */
2192     public String getFormdata() {
2193         return this.formData;
2194     }
2195 
2196     /** @see wjhk.jupload2.policies.UploadPolicy#getAfterUploadTarget() */
2197     public String getAfterUploadTarget() {
2198         return this.afterUploadTarget;
2199     }
2200 
2201     // //////////////////////////////////////////////////////////////////////////////////////////////
2202     // /////////////////// Internal methods
2203     // //////////////////////////////////////////////////////////////////////////////////////////////
2204 
2205     /**
2206      * Delete the current log. (called upon applet termination)
2207      */
2208     public synchronized void deleteLog() {
2209         if (this.debugGenerateFile) {
2210             try {
2211                 if (null != this.debugOut) {
2212                     this.debugOut.close();
2213                     this.debugOut = null;
2214                 }
2215                 if (null != this.debugFile) {
2216                     if (!this.debugFile.delete()) {
2217                         displayWarn(this.debugFile.getName() + " was not correctly removed!");
2218                     }
2219                     this.debugFile = null;
2220                 }
2221             } catch (Exception e) {
2222                 // nothing to do: we mask the exception.
2223                 displayWarn(e.getClass().getName() + " occured in deleteLog(). Exception ignored.");
2224             }
2225         }
2226     }
2227 
2228     /**
2229      * This methods allows the applet to store all messages (debug, warning, info, errors...) into a StringBuffer. If
2230      * any problem occurs, the whole output (displayed or not by the displayDebug, for instance) can be stored in a
2231      * file, or sent to the webmaster. This can help to identify and correct problems that can occurs on the various
2232      * computer configurations.
2233      * 
2234      * @param msg
2235      */
2236     protected synchronized void addMsgToDebugLog(String msg) {
2237         // If uploading lots of chunks, the buffer gets too large, resulting in
2238         // a OutOfMemoryError on the heap so we now use a temporary file for the
2239         // debug log.
2240         if (this.debugGenerateFile && this.debugOk) {
2241             try {
2242                 if (null == this.debugOut) {
2243                     this.juploadContext.registerUnload(this, "deleteLog");
2244                     this.debugFile = File.createTempFile("jupload_", "_log.txt");
2245                     this.debugOut = new PrintStream(new FileOutputStream(this.debugFile));
2246                 }
2247                 boolean endsLF = msg.endsWith("\n");
2248                 msg = msg.replaceAll("\n", this.CRLF);
2249                 if (endsLF) {
2250                     this.debugOut.print(msg);
2251                 } else {
2252                     this.debugOut.println(msg);
2253                 }
2254             } catch (IOException e) {
2255                 this.debugOk = false;
2256                 System.err.println("IO error on debuglog " + this.debugFile.getPath()
2257                         + "\nFallback to standard output.");
2258                 System.out.println(msg);
2259             }
2260         } else {
2261             System.out.println(msg);
2262         }
2263     }
2264 
2265     /**
2266      * Displays a message. If the logWindow panel is set, the message is displayed on it. If not, the System.out.println
2267      * function is used.
2268      * 
2269      * @param msg The message to display.
2270      */
2271     private void displayMsg(String tag, String msg) {
2272         String message;
2273 
2274         if (this.juploadContext.getLogWindow() == null) {
2275             message = tag + " - " + msg;
2276             System.out.println(message);
2277         } else {
2278             message = this.juploadContext.getLogWindow().displayMsg(tag, msg);
2279         }
2280         // Let's store all text in the debug logfile
2281         if (this.debugGenerateFile) {
2282             addMsgToDebugLog(message);
2283         }
2284     }
2285 
2286     /**
2287      * Default reaction after a successful drop operation: no action.
2288      * 
2289      * @see UploadPolicy#afterFileDropped(DropTargetDropEvent)
2290      */
2291     public void afterFileDropped(DropTargetDropEvent dropEvent) {
2292         // Default: no action.
2293     }
2294 
2295     /**
2296      * Default implementation for {@link UploadPolicy#createFileChooser()}: just a creation of a
2297      * {@link JUploadFileChooser}.
2298      * 
2299      * @see UploadPolicy#createFileChooser()
2300      */
2301     public JUploadFileChooser createFileChooser() {
2302         return new JUploadFileChooser(this);
2303     }
2304 
2305     /**
2306      * This method returns the response for the {@link JUploadFileFilter#accept(File)} which just calls this method.
2307      * This method checks that the file extension corresponds to the allowedFileExtensions applet parameter.
2308      * 
2309      * @see UploadPolicy#fileFilterAccept(File)
2310      */
2311     public boolean fileFilterAccept(File file) {
2312         if (file.isDirectory()) {
2313             return true;
2314         } else if (this.allowedFileExtensions == null || this.allowedFileExtensions.equals("")) {
2315             return true;
2316         } else {
2317             // Get the file extension
2318             String extension = DefaultFileData.getExtension(file.getName()).toLowerCase();
2319             // allowedFileExtensions is :
2320             // - a list of file extensions,
2321             // - in lower case,
2322             // - separated by slash
2323             // - A slash has been added at the beginning in
2324             // setAllowedFileExtensions
2325             // - A slash has been added at the end in setAllowedFileExtensions
2326             // So, we just look for the /ext/ string in the stored
2327             // allowedFileExtensions.
2328             return (this.allowedFileExtensions.indexOf("/" + extension + "/")) >= 0;
2329         }
2330     }
2331 
2332     /** @see UploadPolicy#fileFilterGetDescription() */
2333     public String fileFilterGetDescription() {
2334         if (this.allowedFileExtensions == null || this.allowedFileExtensions.equals("")) {
2335             return null;
2336         } else if (getFileFilterName() != null) {
2337             return getFileFilterName();
2338         } else {
2339             return "JUpload file filter (" + this.allowedFileExtensions + ")";
2340         }
2341     }
2342 
2343     /**
2344      * Returns null: the default icon is used.
2345      * 
2346      * @see UploadPolicy#fileViewGetIcon(File)
2347      */
2348     public Icon fileViewGetIcon(File file) {
2349         return null;
2350     }
2351 
2352     /** @see wjhk.jupload2.policies.UploadPolicy#getLastException() */
2353     public JUploadException getLastException() {
2354         return this.lastException;
2355     }
2356 
2357     /**
2358      * Set the last exception.
2359      * 
2360      * @param exception The last exception that occurs into the applet.
2361      */
2362     public void setLastException(JUploadException exception) {
2363         this.lastException = exception;
2364 
2365         // The log window may become visible.
2366         if (this.juploadContext.getUploadPanel() != null) {
2367             this.juploadContext.getUploadPanel().showOrHideLogWindow();
2368         }
2369 
2370     }
2371 
2372     /** @see wjhk.jupload2.policies.UploadPolicy#getLastResponseBody() */
2373     public String getLastResponseBody() {
2374         return this.lastResponseBody;
2375     }
2376 
2377     /** @see wjhk.jupload2.policies.UploadPolicy#getLastResponseMessage() */
2378     public String getLastResponseMessage() {
2379         return (null != this.lastResponseMessage) ? this.lastResponseMessage : "";
2380     }
2381 
2382     /**
2383      * @return The cursor that was active before setting the new one. Can be used to restore its previous state.
2384      * @see UploadPolicy#setCursor(Cursor)
2385      */
2386     public Cursor setCursor(Cursor cursor) {
2387         return this.juploadContext.setCursor(cursor);
2388     }
2389 
2390     /**
2391      * @return The cursor that was active before setting the new one. Can be used to restore its previous state.
2392      * @see UploadPolicy#setWaitCursor()
2393      */
2394     public Cursor setWaitCursor() {
2395         return this.juploadContext.setWaitCursor();
2396     }
2397 
2398 }