In my PrimeFaces app I'm generating a file for download. The generation is kicked off and then I go into a waiting loop until it's ready. It now appears that this loop is being initiated twice. Here's the code:
JSF:
<p:commandButton id="downloadBtn" value="Download" disabled="#{bean.selectedRow == null}"
onclick="blockUI()"
actionListener="#{bean.generateFileAndDownloadWhenReady()}"/>
<script type="text/javascript">
function downloadFileWhenReady(key) {
window.setTimeout(function () {
checkForDownloadReady([{name:"key",value: key }]);
}, 1000);
}
function doTheActualDownload(key) {
// handle the download
}
</script>
Java:
public void generateFileAndDownloadWhenReady() {
key = kickoffFileGeneration();
RequestContext.getCurrentInstance().execute("downloadFileWhenReady('" + key + "');");
}
public void checkForDownloadReady() {
String key = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("key");
STATUS status = FileCache.getFileStatus(key);
if (status == STATUS.READY) {
RequestContext.getCurrentInstance().execute("doTheActualDownload(" + key + ");");
} else if (status == STATUS.FAILED) {
logger.error("Failure creating file. Wail loop will end.");
} else if (status == STATUS.OPEN){
RequestContext.getCurrentInstance().execute("downloadFileWhenReady('" + key + "');");
}
}
Here's a flowchart to hopefully clarify the logical flow:
By placing a breakpoint in generateFileAndDownloadWhenReady(), I can see it's only being called once, but a breakpoint in downloadFileWhenReady() is being called twice. By using a long loop delay I know the second call isn't coming from the loop. Also, the call to kickoffFileGeneration() is pretty quick -- it's spinning off a new thread for the actual work. So why is it being called twice and how do I stop it?
[update: 5/24/17]
I suspect that, being a complete novice with JSF, I'm not using the actionListeners and remoteCommands properly. @BalusC has several responses & articles like this and this, which suggest it might be a scoping problem.
And to answer the question of why I don't just simply return the file from the commandButton actionListener, it's because it can take a few minutes to generate the .zip file. Therefore I'm avoiding blocking the UI by spinning off a worker thread, and I'm also using a <p:blockUI>
element to entertain the user.