FileUpload: Multiple with auto="true" only works first time
See original GitHub issueDescribe the defect
Getting irregular and unreliable results when performing an auto, advanced, multiple file upload.
On startup you simply get a file upload instance to select csv files from. I’m assuming you have, or can get a set of csv files (~4) to be able to use for this. On first selection it appears to work correctly, i.e., select 4 files and upon submit, the table showing files selected will list all four.
The Clear List
button does just that… it removes the file selected list and refreshes the section and should see no files selected.
Now do this again… select the same four files. I’m seeing that subsequent file selections are being missed… in fact, most of the time.
Reproducer I have a fork of the primefaces-test repo here.
Environment:
- PF Version: 10.0
- JSF + version: e.g. Mojarra 2.2.20 or MyFaces 2.3.9
- Affected browsers: e.g. Chrome, iOS, ALL
To Reproduce Steps to reproduce the behavior:
- Have 4 csv files available in a test directory.
- Click on the
Choose
button (FileUpload control) - Navigate to directory with test csv files, select all.
- When updated, you will see list of files selected in a table below the control.
- (First time in, it appear to show all files correctly.)
- Click on
Clear List
- File resources will be deleted from backing bean, form updated, and fileupload will be available again.
- Repeat #s 2-4
- Subsequent selections will show irregular results in the files that were selected. Mostly incorrectly.
Expected behavior I would expect to see the resulting file list represent exactly what I had selected.
Issue Analytics
- State:
- Created 2 years ago
- Comments:34 (20 by maintainers)
Top GitHub Comments
@karlkras after some more analysis I do not think any more that the FileUpload functionality is broken. Let me explain.
In the reproducer the FileUpload component is backed by a
@ViewScoped
bean. In Primefaces showcase the bean is@RequestScoped
. The FileUpload component in advanced mode sends each file asynchronously in parallel (see my previous analysis above). In the showcase each request works on a fresh FileUpload instance, so no race conditions can occur. In the reproducer all requests work on the same FileUpload instance.I think for this use case there have to be a
@RequestScoped FileUploadHandler
and a@ViewScoped FileUploadView
bean. The FileUploadHandler may@Inject FileUploadView
to call a threadsafe method.Because file upload requests are standard Faces requests each of them runs through the JSF lifecycle. Each request updates the model and each response contains the components to be updated. This leads to 2 race conditions in the reproducer
update="test-file-selection"
: after each file upload the panel will be updated. In the end the panel is updated once for each file uploaded. (I think this is sowewhat unexpected here, but imo it is not a bug.) As a result the DataTable showing the list of uploaded files may be incomplete even if all files were uploaded since the reponses are not guaranteed to come in same order as requests were sent.disabled="#{fileUploadView.uploadedFiles.size() gt 0}"
: after the first file upload request has reached the end of PROCESS_VALIDATIONS phase the FileUpload component is set to disabled=true because of the given EL expression. All subsequent file upload requests that have not reached APPLY_REQUEST_VALUES phase aren’t even decoded because the component is disabled. (I think this is sowewhat unexpected here too, but imo it is not a bug.)I think these 2 race conditions can be avoided by using RemoteCommand
(
onComplete
fires after each file uploaded, so it must be checked that no more files are left for upload.)I suggest to add some clarifications to the Advanced File Upload documentation section on how to use FileUpload in this mode. Maybe FileUpload can be enhanced in one way or another, e.g. by adding an
onCompleteMulti
attribute which fires only after all files have been uploaded.@jepsar I think all of your findings can be explained with the observed race conditions. Even
sequential=true
works with the suggested changes.pf-7364-adjusted.zip
I did some analysis on this issue. I think there are (at least 2) race conditions. First on
UIInput#submittedValue
and second in the test class onFileUploadView#fileList
. The root cause is that the FileUpload widget does send asynchronous HTTP requests in parallel. These requests are processed by the underlying HTTP layer in parallel threads. In each of the threadsThe race condition on
FileUploadView#fileList
can be avoided by usingConcurrentHashMap
instead ofHashMap
(but I do not think thats a good solution). I do not have any clue how to mitigate the race condition onUIInput#submittedValue
.