Vaadin 7 Rc2: FileDownloader problems

Hi all, i have a problem regarding the FileDownloader extension. What i trying to do is allow user to download file based on what they chosen with CheckBox in a table. So i need to check whether the file to be downloaded is in my server, if yes then can continue to download, otherwise prompt a message. But there is an issue when i extend my download button with FileDownloader in my Button ClickListener, the first time user click download button, the download dialog wont prompt, and user need to click the second time then only it showed. And when user try to download the empty file ( it should prompt to tell user the file is not exist) but the download dialog prompted and the file is not the one user selected, is previous selection file. Below is my simplify code



 private FileDownloader fileDownloader;
    private Button fileDownloadButton;
    private OptionGroup og;
    private final static Logger log = LoggerFactory.getLogger(TestingUI.class);

    @Override
    protected void init(VaadinRequest request) {
        VerticalLayout mainLayout = new VerticalLayout();

        og = new OptionGroup();
        og.setImmediate(true);
        og.addItem("Temp File (sample file in C drive)");
        og.addItem("No File");

        fileDownloadButton = new Button("Download file");
        fileDownloadButton.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {

                if (og.getValue() != null) {
                    File downloadFile = null;

                    if (((String) og.getValue()).equals("Temp File")) {
                        downloadFile = new File("C:\\temp.txt"); // a sample file in C drive
                    }

                    try {
                        if (downloadFile != null && downloadFile.exists()) {

                            if (fileDownloader == null) {
                                fileDownloader = new FileDownloader(createFileResource(downloadFile));
                                fileDownloader.extend(fileDownloadButton);
                            } else {
                                fileDownloader.setFileDownloadResource(createFileResource(downloadFile));
                            }

                        } else {
                            Notification notif = new Notification("", "File not exist! Pls try again!", Type.ERROR_MESSAGE);
                            notif.show(Page.getCurrent());
                            if (fileDownloader != null) {
                                fileDownloader.setFileDownloadResource(null); // reset
                            }
                        }

                    } catch (Exception e) {
                      
                    }
                }
            }
        });

        mainLayout.addComponent(og);
        mainLayout.addComponent(fileDownloadButton);

        setContent(mainLayout);
    }

    private FileResource createFileResource(File zipFile) {
        return new FileResource(zipFile) {

            @Override
            public DownloadStream getStream() {
                try {
                    final DownloadStream ds = new DownloadStream(new FileInputStream(getSourceFile()), getMIMEType(), getFilename());
                    ds.setParameter("Content-Length", String.valueOf(getSourceFile().length()));
                    ds.setCacheTime(getCacheTime());
                    return ds;
                } catch (final FileNotFoundException e) {
                    return null;
                }
            }
        };
    }

When in click listener you extend your button with the FileDownloader only the second time you click the button will activate the functionality that is provided by the FileDownloader. This is because button extension gets executed when you press the button. When you apply the extension button has already been clicked.

I think also that when the extension is in place, instead of performing the button click listener it will before that perform the file download which will happen before the actual click listener is executed. That’s why it’ll download you “wrong” file.

Thanks for the quick reply Peter! So meaning i can only attach my file resouce before user click download button? But how? I need to confirm which file that user want to download then only i can attach to the FileDownloader()… I need to wait them to click download… Is there other ways… Please help! :wacko:

One way could be that you attach the extension to the button right from the beginning and add for example ValueChangeListener to your OptionGroup and set the OptionGroup to immediate mode. In ValueChangeListener you update the resource of the FileDownloader.

Just an idea.

Hello,

I’ve done exactly what Peter suggested - in a optiongroup (combobox) the resource is updated by calling createExportContent(), which looks as follows:

public void createExportContent() {

        StreamResource s = new StreamResource(new StreamSource() {
            @Override
            public InputStream getStream() {
                        return new ByteArrayInputStream(...someByteArrayToInputStream...);
        }, "example.text");

        fileDownloader.setFileDownloadResource(s);
}

Though still I’ll have to press the downloadbutton twice after that, to have changes take effect. I assume it is because the File-Download-Resource isn’t really being reset until the button is pressed - because the relevant code is within the @Override section.

Isn’t there any way in Vaadin 7 for downloading dynamic content??

Any solution to the problem of having to click twice on the download button before downloading begins?
I tried
buttonName.focus()
but that didn’t help.

Just assign some dummy resource and extend in advance:

StreamResource.StreamSource source = new StreamResource.StreamSource() {
public InputStream getStream() {return null;}
};
StreamResource dummyResource = new StreamResource(source, “”);
fileDownloader = new FileDownloader(dummyResource);
fileDownloader.extend(generatePDFReport);

then assign the actual resource on button click event:
fileDownloader.setFileDownloadResource(pdfResource);

Refer the sample code given in
http://stackoverflow.com/questions/21937516/vaadin-download-the-file-save-as/22730778#22730778
, it will satisfy your requirement.

public class MenuView extends VerticalLayout implements View,
        Button.ClickListener {
    private static final long serialVersionUID = 1L;

    I18nEngineService service;
    MenuExporter menuExporter;
    FileDownloader downloader;
    
    StreamResource menuStream;
    
    HorizontalLayout buttons;
    Button imp;
    Button exp;

    boolean displayed;

    public MenuView(I18nEngineService service) {
        this.service = service;
        menuStream = createResource();
        downloader = new FileDownloader(menuStream);
        menuExporter = new MenuExporter(service);
        initComponents();
    }

    private StreamResource createResource() {
        return new StreamResource(new StreamSource() {
            @Override
            public InputStream getStream() {
                InputStream stream = null;
                try {
                    stream = menuExporter.process();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return stream;

            }
        }, "export.xls");
    }

    private void initComponents() {
        buttons = new HorizontalLayout();
        exp = new Button("Export");
        imp = new Button("Import", this);
        
        downloader.extend(exp);
    }
}

Hi, i have a problem with FileDownloader component. i have always the problem "session expired"
when i press the download button. I use Spring and Spring boot.
The "I18nEngineService" is autowired (@Autowired) in my UI.
That could be the problem ?


I figured out the issue finally - hurray!

The solution is much simpler than you think it is!

Firstly - as you rightfully pointed out - the issue is that the relevant code for setting resource is written in the onclick method and thus the activation takes one click. The download happens on the second click.

The trick is to NOT implement ClickListener at all - you don’t need an additional on-click method of your own - just use the default one! Here is code to help you:

public void createExportButton()
{
   Button exportConfig = new Button("Export");
   FileDownloader fD = new FileDownloader(createXMLResource());
   fD.extend(exportConfig);
}

public StreamResource createXMLResource()
{
   String exportFile = setExportFileName();
   return new StreamResource(new StreamResource.StreamSource()
   {
       private static final long serialVersionUID = 1L;

       @Override
       public InputStream getStream()
       {
            InputStream in = generateMyInputStream();
            retturn in;
       }
   }, exportFile);
}

Good luck! :slight_smile:

Reference: Vikhrant Thakur’s answer on
https://vaadin.com/wiki/-/wiki/Main/Letting+the+user+download+a+file

My requirement is something different.
when user clickes on download button,I want to get bytes from other server.
So,On button click i have to call service and get bytes data.
I have tried to assign dummy resource at init time and set original resource after getting bytes data from server.
But not getting success.
So please help me to do this.

I have to click download button two times as well sometimes. In my case, I think it is because I am calling “Notification.show” inside my handleConnectionRequest ( if all goes well, it calls super.handleConnectionRequest, else it shows an error to the user ). Basically, I need to ask the server to create a file, but it cannot always create it ( for various legitimate reasons ), so I wanted to report the problem. Do I need to do it someplace different? Any better ideas?

I am also researching another users AdvancedFileDownloader to see if that might help, since it seems to allow us to intercept things before the “handleConnectionRequest” ( if I understand correctly ).