Open StreamResource in new browser tab

Hi,
I’m generating PDF reports which I’m trying to open on new browser tab.

For doing this I’m using

StreamResource resource = new StreamResource(source, "report.pdf");
resource.getStream().setParameter("Content-Disposition", "attachment;filename=\"report.pdf\"");
resource.setMIMEType("application/pdf");
resource.setCacheTime(0);
Page.getCurrent().open(resource, "_blank", false);

Unfortunately Page.getCurrent().open(resource…) is now deprecated. Have you got any suggestions?

You need to use BrowserWindowOpener for that. You need to have a button or some other component, then create a BWO bound to the StreamResource, and call opener.extend(button).

See
this example
for about exactly the case you have.

Hi Carmelo, you can try creating an Request Handler inside the UI Class.
I don’t know if this is the best solution to your problem, but this is my way to solve your problem. Sorry for my english, but not my native language.

You can try something similar to this:

[code]
VaadinSession.getCurrent().addRequestHandler(

new RequestHandler() {
@Override
public boolean handleRequest(VaadinSession session,
VaadinRequest request,
VaadinResponse response)
throws IOException {
if (“/downloadFile”.equals(request.getPathInfo())) {
// if you want to use some parameter in your application
String param = request.getParameter(“yourFileName”);
response.setHeader(“Expires”, “0”);
response.setHeader(“Cache-Control”,“must-revalidate, post-check=0, pre-check=0”);
response.setHeader(“Pragma”, “public”);
response.setHeader(“Content-Disposition”, “attachment; filename="”+param+“"”);
response.setContentType(“application/pdf”);
OutputStream os = response.getOutputStream();
byte buffer = new byte[1024]
;
InputStream is = new FileInputStream(param);
int len;
while ((len = is.read(buffer)) > 0) {
os.write(buffer, 0, len);
}
is.close();
os.flush();
os.close();
return true;
} else
return false;
}
});
[/code]You can download your file using :

String url = "/yourApp/downloadFile?yourFileName=myfile.pdf"; Page.getCurrent().open(url,"_blank"); I hope that you find this useful.

Thank you for your answers, however I don’t want to download the pdf, but to open it on a new browser tab.

I also tried BrowserWindowOpener, but it did not work properly, because it listens for clicks only “after” the first button click…

Is it possible to get an URL from StreamResource? Maybe using properly ResourceReference? I tried with the following code but I get an error: <<HTTP Status 404 - /APP/connector/0/12/report/report.pdf can not be found. The requested resource is not available.>>

StreamResource resource = new StreamResource(source, "report.pdf");
resource.getStream().setParameter("Content-Disposition", "attachment;filename=\"report.pdf\"");
resource.setMIMEType("application/pdf");
resource.setCacheTime(0);

final ResourceReference ref = ResourceReference.create(resource, ((AppUI) getCurrent()).getContent(), "report");
Page.getCurrent().open(ref.getURL(), "_blank", false);

That example uses “two” buttons: the “OK” button for generating the report, and the “Open PDF” button to open it. But it’s a strange workflow… I should have one single button called “Print”. Have you got any idea?

Hi Carmelo.

Try removing de tag attachment

response.setHeader("Content-Disposition", "filename=\""+param+"\"");

I tried removing it, but same problem…

Hi,

You were saying on IRC that you need to click twice on the button for the new page to open with the report, and referenced this code:
http://pastebin.com/tQHMV6zi

You call BrowserWindowOpener.extend in the button’s click listener (through the helper class method stampaReport), which is the reason it won’t open the new window on the first click. You should just call AppUI.stampaReport(“report.jasper”, report.getId(), print); in the UI’s initialization.

The problem with it generating the report before you click the button is caused by line 44 of the paste:

resource.getStream().setParameter("Content-Disposition", "attachment;filename=\"report.pdf\""); Calling StreamResource.getStream() also internally calls the associated StreamSource’s getStream method, because it is needed for the DownloadStream object’s constructor. Since you wish to open the resource in a new window, I assume you don’t wish it to be automatically downloaded, so you can remove the whole line, especially since I’m quite sure it doesn’t even do anything with BrowserWindowOpener.

Hi,
I’ve got different types of report, which should be printed on button click based on its type. So I cannot make calls in the UI’s initialization, because StreamResource is generated “after” button click, so I cannot have it before…

Here is the latest pastebin, updated with different report types
http://pastebin.com/a4UfrK41

I’m also trying to open the pdf report using Embedded, but unfortunately it’s displayed as a blank window. Have you got any suggestions?

Here is a pastebin
http://pastebin.com/ZAgDNZKC

Hi Carmelo,

To display PDF document in Embedded frame, the browser must have support for PDF documents. Generally it requires a browser plugin, which may not be installed or even available for all browsers Hence, displaying embedded PDFs is not a good idea, except if the application is for an intranet, where you can configure workstations with the plugin, or if you use some embedded PDF viewer (which the Embedded component is not).

If you really have that requirement for internet apps (where you can’t rely on installed add-ons), I’d suggest looking for some embedded PDF viewer and integrating that with the Vaadin app. Some cloud services, such as Google Docs, offer an embedded PDF viewer.

Hi Marko,
nowadays PDF documents are readable by moderm browsers, and however users of this webapp will have necessary plugin.

Have you got any idea why the PDF document in the Embedded frame is not displayed? Is there any error in the code?

Hi Carmelo, did you make it work with one button?

Hi Matias,
I used BrowserFrame instead of Embedded. Here is the code:

public static void printReport(final String filename, long p1) {
        String path = "/com/carmelosaffioti/myapp/reports/";
        final String reportFile = path + filename;
        final HashMap parameters = new HashMap();
        parameters.put("id", p1);
        
        try {
            StreamResource.StreamSource source = new StreamResource.StreamSource() {

                public InputStream getStream() {
                    byte[] b = null;
                    Connection conn = null;
                    try {
                        InputStream report = getClass().getClassLoader().getResourceAsStream(reportFile);
                        if (report == null) {
                            Notification.show("No report!", Type.ERROR_MESSAGE);
                            return null;
                        }
                        conn = getDbHelp().getJDBCConnectionPool().reserveConnection();
                        b = JasperRunManager.runReportToPdf(report, parameters, conn);
                        conn.commit();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        getDbHelp().getJDBCConnectionPool().releaseConnection(conn);
                    }

                    return new ByteArrayInputStream(b);
                }
            };

            long time = System.currentTimeMillis();
            StreamResource resource = new StreamResource(source, "report" + time + ".pdf");
            resource.getStream().setParameter("Content-Disposition", "attachment;filename=\"report" + time + ".pdf\"");
            resource.setMIMEType("application/pdf");
            resource.setCacheTime(0);
            
            Window w = new Window();
            w.setModal(true);
            w.setCloseShortcut(KeyCode.ESCAPE, null);
            w.setResizable(false);
            //w.setClosable(false);
            w.setHeight(90.0f, Unit.PERCENTAGE);
            w.setWidth(90.0f, Unit.PERCENTAGE);
            
            BrowserFrame e = new BrowserFrame("Print", resource);
            e.setSizeFull();
            
            VerticalLayout layout = new VerticalLayout();
            layout.setSizeFull();
            layout.addComponent(e);
            
            w.setContent(layout);
            UI.getCurrent().addWindow(w);
            w.focus();
        } catch (Exception e) {
            e.printStackTrace();
            Notification.show("Error!", Type.ERROR_MESSAGE);
        }
    }

Thansk Carmelo!!
Work good for me too.

Regards

Any help on how this needs to be done when we migrate to Vaadin 14

Neeti Lakhotia:
Any help on how this needs to be done when we migrate to Vaadin 14

Assuming that you are using SpringBoot + Vaadin Flow 14 and that you have imported Jasper Libraries in Maven POM and that your reports (*.jasper) are in \app\src\main\resources\reports…

You may use IFrame instead of BrowserFrame, like this:

            public void printReport(String reportName, HashMap<String, Object> params) {

                final StreamResource resource = buildReport(reportName, params);
                resource.setContentType("application/pdf");
                resource.setCacheTime(0);

                final StreamRegistration registration = VaadinSession.getCurrent().getResourceRegistry().registerResource(resource);

                final IFrame content = new IFrame(registration.getResourceUri().toString());
                content.setSizeFull();

                final EnhancedDialog d = new EnhancedDialog();
                d.setHeader(new H3("Report Viewer"));
                d.setThemeVariants(EnhancedDialogVariant.SIZE_MEDIUM);
				d.setModal(true);
				d.setDraggable(false);
				d.setResizable(false);
				d.setHeight("90%");
                d.setContent(content);
                d.open();
                d.addDialogCloseActionListener(e-> {registration.unregister(); d.close();} );
        };
		
    private StreamResource buildReport(String reportName, HashMap<String, Object> params) {

        ResourceLoader loader = new DefaultResourceLoader();
        Resource resource = loader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX+"/reports/" + reportName);

        byte[] b = null;
        Connection conn = null;
        try {
            params.put("REPORT_DIRECTORY", resource.getFile().getParent());
            conn = PgDatabaseService.getPoolDB().getConnection();
            b = JasperRunManager.runReportToPdf(resource.getInputStream(), params, conn);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
            }
        }

        InputStream is = new ByteArrayInputStream(b);
        StreamResource myResource = new StreamResource("Report-"
                + UUID.randomUUID().toString().replace("-", "")
                + ".pdf", () -> is);
        return myResource;
    };
	
	

Winston Carlos:

Neeti Lakhotia:
Any help on how this needs to be done when we migrate to Vaadin 14

Assuming that you are using SpringBoot + Vaadin Flow 14 and that you have imported Jasper Libraries in Maven POM and that your reports (*.jasper) are in \app\src\main\resources\reports…

You may use IFrame instead of BrowserFrame, like this:

            public void printReport(String reportName, HashMap<String, Object> params) {

                final StreamResource resource = buildReport(reportName, params);
                resource.setContentType("application/pdf");
                resource.setCacheTime(0);

                final StreamRegistration registration = VaadinSession.getCurrent().getResourceRegistry().registerResource(resource);

                final IFrame content = new IFrame(registration.getResourceUri().toString());
                content.setSizeFull();

                final EnhancedDialog d = new EnhancedDialog();
                d.setHeader(new H3("Report Viewer"));
                d.setThemeVariants(EnhancedDialogVariant.SIZE_MEDIUM);
				d.setModal(true);
				d.setDraggable(false);
				d.setResizable(false);
				d.setHeight("90%");
                d.setContent(content);
                d.open();
                d.addDialogCloseActionListener(e-> {registration.unregister(); d.close();} );
        };
		
    private StreamResource buildReport(String reportName, HashMap<String, Object> params) {

        ResourceLoader loader = new DefaultResourceLoader();
        Resource resource = loader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX+"/reports/" + reportName);

        byte[] b = null;
        Connection conn = null;
        try {
            params.put("REPORT_DIRECTORY", resource.getFile().getParent());
            conn = PgDatabaseService.getPoolDB().getConnection();
            b = JasperRunManager.runReportToPdf(resource.getInputStream(), params, conn);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
            }
        }

        InputStream is = new ByteArrayInputStream(b);
        StreamResource myResource = new StreamResource("Report-"
                + UUID.randomUUID().toString().replace("-", "")
                + ".pdf", () -> is);
        return myResource;
    };
	
	

thank you for this, it works fine! In my project I need to open doc/docx files as well as PDF files, but when i try to do so the dialog opens blank and the doc file downloads instantly. Could you help me to open these files like the pdf ones? I just cant figure it out…
Or if you could point me to another solution to do this would be great!

In my case I got pictures -which are docs/pdfs converted to images- in a view. When I click on the image it opens the file which it was saved to disk before.

finalImage.addClickListener((ClickEvent<Image> event) -> {
            StreamResource streamResource = new StreamResource(imageName,
                    new InputStreamFactory() {
                @Override
                public InputStream createInputStream() {
                    try {
                        return new FileInputStream(path);
                    } catch (FileNotFoundException ex) {
                        Logger.getLogger(DocumentViewer.class.getName()).log(Level.SEVERE, null, ex);
                        return null;
                    }
                }
            });

            openDocumentDialog(streamResource);
        });
private void openDocumentDialog(StreamResource resource) {       
        Dialog dialog = new Dialog();
        StreamRegistration registration = VaadinSession.getCurrent().getResourceRegistry().registerResource(resource);
        IFrame content = new IFrame(registration.getResourceUri().toString());
        content.setSizeFull();    
        dialog.add(content);
        dialog.setWidth("80%");
        dialog.setHeight("100%");
        dialog.open();
        
    }