10 Replies Latest reply on Jan 30, 2008 12:08 PM by tynor

    how to download a file via Seam& JSF,

    tyshan

      hi,

      I can upload a file successfully, but failed to download a file.

      I get an exception that

      Servlet response already use stream, Writer not possible


      and I use the codes

      HttpServletResponse res = (HttpServletResponse) javax.faces.context.FacesContext
      .getCurrentInstance().getExternalContext().getResponse();
      res.reset();


      anyonce can help me?

      Best regards

      Tyshan

        • 1. Re: how to download a file via Seam& JSF,
          tyshan

          hi,


          emmergency,

          how to get a OutputStream from the HttpServletResponse? or can I use a servlet to do that?


          Best regards

          Tyshan

          • 2. Re: how to download a file via Seam& JSF,

             

            "tyshan" wrote:
            hi,

            I can upload a file successfully, but failed to download a file.

            I get an exception that

            Servlet response already use stream, Writer not possible



            Same problem here trying to output a Jasper report. Perhaps calling another bean and exposing the generated report binary to JSF would work?


            • 3. Re: how to download a file via Seam& JSF,
              dustismo

               

              
              FacesContext context = FacesContext.getCurrentInstance();
              HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
              response.setContentType(contentType); //fill in contentType
              OutputStream os = response.getOutputStream();
              os.write(bytes); //fill in bytes
              os.flush();
              os.close();
              context.responseComplete();
              
              


              -Dustin

              • 4. Re: how to download a file via Seam& JSF,

                Thanks for the reply. Is that code working for you? Because that's exactly what I tried, but I get the

                Servlet response already use stream, Writer not possible
                


                error when I do that.


                • 5. Re: how to download a file via Seam& JSF,
                  nickarls

                  Hmm, using a ServletOutputStream os shouldn't make a difference, should it? One one think that it's the same code called...

                  • 6. Re: how to download a file via Seam& JSF,
                    nickarls

                    Is FacesContext.getCurrentInstance().getResponseStream() useable?

                    • 7. Re: how to download a file via Seam& JSF,
                      dustismo

                      The code I posted works fine for me.. Here is a working example.

                      Component:

                      @Name("testController")
                      @Scope(ScopeType.PAGE)
                      public class TestController {
                       public void hello() {
                       try {
                       FacesContext context = FacesContext.getCurrentInstance();
                       HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
                       response.setContentType("text/plain"); //fill in contentType
                       OutputStream os = response.getOutputStream();
                       os.write("HELLO THERE".getBytes()); //fill in bytes
                       os.flush();
                       os.close();
                       context.responseComplete();
                       } catch (Exception x) {
                       x.printStackTrace();
                       }
                       }
                      }
                      


                      View:

                      
                      <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                       xmlns:s="http://jboss.com/products/seam/taglib"
                       xmlns:ui="http://java.sun.com/jsf/facelets"
                       template="templates/template.xhtml"
                       >
                       <s:button action="#{testController.hello}" value="test"/>
                      
                      </ui:composition>
                      


                      • 8. Re: how to download a file via Seam& JSF,

                        Well I'm not sure why this isn't working for Jasper output, then. My code is very similar (although there is more involved, of course). I was actually getting the context before using injection, which worked better. I'm also using a session EJB - I assume your test code is not.

                        In any case, using

                        FacesContext context = FacesContext.getCurrentInstance();
                        

                        causes errors even earlier. When I do
                        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
                        

                        I get an exception:
                        20:00:28,098 ERROR [STDERR] java.lang.IllegalStateException
                        20:00:28,108 ERROR [STDERR] at com.sun.faces.context.FacesContextImpl.assertNotReleased(FacesContextImpl.java:428)
                        20:00:28,108 ERROR [STDERR] at com.sun.faces.context.FacesContextImpl.getExternalContext(FacesContextImpl.java:149)
                        20:00:28,108 ERROR [STDERR] at org.my.project.session.I9CertForm.generateCertificate(I9CertForm.java:145)
                        




                        • 9. Re: how to download a file via Seam& JSF,

                          Ok, I have my code working now. There were a couple of things that didn't work:

                          1) Initially I tried using the

                          JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
                          

                          for passing the outputStream from the Response object to the JasperExportManager. AFAIK, that's what produced the "Writer not possible" error.

                          2) In the session EJB, using FacesContext.getCurrentInstance() does not provide a usable context - at least not one that can be used to obtain the Response object. So maybe that's usable in a POJO component, but not an EJB component, and that's possibly by design, I don't know. Scope doesn't really seem to matter.

                          Anyway, what works is this:

                          - In the session EJB:
                          @In
                          private FacesContext facesContext;
                          private byte[] report1;
                          
                          ...
                          
                           String reportName = "/reports/myreport.jrxml";
                           CreateReport cr = new CreateReport();
                           report2 = cr.getReport(reportName);
                           try {
                           HttpServletResponse response = (HttpServletResponse)
                           facesContext.getExternalContext().getResponse();
                           response.setContentType("application/pdf");
                           OutputStream os = response.getOutputStream();
                           os.write(report2);
                           os.flush();
                           os.close();
                           facesContext.responseComplete();
                           } catch(Exception ex) {
                           ex.printStackTrace();
                           }
                          


                          Just for completeness - the CreateReport.getReport method just does the jasper stuff to load and fill the report, then return the byte array:
                          public byte[] getReport(String reportName)
                          {
                           try
                           {
                           ServletContext sCtxt = ServletLifecycle.getServletContext();
                           File reportFile = new File(sCtxt.getRealPath(reportName));
                           if( !reportFile.exists()) {
                           throw new JRRuntimeException("File " + reportName + " not found.");
                           }
                          
                           JasperDesign jasperDesign = JRXmlLoader.load(reportFile);
                           JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
                           JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
                          
                           if (jasperPrint != null) {
                           byte[] reportPDF = JasperExportManager.exportReportToPdf(jasperPrint);
                           return reportPDF;
                           } else {
                           throw new JRRuntimeException("null jasperPrint");
                           return null;
                           }
                           }
                           catch (Exception e)
                           {
                           e.printStackTrace();
                           }
                           return null;
                          }
                          


                          Thanks for the help!


                          • 10. Re: how to download a file via Seam& JSF,
                            tynor

                            Our application uses the same technique as discussed in this thread for downloading files (see below).

                            This works, but if any messages (FacesMessage) are queued during the generation of the downloaded content, they are not displayed to the user since the facesContext.responseComplete() interrups the JSF lifecycle and the view is never rerendered.

                            Is there a way to generate downloadable content, as below, but still refresh the browser view, showing any pending messages? In many cases, we wish to provide downloadable content, but also include warning messages (e.g., "Warning: generated report includes partially validated records").

                            Thanks!

                            HttpServletResponse response = (HttpServletResponse)facesContext.getExternalContext().getResponse();
                            try {
                             response.setContentType(contentType);
                             response.setHeader( "Content-Disposition", "attachment; filename=\""
                             + name + "\";");
                             response.getOutputStream().write(fileData);
                             response.setStatus(HttpServletResponse.SC_OK);
                             response.getOutputStream().close();
                             facesContext.responseComplete();
                            } catch (IOException ex) {
                             log.error("Error writing file data (#0 bytes) to response", ex, fileData.length);
                            }