kungfoo
kungfoo

Reputation: 1347

Lazily detemine filename when using FileDownloader

In vaadin 7, how does one lazily determine the file name when using FileDownloader?

final Button downloadButton = new Button("Download file");
FileDownloader downloader = new FileDownloader(new StreamResource(new StreamSource() {
    @Override
    public InputStream getStream () {
        return new ByteArrayInputStream(expesiveCalculationOfContent());
    }
}, "file.snub"));

downloader.extend(downloadButton);

In this code sample, clearly the filename

  1. is rubbish
  2. has to be known early on.

How can one lazily determine the filename of the downloaded file?

Upvotes: 2

Views: 4039

Answers (3)

Nico de Wet
Nico de Wet

Reputation: 334

If one assumes that lazily determining a file name means dynamically setting the filename irrespective of what the actual file system name may be, then the code below is what I'm using.

In the code below fileName points to the local file system file with a name that we want to change upon download. A usecase for this would be when one uploaded files to tmp with filenames containing some random characters that where not present in the original upload.

File file = new File(localFile);
final FileResource fileResource = new FileResource(file);
if (!file.exists()) {
   throw new IllegalStateException();
}
final StreamResource stream = new StreamResource(
                            new StreamSource() {
                                @Override
                                public InputStream getStream() {
                                    return fileResource.getStream().getStream();
                                }
                            }, "newname.txt");

FileDownloader fileDownloader = new FileDownloader(stream);
fileDownloader.extend(downloadButton);

Upvotes: 0

kungfoo
kungfoo

Reputation: 1347

This is the final solution I came up with:

/**
 * This specializes {@link FileDownloader} in a way, such that both the file name and content can be determined
 * on-demand, i.e. when the user has clicked the component.
 */
public class OnDemandFileDownloader extends FileDownloader {

  /**
   * Provide both the {@link StreamSource} and the filename in an on-demand way.
   */
  public interface OnDemandStreamResource extends StreamSource {
    String getFilename ();
  }

  private static final long serialVersionUID = 1L;
  private final OnDemandStreamResource onDemandStreamResource;

  public OnDemandFileDownloader (OnDemandStreamResource onDemandStreamResource) {
    super(new StreamResource(onDemandStreamResource, ""));
    this.onDemandStreamResource = checkNotNull(onDemandStreamResource,
      "The given on-demand stream resource may never be null!");
  }

  @Override
  public boolean handleConnectorRequest (VaadinRequest request, VaadinResponse response, String path)
      throws IOException {
    getResource().setFilename(onDemandStreamResource.getFilename());
    return super.handleConnectorRequest(request, response, path);
  }

  private StreamResource getResource () {
    return (StreamResource) this.getResource("dl");
  }

}

Upvotes: 3

I do not know if it is dirty but this works: extending FileDownloader.handleConnectorRequest() to call the StreamResource.setFilename() prior to calling its super's method.

    {
        final Button downloadButton = new Button("Download file");
        final StreamResource stream = new StreamResource(
                new StreamSource() {
                    @Override
                    public InputStream getStream() {
                        return new ByteArrayInputStream("Hola".getBytes());
                    }
                }, "badname.txt");
        FileDownloader downloader = new FileDownloader(stream) {
            @Override
            public boolean handleConnectorRequest(VaadinRequest request,
                    VaadinResponse response, String path)
                    throws IOException {
                stream.setFilename("better-name.txt");
                return super
                        .handleConnectorRequest(request, response, path);
            }
        };

        downloader.extend(downloadButton);
        layout.addComponent(downloadButton);
    }

Upvotes: 9

Related Questions