In traditional web request-response workflows, we activate a "do something and tell me what happened" button on a page and the browser is sent to a new page that tells us what happened, good or bad. The server logic standardly treats our all-or-nothing "submit this" request as an all-or-nothing atomic transaction.
When client-server activity is going on in the background, it's harder to specify how glitches in that activity should be handled. How are we notified? What's the effect on our other activities going on in parallel?
Our current (rev 4997) Uploader component doesn't provide very convincing answers to those questions. When the server reports an error, the hard-luck files are simply left in the queue, ready to try uploading again, with no notification except in the optional debugging window. Doing better will require a bit more design, a bit more development work and a bit of research.
Consider the two types of server-side glitches we face in the traditional request-response world:
- Unexpected errors for which no special functional provision has been made. These result in the server handing the browser some non-success status like "500" or "440", at best with an ugly developer-oriented message or stack trace attached.
- Anticipated problems for which some UI provision has been made, even if the standard work flow is interrupted. The server sends back a normal web page with a normal success status, and what's on the page explains or deals with the issue in (we hope) constructive terms.
The Fluid Uploader component is currently based on the SWFUpload project (and is therefore limited by its capabilities), which in turn is limited by the capabilities of Flash file transfer. Here's what we face in both scenarios:
The SWFUpload API includes support for an upload_error_handler function:
uploadErrorHandler(file object, error code, message)
This suggests that your handler might expect a call like:
uploadErrorHandler(someFlashyObject, 500, "org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; ....")
Instead it will receive something like:
uploadErrorHandler(someFlashyObject, -200, "500")
This is because the "error code" arguments are internally defined by swfupload.js rather than determined by the server response. Every non-success status from the server is mapped to the single error code "UPLOAD_ERROR.HTTP_ERROR" (or -200). The status code returned by the server itself is put into the "message" argument. Nothing else returned by the server is passed on to your handler.
The documented suggestion here is for application developers to piggyback on swfupload's upload_success_handler support.
Under normal (successful) circumstances, this handler is used to pass application-specific server-side data associated with the newly uploaded file to application-specific client-side code. The current Gallery demo uses the handler to remember which files have been uploaded on the current page so that their IDs can be passed along to the next page of the workflow. Another design might have client-side component code receive URLs for the newly uploaded files and display thumbnails for each as the uploads accumulate.
Overloading the meaning of this "success" handler to deal with glitches seems awkward. On the one hand, it does sound a lot like what's going on in the single request-response case. On the other hand, it forces the application to make its server response more complex, with client-side code parsing it to decide whether this is data for a "real" success or an error message to report for a "fake" success. Worse yet, it mixes up application-specific concerns with generic-component concerns: we probably don't want a file which hasn't been uploaded displaying in our queue exactly as if it had been successfully uploaded.
Possible development approach
1. With the current SWFUpload code, we can't find out why the server is upset, but we can at least note that some error occured while uploading a particular file in the queue. Since we can always expect unexpected server errors, and can't always expect that we'll get usable information past that, our first step should probably be to deal with this minimal amount of data. This will require design work, but it's not blocked by any other considerations.
2. Find out whether the current tight restriction on what we can find out about the server response is due to limitations in Flash event handling or just in SWFUpload's implementation. The HTTPStatusEvent is documented as including an array of "responseHeaders" which very well might include the same ugly (but better than nothing) message we're used to seeing in the browser. If SWFUpload is simply choosing to ignore that at present, we can request that the next release of the project expose it. (On the other hand, I've seen ominous notes that not all parts of HTTPStatusEvent are filled in all contexts....)
If this effort is successful, we can then improve our Step 1 design to include some way for users to see just which ugly message the server sent along with its error status.
3. Have at least one of our client applications implement the suggested SWFUpload approach to anticipated problems – living with the issue of bogus "success" rows in our component's file queue – so that we have sample code to show and a customer to work with.
4. If it still seems necessary, try coming up with a safely flexible way to componentize the "anticipated problems" approach. One possibility is that we could allow for an optional "errorMessageFromServerResponse" function to parse the server response. If null, we'd assume success; if non-null, we'd assume failure. With that safety net in place, we could ship a default implementation for application developers to plan around (one which, for example, assumed that an error report started with "errorMessage:") and still let clients override it.