1 2 Previous Next 17 Replies Latest reply on Mar 23, 2008 5:13 PM by msystems

    Direct PDF serving

    mki_ffm

      Hi,


      i have created a pdf with itext directly in my action class and iText is offering me some outputstream options (e.g. ByteArrayOutputStream, ...)


      Now i would like to send this pdf (stream)  to a browser without using a jsf (.xhtml) page. Or is there a tag to this ?
      I do not want to store the pdf on disc if i can avoid it.


      Is this possible ?


      Any ideas are welcome.


      Best regards.


      mki

        • 1. Re: Direct PDF serving
          damianharvey.damianharvey.gmail.com

          Easy. Use the byteArrayOutputStream and hook it up to a servlet. You can keep the byteArrayOutputStream in memory in a conversation/session scoped Bean until the servlet needs it. Use Component.getInstance() in your servlet to access the Bean.


          Cheers,


          Damian.

          • 2. Re: Direct PDF serving
            keithnaas

            mki,


            Possibly an even easier way that doesn't require writing a custom servlet....write a Seam component that serves up the report - this is the approach we took for the application we demoed at JbossWorld.


            @Name("reportAction")
            public class ReportAction
            {
                @In
                private FacesContext facesContext;
                
                public void run() 
                { 
            
            final HttpServletResponse resp = (HttpServletResponse) facesContext.getExternalContext().getResponse();
            // run the report            
            // write the report to resp.getOutputStream()
                        facesContext.responseComplete();
                }
            }
            



            Then in xhtml


            <h:commandLink action="#{reportAction.run}"/>
            



            or


            <s:link action="#{reportAction.run}"/>
            



            etc.


            Good luck!

            • 3. Re: Direct PDF serving
              mki_ffm

              Thanks Keith,


              that was exactly the solution i was looking for. :-)

              • 4. Re: Direct PDF serving
                damianharvey.damianharvey.gmail.com

                Keith,


                I gave this a go and it's very cool and easier to implement than the servlet. The only thing that escapes me at the moment is how to assign a filename to the download. With the servlet I used a servlet URL pattern so I could put any name in the link.


                What is the JSF equivalent of that?


                Cheers,


                Damian.

                • 5. Re: Direct PDF serving
                  mki_ffm

                  That's easy, you simply have to set the Content-Disposition in the header:



                            final HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
                            
                            response.setContentType("application/pdf");
                            response.setHeader("Content-Disposition", " attachment; filename=invoice.pdf");




                  Greetings,


                  Manuel

                  • 6. Re: Direct PDF serving
                    keithnaas

                    Damian, Manuel has it dead on.  If I remember correctly IE behaves slightly differently than the other browsers so you may or may not see the right filename in all browsers.  I just found this article that describes IE's flakiness.


                    I would have replied sooner, but we just had a record snowfall of 16 inches and I've spent a good part of the day digging out of it!


                    Keith

                    • 7. Re: Direct PDF serving
                      damianharvey.damianharvey.gmail.com

                      Genius. Thanks Manuel & Keith. Much appreciated.


                      Cheers,


                      Damian.

                      • 8. Re: Direct PDF serving

                        I have used exactly that technique a couple of times, but recently I got notice from quite a few customers that it did not work.


                        The problem was Safari (3+ something, whatever ships with their newest cat-release), where this approch does not work. So we also had to go with the custom servlet approach, which works fine.

                        • 9. Re: Direct PDF serving
                          tracker

                          I implemented the solution described by Keith Naas on 3/6, and it got it working. I'm just learning, so it took a little while. Now that I have it, I would like to expose the servlet so that it is available by direct URL, instead of by JSF commandLink. Is that possible? How would I go about doing that?

                          • 10. Re: Direct PDF serving
                            mki_ffm

                            Ken,


                            you can define a link to your action in pages.xml.


                            <page view-id="/pdf.xhtml" action="#{pdfgeneratorAction.generate}"/> 



                            Manuel

                            • 11. Re: Direct PDF serving
                              tracker

                              Thanks Manuel. Is there a way to configure it so that the page I use (/pdf.xhtml in your example) doesn't actually have to exist? I can certainly put the page in place, but it seems sort of kludgy, since it never gets displayed, and never should.

                              • 12. Re: Direct PDF serving
                                tracker

                                Thanks for your help. I am new at this, so I'm certain I'm asking questions that would seem stupid to anyone who knows this stuff, but anyway, I have one more thing. I was hoping to pass form information in the request, and use that to manipulate the PDF created. After setting up access through pages.xml, I'm not seeing any parameters in the HttpServletRequest object. I promise I'm not trying to get you to write my code for me, but I'm up against the boundaries of my knowledge.


                                The HTML code that calls this looks like this:



                                <html>
                                <head>
                                <title>Connector test</title>
                                </head>
                                <body>
                                
                                <p> </p>
                                <form action="http://localhost/hbi/services/pdf/test.seam" method="post">
                                <input name="content" id="content" type="text" size=20>
                                <div><input type="submit" value="PDF"></div>
                                </form>
                                
                                </body>
                                </html>




                                My code looks like this, and I'm finding nothing in my parameterMap:



                                public class PrintServer extends SeamResourceServlet {
                                     private static final long serialVersionUID = 1278807414184735439L;
                                
                                     @In
                                    private FacesContext facesContext;
                                     
                                     @Logger
                                     private static Log log;
                                     
                                     
                                     public void test( String message )
                                           throws ServletException, IOException, DocumentException
                                     {
                                          final HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
                                          final HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
                                
                                          log.info( "context path: " + request.getContextPath());
                                          log.info( "method: " + request.getMethod());
                                          log.info( "URI: " + request.getRequestURI());
                                          
                                          Map parameterMap = request.getParameterMap();
                                          
                                          if( parameterMap==null)
                                          {
                                               log.info( "Can't get parameter names");
                                          }
                                          else
                                          {
                                               
                                               log.info("Request Parameters: " + parameterMap.toString());
                                               Collection <Map.Entry> paramCollection =  parameterMap.entrySet();
                                               java.util.Iterator <Map.Entry> paramIterator = paramCollection.iterator();
                                               
                                               while( paramIterator.hasNext())
                                               {
                                                    Map.Entry me = paramIterator.next();
                                                    String [] sa = (String [] ) me.getValue();
                                                    String sValue = "";
                                                    
                                                    for( int i=0; i<sa.length; ++i )
                                                    {
                                                         sValue += sa[i] + ",";
                                                    }
                                                    log.info("Request Parameter " + me.getKey() + " size " + sValue);
                                               }
                                               log.info("Request Parameters size: " + parameterMap.size());
                                          }
                                          log.info("Request Querystring: " + request.getQueryString());
                                
                                          facesContext.responseComplete();
                                          
                                          ServletOutputStream out = response.getOutputStream();
                                          
                                          Document document = new Document();
                                          PdfWriter.getInstance(document, out);
                                          document.open();
                                          document.add(new Paragraph("Form message: " + message));
                                          document.close();
                                          
                                          response.setContentType("application/pdf");
                                          response.setHeader("Content-Disposition", " attachment; filename=PrintTest.pdf");                      
                                          
                                          log.info("Run GraphServer.test");
                                          return;
                                     }
                                }

                                • 13. Re: Direct PDF serving
                                  mki_ffm

                                  Ken,


                                  the beauty of the solution in 3 is, that it does even not use a servlet to deliver the PDF, so you can do everything in a standard seam way by calling an action, create the pdf and deliver it to the browser.


                                  Inside this action you have easy access to all form values.


                                  So why going the hard way ?



                                  Manuel

                                  • 14. Re: Direct PDF serving
                                    tracker

                                    Thanks for your help Manuel.


                                    Am I going the hard way? I thought I was replicating the solution above. I do see that my code extends the SeamResourceServlet, but I'm not using that interface - it was left over from my servlet approach, and I forgot to remove it.


                                    I restarted my JBoss server (the whole machine, in fact) and now I'm seeing the form information. There must have been something left in my deployment that was interfering, and it got cleaned out by the restart. So the code I provided above works after all.


                                    As a last question, is there a better/simpler way to retrieve the form information than what I do above?


                                    Thanks again.

                                    1 2 Previous Next