What a simple solution that is very elegant from the user's point of view ..... the thought never crossed my mind to use the Refresh header to trigger a single download response on refresh! This is exactly the kind of idea I was looking for and it works great while providing the best user experience.
Rather than muck with http-equiv meta tags in my page wrapper, I implemented your recommendation using the technique demonstrated by Anjo in ERXLongResponse class whereby the Refresh header is dynamically added in appendToResponse with a custom element sender id appended to the end of the component context id and then in invokeAction I use that sender id to capture the refresh and return the download response .... this encapsulates all this download functionality in the java file of the one WOComponent ..... awesome .... this is the cleanest long response download solution by far.
FWIW, I have pasted code snippet below in case anyone else wants to implement this for downloads that require a long response to prepare the download file ..... see Anjo's ERXLongResponse class for the Refresh-fiddling basis of this approach....
This approach uses one boolean,shouldDownloadOnRefresh(), to trigger the download once....
Thanks again Suzanne for this simple effective idea. I like it a lot.
private boolean _shouldDownloadOnRefresh = false;
/** @return whether to download the file using refresh aka 'meta reload' */
public boolean shouldDownloadOnRefresh() {
return _shouldDownloadOnRefresh;
}
/** @param shouldDownloadOnRefresh whether to download the file using refresh aka 'meta reload' */
public void setShouldDownloadOnRefresh(boolean shouldDownloadOnRefresh){
_shouldDownloadOnRefresh = shouldDownloadOnRefresh;
}
/**
* We use our custom senderID key for the refresh to detect the refresh
* and we call the download action that returns the download file and we
* remove the refresh header
* @see wk.cheetah.appserver.WKPageComponent#invokeAction(com.webobjects.appserver.WORequest, com.webobjects.appserver.WOContext)
*/
@Override
public WOActionResults invokeAction(WORequest request, WOContext context) {
if (context.senderID().equals(WO_META_REFRESH_SENDER_ID)) {
return downloadTheFile();
}
return super.invokeAction(request, context);
}
/**
* We override so we can dynamically manage the META Refresh header in the response
*/
@Override
public void appendToResponse(WOResponse response, WOContext context) {
if (shouldDownloadOnRefresh()) {
response.setHeader(metaReloadResponseHeader(context), REFRESH_HEADER_KEY);
// Toggle off so we don't download again
setShouldDownloadOnRefresh(false);
} //~ if (shouldDownloadOnRefresh())
super.appendToResponse(response, context);
if (log.isDebugEnabled())
log.debug("response.headers() = " + (response.headers() == null ? "null" : response.headers().toString()));
}
private String metaReloadResponseHeader(WOContext aContext) {
StringBuilder b = new StringBuilder();
b.append("0;url=""margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "> b.append(aContext.urlWithRequestHandlerKey(WOApplication.application().componentRequestHandlerKey(), null, null));
b.append("/");
b.append(aContext.session().sessionID());
b.append("/");
b.append(aContext.contextID());
b.append(".");
b.append(WO_META_REFRESH_SENDER_ID);
return b.toString();
}
</snip>