8 Replies Latest reply on Mar 13, 2009 11:35 AM by jjoji1

    Downloading a File from within a Portlet.

      I'm trying to create a portlet that allows a user to download a file from it. Since I can't figure out a way of changing the response header from within portlet, there's no way of setting the Content-Disposition. So if the content-disposition can't be set on the header, the browser doesn't know to initiate the download process.

      I know that I can easily use a Servlet to perform the download process but I just wanted to make sure that there's absolutely no way of performing the function from within the portlet alone.

      I am using JBoss Portal 2.7.0 GA.

        • 1. Re: Downloading a File from within a Portlet.
          claprun

          Use the new resource serving mechanism in JSR-286... See the spec for more details.

          • 2. Re: Downloading a File from within a Portlet.

            Thanks Chris, for responding to the post.

            I have looked at the spec and also tried to use the serveResource() method. The issue that I'm having is that changing the content type of the ResourceResponse object to the desired type (in this case a vCard with mime type of text/x-vcard), and streaming the content back to the client doesn't initiate a download of the vCard. It merely sends the result back as text and it's embedded into the browser.

            From my understanding of how to force the browser to initiate a download, i will have to set the response header of "Content-Disposition" with an attachment parameter to let the browser bring up a "Save As" dialogue or launch the target application.

            Any thoughts, or am I totally off base?

            Thanks again.

            • 3. Re: Downloading a File from within a Portlet.
              claprun

              Take a look at section 13.3 of JSR-286. You should be able to set the response header using setProperty on the PortletResponse...

              • 4. Re: Downloading a File from within a Portlet.

                Thank Chris! I was able to use your suggested approach and got the browser to respond with a "Save as" dialog box.

                The only strange thing that I noticed is that the filename sent back to the browser is not the one that I set on the header. Here's a code sample:

                response.setContentType("text/x-vcard");
                
                response.setProperty("Content-Disposition", "attachment; filename=" + personDetails.getFirstName() + "_" + personDetails.getLastName() + ".vcf");
                
                response.getPortletOutputStream().write(vCardData.getBytes());


                Essentially the filename in the browser should be of the format: Firstname_Lastname.vcf

                But instead the Portlet window name is used as the name of the file to be downloaded.

                Any thoughts on why this might be occuring?

                Thanks again for the help...much appreciated.


                • 5. Re: Downloading a File from within a Portlet.
                  felderr

                  Forget about the RenderResource! Just tried it out but JBoss Portal 2.7 responded with an not yet implemented Exception!

                  What JSR 286 compliant container is JBoss Portal 2.7?? For my opinion it is not compliant to the JSR 286 Specification in any way!!!

                  Here's the code for anyone runnning a JSF Application via the Portlet Bridge:

                  public String getRenderResourceUrl() {
                  Object responseObject = FacesContext.getCurrentInstance().getExternalContext().getResponse();
                  if (responseObject instanceof RenderResponse) {
                  RenderResponse response = (RenderResponse)responseObject;
                  return response.createResourceURL().toString();
                  }
                  return "";
                  }


                  to anyone else who is a native Portlet you can use:

                  <html xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:portlet="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
                  xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
                  <portlet:resourceURL var="signedPdf"/>
                  Download file


                  If you are running in a JSR 168 compliant Portlet Container you can try to get access to the HttpServletRequest where you can set the ContentType:

                  public HttpServletRequest getHttpServletRequest(PortletRequest request) {
                  PortletInvocation portletInvocation = (PortletInvocation) request.getAttribute(ContextDispatcherInterceptor.REQ_ATT_COMPONENT_INVOCATION);
                  return portletInvocation.getDispatchedRequest();
                  }

                  The problem with this approach is that JBoss Portal overrides the ContentType after you set it.

                  For my opinion the only solution is to forward to a Servlet to handel PDF downloads! The worst solution as you do not have any access to the Portlet attributes any more. But JBoss does not offer any other solution.

                  Looks to me that they ignore the fact of using JBoss Portal in real world systems. Watch out for Liferay they give you solutions for down- and uploading files.

                  • 6. Re: Downloading a File from within a Portlet.
                    theute

                    analyzediz do you have your portlet that I could try ? (you can send it to me by email)

                    • 7. Re: Downloading a File from within a Portlet.
                      yacoobkb

                      Hi,

                      Iam struck up with this issue for the past two days any help will be greatly appreciated.

                      I have a JSF(xhtml) with the following command link

                       <a4j:commandLink action="#{navigateBean.downloadPDF}"
                       value="View PDF"></a4j:commandLink>
                      


                      Clicking the View PDF should call the bean and the downloadPDF method will call a servlet

                      Bean code:
                      
                      package com.portal.tata.beans;
                      
                      import javax.faces.context.FacesContext;
                      
                      import org.jboss.seam.ScopeType;
                      import org.jboss.seam.annotations.Logger;
                      import org.jboss.seam.annotations.Name;
                      import org.jboss.seam.annotations.Scope;
                      import org.jboss.seam.log.Log;
                      
                      /**
                       * Created by IntelliJ IDEA. User: bharat Date: Sep 27, 2007 Time: 10:30:58 AM
                       * To change this template use File | Settings | File Templates.
                       */
                      
                      @Name("navigateBean")
                      @Scope(ScopeType.SESSION)
                      public class NavigateBean {
                      
                       @Logger
                       static Log log;
                      
                       String linkType = "";
                      
                       public String getLinkType() {
                       return linkType;
                       }
                      
                       public void setLinkType(String linkType) {
                       log.info("setLinkType", linkType);
                       this.linkType = linkType;
                       }
                      
                       public String delegateReq() {
                       log.info("linkType", linkType);
                       return linkType;
                       }
                      
                       public String forward() {
                       System.out.println("Check............");
                       log.info("forward", "forward this");
                       return "done";
                       }
                      
                       public String downloadPDF() {
                       System.out.println("NavigateBean.downloadPDF()..........");
                       // We must get first our context
                      
                       String url = "/servlet/downloadservlet?fileName=Reports.pdf";
                       FacesContext context = FacesContext.getCurrentInstance();
                      
                       try {
                       context.getExternalContext().dispatch(url);
                       } catch (Exception e) {
                       e.printStackTrace();
                       } finally {
                       context.responseComplete();
                       }
                       return "success";
                       }
                      }
                      
                      


                      Servlet code:

                      
                      package com.portal.tata;
                      
                      import javax.servlet.http.HttpServlet;
                      import javax.servlet.ServletOutputStream;
                      import javax.servlet.http.HttpServletRequest;
                      import javax.servlet.http.HttpServletResponse;
                      import java.io.File;
                      import java.io.PrintWriter;
                      import java.io.FileInputStream;
                      import java.io.IOException;
                      
                      public class DownloadServlet extends HttpServlet {
                      
                       public void doPost(HttpServletRequest request, HttpServletResponse response)
                       throws IOException {
                       doGet(request, response);
                       }
                      
                       public void doGet(HttpServletRequest request, HttpServletResponse response)
                       throws IOException {
                       System.out.println("DownloadServlet.doGet()");
                       String fileName = request.getParameter("fileName");
                       System.out.println("fileName==="+fileName);
                       if (fileName == null) {
                       response.setContentType("text/html");
                       PrintWriter writer = response.getWriter();
                       writer.print("<h2>No fileName get parameter was passed</h2>");
                       writer.close();
                       return;
                       }
                       try {
                       File newFile = new File(fileName);
                       System.out.println("newFile.isFile()::"+newFile.isFile());
                       System.out.println("path::"+newFile.getAbsolutePath());
                      
                       FileInputStream in = new FileInputStream(newFile);
                       ServletOutputStream out = response.getOutputStream();
                       response.setContentType("application/pdf");
                       response.setContentLength((int) newFile.length());
                       response.setHeader("Content-Disposition", "attachment;filename="+fileName);
                      
                       for (int i = in.read(); i != -1; i = in.read()) {
                       out.write(i);
                       }
                       in.close();
                       out.flush();
                       out.close();
                       System.out.println("========================================");
                       } catch (Exception e) {
                       e.printStackTrace();
                       response.setContentType("text/html");
                       PrintWriter writer = response.getWriter();
                       writer.print("<h2>Sorry, that file cannot befound </h2>");
                       writer.close();
                       }
                       }
                      }
                      



                      What is happening is on clicking the link the browser shows the junk character of the pdf instead of opening a pop-up save dialog box.

                      Thanks
                      Yacoob



                      • 8. Re: Downloading a File from within a Portlet.
                        jjoji1

                        Hi yacoobkb,

                        I am stuck at the same stage. Did you solve this problem? if so, Can you please share what you did ?