StreamResource sometimes resource not found when clicking download button in a closing dialog window

Julius Koljonen :

I am working on a dialog which has a download link to dynamically generated file via StreamResource and when user clicks on the download button the dialog should close. Simple enough. However when user opens the dialog and clicks on the download button sometimes the created file is downloaded successfully. Problem is that on other times user might encounter "resource/file not found" error message randomly when attempting to download created file. Below a code snippet that reproduces the problem.

public class HomeView extends VerticalLayout{

Dialog dialog;

public HomeView() {
    //Set up dialog
    dialog = new Dialog();
    Button downloadButton = new Button("Download");
    //This might be the problem. Dialog might be closed before the download even starts?
    downloadButton.addClickListener(click -> dialog.close());
    Anchor anchor = new Anchor();
    anchor.add(downloadButton);
    anchor.setHref(new StreamResource("file", () -> createInputStream()));
    dialog.add(anchor);

    //Add a button to open dialog
    Button openDialog = new Button("Open Dialog");
    openDialog.addClickListener(click -> dialog.open());
    add(openDialog);
}

private InputStream createInputStream() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        outputStream.write("text".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
    return new ByteArrayInputStream(outputStream.toByteArray());
}

So user might sometimes encounter resource not found error message when pressing download.

"Resource is not found for path" image

The funny thing is that if I close the dialog in createInputStream() method I don't get the error message. Below an example.

public class HomeView extends VerticalLayout{

Dialog dialog;

public HomeView() {
    dialog = new Dialog();
    Button downloadButton = new Button("Download");
    //Commented out
    //downloadButton.addClickListener(click -> dialog.close());
    Anchor anchor = new Anchor();
    anchor.add(downloadButton);
    anchor.setHref(new StreamResource("file", () -> createInputStream()));
    dialog.add(anchor);

    Button openDialog = new Button("Open Dialog");
    openDialog.addClickListener(click -> dialog.open());
    add(openDialog);
}

private InputStream createInputStream() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        outputStream.write("text".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
    //Close the dialog here
    dialog.close();
    return new ByteArrayInputStream(outputStream.toByteArray());
}

Now no matter how many times I click on the download button I don't get the resource error message and dialog still closes as intended.

I'm using Vaadin 13.0.1.

So in the end I have this question. The first code snippet doesn't work 100% of the time but the second code snippet seems to, why?

Leif Åstrand :

Behind the scenes, StreamResource works so that it generates a temporary URL and adds the resource instance to a map with the URL as the key. This is then used to find the right stuff to put in the response when the browser makes a request to that URL.

To prevent this from leaking memory indefinitely, it is implemented so that the resource is removed from that global map immediately when the "owner" component is detached. In your case, anchor is the owner and it is indeed detached when the dialog is closed. The randomness that you're observing depends on which request reaches the server first.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=159524&siteId=1