Download (Stream/File Resource) via window.open() opening new App

Hi,

At a bit of a stone wall with this one, I’m wondering if anyone can give me some pointers.

Basically whats happening is instead of the browser opening a file dialog to download the file, another browser window opens with the Vaadin App main window (and its widgets) contained within it I suspect it might be related to the fact I’m running Vaadin embedded in an HTML div within an HTML page (as its an existing web application).

I’m running a Vaadin Applicaiton embedded in div within an HTML file (that happens to be served up via Spring MVC, though this should be irrelevant).
The vaadin app is bound to a particular path under the context root.

My Web.xml looks like this:



    <servlet>
        <servlet-name>PartnerApplication</servlet-name>
        <servlet-class>
            com.vaadin.terminal.gwt.server.ApplicationServlet
        </servlet-class>
        <init-param>
            <description>Partner Application</description>
            <param-name>application</param-name>
            <param-value>
                uk.gov.ukti.bpb.partner.PartnerApplication
            </param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>PartnerApplication</servlet-name>
        <url-pattern>/partner/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>PartnerApplication</servlet-name>
        <url-pattern>/VAADIN/*</url-pattern>
    </servlet-mapping>

It all works great until I try to serve up a dynamically generated Open Office file.

Here’s a trivial example of downloading a smple text file, which exhibits the problem


 addListener(new ClickListener() {
                @Override
                public void buttonClick(ClickEvent event) {
                    final FileResource stream = new FileResource(new File(""),
                            PartnerApplication.getInstance()) {
                        @Override
                        public DownloadStream getStream() {
                            ByteArrayInputStream in = new ByteArrayInputStream(
                                    "Simple Text File".getBytes());
                            DownloadStream ds = new DownloadStream(in,
                                    "text/plain", "test.txt");
                            // Need a file download POPUP
                            ds.setParameter("Content-Disposition",
                                    "attachment; filename=test.txt");
                            return ds;
                        }
                    };
                    stream.setCacheTime(0);
                    getWindow().open(stream);
                }

            });

The URL of the window (that opens instead of the file download dialog that I expect) is :
http://localhost:9090/client-reader-web/partner/PartnerApplication/APP/1/
(where client-reader-web is the context root).

I’m running Vaadin version 6.6.0 if that’s important.

Thanks for any help!!

Just wondering if anyone has any suggestions…otherwise I’m about to accept that it just doesn’t work and implement the dynamic download with a java servlet :frowning:

Hi Alan,

There is another thread related to your problem:

Download file

I think you might find your answer there.

Thanks Jarno.

I’ve implemented it the same way as in that thread, and tried a number of other ways also.
I continue to get the same result. Basically, the application gets served up in another window as opposed to the the stream being downloaded./

On the last attempt, I implemented ApplicationResource directly. I debugged though to repaint code, and I see that a URL is generated which I presume is intended as the URL at which the stream will be downloaded

The URL in my case is:
http://localhost:9090/client-reader-web/[b]
partner/PartnerApplication
[/b]/APP/1/

My Stream ApplicationResource implementation currenly returns null in getFilename(), and that should be fine looking at the code.
I tried with a filename being returned also, and the result was the same.

In firebug, I can see the browser making a request to the generated URL. At this point, - the application widgets get redisplayed/repainted.
I presume, that when this generated URL is requested, - it should resolve to the stream Resource instead…

The getStream method of my ApplicationResource never gets called.

The one remarkable thing with my application is that is is being run embedded in the Div of an existing application. I am convinced it is realted.

I will look for another while. In the meantime any hints or ideas would be appreciated.

OK, I’ve ran it through the debugger and it is related.
I think it is a bug.
The problem is in this method.


  public boolean isApplicationResourceURL(URL context, String relativeUri) {
        // If the relative uri is null, we are ready
        if (relativeUri == null) {
            return false;
        }

        // Resolves the prefix
        String prefix = relativeUri;
        final int index = relativeUri.indexOf('/');
        if (index >= 0) {
            prefix = relativeUri.substring(0, index);
        }

        // Handles the resource requests
        return (prefix.equals("APP"));
    }

Here, because my application is embedded, its under a specific path, ie “/PartnerApplication” and not the default “/” path.
This is the problem, - the above code assumes that the Vaadin servlet live under the “/” path.

“relativeUri” in my case is “PartnerApplication/APP/2/”
So, “prefix” in my case is “PartnerApplication”
not
“APP” as expected.

I think the fix would be to strip the full application context path from the URI before looking for “APP”.

I can fix this in my case by overriding “isApplicationResourceURL” in my Application implementation.

There should probably be a substantive fix put in for this though as it will catch others running Vaadin embedded in an existing application.

On the plus side, I found the code generally well written and easy to debug :smiley:
.

Hi,

I am not experiencing described problem, but would share some comments still.

Under normal circumstances Vaadin servlet handles URL and in case it refers to something like “url-base/APP/resource” or “url-base/VAADIN” it would just serve the resource instead of starting another application instance.

You’re not mentioning what browser was used for observation, which matters quite a lot. For example, when downloading TXT resource (text/plain mime type) i get these varying results:

FF5 + Content-Disposition: attachment + open(txtStream) = no new window, open / save dialog comes up.
FF5 + Content-Disposition: inline + open(txtStream, “_blank”) = new window, text content displayed as body
Chromium + Content-Disposition: attachment + open(txtStream) = new window, file download starts immediately without interaction
Chromium + Content-Disposition: inline + open(txtStream, “_blank”) = new window, text content displayed as body

And these are just 2 major browsers out of N. Plus add non-ascii file names handling (url encoded using different schemes according to individual browser requirements) into the mix and even you get even more eventual browser reactions.

Last but not least, opening resource in application window using open(txtStream) as opposed to new window using open(txtStream, “_blank”) is not recommended practise as it may trigger fatal synchronization errror in client application. See more http://vaadin.com/forum/-/message_boards/view_message/590383

Serving files / resources via Vaadin native resource infrastructure looks tempting first, but has decent potential of turning to nightmare later on, sadly. At least we can get back to servlet handling any time.

Tomas

Could you
create a ticket
about this so it does not get forgotten.

Overriding handleURI in my Application implementation has fixed the problem in my specific case.
“NAME” referred to below, in my case also maps to the servlet mapping path of my VAADIN application instance.

 
  public DownloadStream handleURI(URL context, String relativeUri) {
        relativeUri = StringUtils.removeStart(relativeUri, NAME + "/");
        return super.handleURI(context, relativeUri);
  }

I’ll raise a bug with some suggestions also.

Raised http://dev.vaadin.com/ticket/7294

Hi,

this is my code for dynamic download for jasper report and working for me…
testing with firefox and chrome browser and save like firefox and chrome too without open new window
Just for Sharing who need it

con = ((XApplication) getApplication()).getConnectionPool().reserveConnection();

map = new HashMap<String , Object>();
map.put(“id”, id);

ApplicationContext ctx = ((XApplication) getApplication()).getContext();
WebApplicationContext webCtx = (WebApplicationContext) ctx;
ServletContext sc = webCtx.getHttpSession().getServletContext();

String reportFile=sc.getRealPath(“/WEB-INF/reports/”) + “/xyz.jasper”;

try {
b = JasperRunManager.runReportToPdf(reportFile, map, con);
} catch (JRException e) {}

final byte bConv = b;
StreamResource.StreamSource source = new StreamResource.StreamSource() {
public InputStream getStream() {
return new ByteArrayInputStream(bConv);
}
};

StreamResource resource = new StreamResource(source, “XYZ.pdf”, XApplication.getInstance());
resource.setMIMEType(“application/unknow”);

getApplication().getMainWindow().open(resource);

Cheers

[left]

[/left]I have tried your code from a subwindow and it doesn’t work for me. It sais: “Redirecting to null” (FF13)

Again, it’s because of the URI problem: http://localhost/rl/[b]
APP/1
[/b]/project_metrics.xml

ApplicationContext ctx = ((ReallotoApplication) getApplication())
						.getContext();
				WebApplicationContext webCtx = (WebApplicationContext) ctx;
				ServletContext sc = webCtx.getHttpSession().getServletContext();

				String reportFile = sc.getRealPath("\\WEB-INF\\classes")
						+ "\\project metrics.xml";
				InputStream is = null;
				final byte[] bConv;
				StreamResource.StreamSource source = null;
				try {
					is = new FileInputStream(reportFile);
					bConv = IOUtils.toByteArray(is);
					source = new StreamResource.StreamSource() {
						public InputStream getStream() {
							return new ByteArrayInputStream(bConv);
						}
					};
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				StreamResource resource = new StreamResource(source,
						"project_metrics.xml", ReallotoApplication
								.getInstance());
				resource.setMIMEType("application/unknown");

				getApplication().getMainWindow().open(resource);