Rectangle 27 6

Your concrete problem is caused because the webbrowser is actually downloading the PDF file in a physically completely separate HTTP request than the HTTP request which is generating and sending the HTML output based on JSF source code. You probably already know that view scoped beans are tied to a particular JSF view via javax.faces.ViewState hidden input field. If this get changed or is absent, then the request gets a new and different view scoped bean instance.

In other words, while the browser is downloading the PDF file from the server in a separate HTTP request, it isn't using the same @ViewScoped bean instance, but instead getting a brand new and completely independent instance which does not hold the same properties (state) as the one tied to the page and thus the whole StreamedContent is simply null at that point.

This problem with <p:media> and StreamedContent has essentially the same grounds as the problem with <p:graphicImage> and StreamedContent which is answered several times before:

In your particular case, you need to redesign the whole bunch in such way that the DocumentsBean backing bean stores the PDF file in some place (e.g. temp disk, server memory, database, etc) by an unique identifier and then pass exactly that unique identifier along as request parameter to <p:media> as follows:

<p:media value="#{mediaManager.stream}" width="100%" height="700px" player="pdf">
    <f:param name="id" value="#{documentsBean.mediaId}" />
</p:media>

Whereby the MediaManager backing bean look something like this:

@ManagedBean
@ApplicationScoped
public class MediaManager {

    @EJB
    private MediaService service;

    public StreamedContent getStream() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();

        if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
            // So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
            return new DefaultStreamedContent();
        } else {
            // So, browser is requesting the media. Return a real StreamedContent with the media bytes.
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            Media media = service.find(Long.valueOf(id));
            return new DefaultStreamedContent(new ByteArrayInputStream(media.getBytes()));
        }
    }

}

Great, works! Your blog really helps. I actually just start to use JSF2, so I dont have too much experience on identifying category of this problem. I am still absorbing.

jsf - primefaces update pdf media not working - Stack Overflow

jsf pdf jsf-2 primefaces
Rectangle 27 0

You need to let the client send 2 HTTP requests. In this particular case, easiest would be to store the data which is necessary for generating the PDF temporarily in session and use JavaScript's window.open() to fire a new request in a new window which in turn triggers the PDF generation. E.g.

id = UUID.randomUUID().toString();
Data data = collectDataWhichIsNecessaryForGeneratingPdf();
externalContext.getSessionMap().put(id, data);
return "brandNewEmptyform";

with in the brand new empty form

<h:outputScript rendered="#{not empty bean.id}">
    window.open('somePdfServlet?id=#{bean.id}');
</h:outputScript>

and then in the servlet which is mapped on /somePdfServlet:

String id = request.getParameter("id");
Data data = (Data) session.getAttribute(id);
session.removeAttribute(id);
// Now generate PDF based on data and write to response the usual way.

jsf 2 - primefaces: how to show pdf AND load new form (separate window...

jsf-2 primefaces
Rectangle 27 0

I can reproduce your problem. It indeed doesn't work in Firefox (nor in IE9, but it works in Chrome). PrimeFaces lead Cagatay has also mentioned that several times.

I'm not sure if this is a bug in the PrimeFaces resource handler or in the browser. I'll leave it in the middle.

In the meanwhile, your best bet is a simple web servlet for the job. Just create this class:

@WebServlet("/report.pdf")
public class PdfReportServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        byte[] content = (byte[]) request.getSession().getAttribute("reportBytes");
        response.setContentType("application/pdf");
        response.setContentLength(content.length);
        response.getOutputStream().write(content);
    }

}

And invoke it as follows:

<p:media value="/report.pdf" ... />

That's it. No XML config necessary. It works for me in all browsers. Depending on the functional requirements, you may want to further finetune response headers related to browser caching.

I think that real problem is in PrimeResourceHandler.handleResourceRequest, in finally part is this line session.remove(dynamicContentId). That is maybe a point where these two requests have race condition.

With the servlet workaround, Firefox sends only 1 request on the PDF instead of 2. So the problem is actually in the response of the 1st request; the browser somehow couldn't deal with it. If I have more time I'd investigate it, but not now :)

Thank you BalusC. -Although, its sad that in 2015, we have to resort to "workaround" for IE11. (IE11 was still getting the "must start with '%PDF-' error, so I am using your servlet technique)

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media
Rectangle 27 0

I can reproduce your problem. It indeed doesn't work in Firefox (nor in IE9, but it works in Chrome). PrimeFaces lead Cagatay has also mentioned that several times.

I'm not sure if this is a bug in the PrimeFaces resource handler or in the browser. I'll leave it in the middle.

In the meanwhile, your best bet is a simple web servlet for the job. Just create this class:

@WebServlet("/report.pdf")
public class PdfReportServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        byte[] content = (byte[]) request.getSession().getAttribute("reportBytes");
        response.setContentType("application/pdf");
        response.setContentLength(content.length);
        response.getOutputStream().write(content);
    }

}

And invoke it as follows:

<p:media value="/report.pdf" ... />

That's it. No XML config necessary. It works for me in all browsers. Depending on the functional requirements, you may want to further finetune response headers related to browser caching.

I think that real problem is in PrimeResourceHandler.handleResourceRequest, in finally part is this line session.remove(dynamicContentId). That is maybe a point where these two requests have race condition.

With the servlet workaround, Firefox sends only 1 request on the PDF instead of 2. So the problem is actually in the response of the 1st request; the browser somehow couldn't deal with it. If I have more time I'd investigate it, but not now :)

Thank you BalusC. -Although, its sad that in 2015, we have to resort to "workaround" for IE11. (IE11 was still getting the "must start with '%PDF-' error, so I am using your servlet technique)

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media
Rectangle 27 0

Don't call super.doGet: that's what is throwing the "GET not supported" error. The default implementation of doGet (i.e. the one defined in HttpServlet which is the super class here, is to print the message that GET is undefined. Because by default, you haven't defined it yet (i.e. not overloaded the doGet method). So when you call super.doGet its filling the response with the 405 headers. You don't want the super class to run its default method; you only want your overloaded method to run.

After you've called super.doGet the rest of your function is wrapped in a try with an empty catch. I think probably, if you were to output the error there to a log it would be something like "response headers already set" because the call to super.doGet already set the headers to content-type HTML, status 405, etc. so your attempt to change the content-type to PDF is going to throw an error there.

As to the rest of your problem, you have not set enough headers. Namely, you are missing these two:

I would advise just passing the servlet response outputstream directly into the getInstance method of the PDF writer:

(You probably also want to save the writer into a variable PdfWriter writer = PdfWriter.getInstance(....);) and maybe do something with it.

That way you aren't writing to a buffer, reading from the buffer, and finally writing to the response. It just writes the PDF to the response directly instead. And there's no need to manually flush or close the response buffer. Doing it this way does mean you can no longer set the content length header, but that one is not necessary anyway and will cause problems if you get it wrong.

Also, if you set the headers first, at the very top, then it will be locked in to serving the response as PDF even if it encounters an error and doesn't actually build a valid PDF, so that rather than ending up with a blank page, in the event of an error, you'll end up with a blank (i.e. corrupt) PDF. So at least the PDF application will open. It will just open with an error like "Could not open this PDF; it may be corrupt."

Great answer, however I have one comment: there is a reason why people write the PDF bytes to memory first. Some browsers can't deal with PDF very well. They read data in blocks of a fixed size, adding meaningless bytes at the end of the PDF file if its size isn't a multiple of the fixed size. The only way to work around this, is by adding a header with the file size response.setContentLength(pdfOutputStream.size());. The only way to know the file size, is to create the PDF in memory first.

Now that you mention it, I do recall that issue with IE6.

servlets - Pdf generating using iText on a primefaces project - Stack ...

servlets pdf itext
Rectangle 27 0

I can reproduce your problem. It indeed doesn't work in Firefox (nor in IE9, but it works in Chrome). PrimeFaces lead Cagatay has also mentioned that several times.

I'm not sure if this is a bug in the PrimeFaces resource handler or in the browser. I'll leave it in the middle.

In the meanwhile, your best bet is a simple web servlet for the job. Just create this class:

@WebServlet("/report.pdf")
public class PdfReportServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        byte[] content = (byte[]) request.getSession().getAttribute("reportBytes");
        response.setContentType("application/pdf");
        response.setContentLength(content.length);
        response.getOutputStream().write(content);
    }

}

And invoke it as follows:

<p:media value="/report.pdf" ... />

That's it. No XML config necessary. It works for me in all browsers. Depending on the functional requirements, you may want to further finetune response headers related to browser caching.

I think that real problem is in PrimeResourceHandler.handleResourceRequest, in finally part is this line session.remove(dynamicContentId). That is maybe a point where these two requests have race condition.

With the servlet workaround, Firefox sends only 1 request on the PDF instead of 2. So the problem is actually in the response of the 1st request; the browser somehow couldn't deal with it. If I have more time I'd investigate it, but not now :)

Thank you BalusC. -Although, its sad that in 2015, we have to resort to "workaround" for IE11. (IE11 was still getting the "must start with '%PDF-' error, so I am using your servlet technique)

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media
Rectangle 27 0

If you look at whats going on in the PDFExporter.java export method, the data table in the PDF can not manipulated.

com.itextpdf.text.Document
Document document = new Document(PageSize.A4.rotate());

Then the preProcessor method is called passing the Document, this is before the table is added to the PDF Document.

if(preProcessor != null) {
    preProcessor.invoke(facesContext.getELContext(), new Object[]{document});
}

Then the com.itextpdf.text.pdf.PdfPTable is created. The exportPDFTable method doesn't do any special formatting.

PdfPTable pdfTable = exportPDFTable(table, excludeColumns);
document.add(pdfTable);

Now the postProcess method is called and the Document is passed again. Here I would think you would be able to access and change the PdfPTable from the Document object but looking at the iText api it doesn't look like you can.

if(postProcessor != null) {
    postProcessor.invoke(facesContext.getELContext(), new Object[]{document});
}

So if you want a styled PDF table your going to have to implement your own PDF export. Hopefully looking at how the PrimeFaces PDFExporter is done will help you with that.

Thanks Mark for the detailed information. I'll think about implement my own PDF export.

changing style on generating pdf with Primefaces dataExporter - Stack ...

primefaces
Rectangle 27 0

If you look at whats going on in the PDFExporter.java export method, the data table in the PDF can not manipulated.

com.itextpdf.text.Document
Document document = new Document(PageSize.A4.rotate());

Then the preProcessor method is called passing the Document, this is before the table is added to the PDF Document.

if(preProcessor != null) {
    preProcessor.invoke(facesContext.getELContext(), new Object[]{document});
}

Then the com.itextpdf.text.pdf.PdfPTable is created. The exportPDFTable method doesn't do any special formatting.

PdfPTable pdfTable = exportPDFTable(table, excludeColumns);
document.add(pdfTable);

Now the postProcess method is called and the Document is passed again. Here I would think you would be able to access and change the PdfPTable from the Document object but looking at the iText api it doesn't look like you can.

if(postProcessor != null) {
    postProcessor.invoke(facesContext.getELContext(), new Object[]{document});
}

So if you want a styled PDF table your going to have to implement your own PDF export. Hopefully looking at how the PrimeFaces PDFExporter is done will help you with that.

Thanks Mark for the detailed information. I'll think about implement my own PDF export.

changing style on generating pdf with Primefaces dataExporter - Stack ...

primefaces
Rectangle 27 0

Your concrete problem is caused because the webbrowser is actually downloading the PDF file in a physically completely separate HTTP request than the HTTP request which is generating and sending the HTML output based on JSF source code. You probably already know that view scoped beans are tied to a particular JSF view via javax.faces.ViewState hidden input field. If this get changed or is absent, then the request gets a new and different view scoped bean instance.

In other words, while the browser is downloading the PDF file from the server in a separate HTTP request, it isn't using the same @ViewScoped bean instance, but instead getting a brand new and completely independent instance which does not hold the same properties (state) as the one tied to the page and thus the whole StreamedContent is simply null at that point.

This problem with <p:media> and StreamedContent has essentially the same grounds as the problem with <p:graphicImage> and StreamedContent which is answered several times before:

In your particular case, you need to redesign the whole bunch in such way that the DocumentsBean backing bean stores the PDF file in some place (e.g. temp disk, server memory, database, etc) by an unique identifier and then pass exactly that unique identifier along as request parameter to <p:media> as follows:

<p:media value="#{mediaManager.stream}" width="100%" height="700px" player="pdf">
    <f:param name="id" value="#{documentsBean.mediaId}" />
</p:media>

Whereby the MediaManager backing bean look something like this:

@ManagedBean
@ApplicationScoped
public class MediaManager {

    @EJB
    private MediaService service;

    public StreamedContent getStream() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();

        if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
            // So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
            return new DefaultStreamedContent();
        } else {
            // So, browser is requesting the media. Return a real StreamedContent with the media bytes.
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            Media media = service.find(Long.valueOf(id));
            return new DefaultStreamedContent(new ByteArrayInputStream(media.getBytes()));
        }
    }

}

Great, works! Your blog really helps. I actually just start to use JSF2, so I dont have too much experience on identifying category of this problem. I am still absorbing.

jsf - primefaces update pdf media not working - Stack Overflow

jsf pdf jsf-2 primefaces
Rectangle 27 0

I hope my little contribution can help anyone who can't display pdf preview in Firefox. I was using Primefaces 6 + Spring and I had the same problem but maybe not due the same reason. Indeed, I tried the proposed solution by Balus C. It helped me to display the pdf in Chrome and IE11 but it still was not working in Firefox 52.

I noticed an error in the Firefox console: Load denied by X-Frame-Options: http://localhost:8080/myapp/ does not permit framing

In my case, it was because spring-security configuration and the solution was edit spring-context.xml in this way:

<sec:http ...>
...
<sec:headers>        		
         <sec:frame-options policy="SAMEORIGIN" />
</sec:headers>
...
</sec:http>

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media
Rectangle 27 0

It is not a browser or primefaces problem, just a funny getter problem.

The getter is called twice by p:media (or if you refresh page than more times), but only the 1st call gets the correct data. StreamedContent encapsulates an InputStream, which has the property that it will give no bytes if the stream is at the end of the file. First time it is read to its end (data is ok), but every next call will get no data. :)

private StreamedContent streamedContent;
            private InputStream stream;


            public void somewhere(){
                byte[] b = ...
                stream = new ByteArrayInputStream( b );
                stream.mark(0); //remember to this position!
                streamedContent = new DefaultStreamedContent(stream, "application/pdf");
            }


            public StreamedContent getStreamedContent() {
                if (streamedContent != null)
                    streamedContent.getStream().reset(); //reset stream to the start position!
                return streamedContent;
            }

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media
Rectangle 27 0

Your concrete problem is caused because the webbrowser is actually downloading the PDF file in a physically completely separate HTTP request than the HTTP request which is generating and sending the HTML output based on JSF source code. You probably already know that view scoped beans are tied to a particular JSF view via javax.faces.ViewState hidden input field. If this get changed or is absent, then the request gets a new and different view scoped bean instance.

In other words, while the browser is downloading the PDF file from the server in a separate HTTP request, it isn't using the same @ViewScoped bean instance, but instead getting a brand new and completely independent instance which does not hold the same properties (state) as the one tied to the page and thus the whole StreamedContent is simply null at that point.

This problem with <p:media> and StreamedContent has essentially the same grounds as the problem with <p:graphicImage> and StreamedContent which is answered several times before:

In your particular case, you need to redesign the whole bunch in such way that the DocumentsBean backing bean stores the PDF file in some place (e.g. temp disk, server memory, database, etc) by an unique identifier and then pass exactly that unique identifier along as request parameter to <p:media> as follows:

<p:media value="#{mediaManager.stream}" width="100%" height="700px" player="pdf">
    <f:param name="id" value="#{documentsBean.mediaId}" />
</p:media>

Whereby the MediaManager backing bean look something like this:

@ManagedBean
@ApplicationScoped
public class MediaManager {

    @EJB
    private MediaService service;

    public StreamedContent getStream() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();

        if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
            // So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
            return new DefaultStreamedContent();
        } else {
            // So, browser is requesting the media. Return a real StreamedContent with the media bytes.
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            Media media = service.find(Long.valueOf(id));
            return new DefaultStreamedContent(new ByteArrayInputStream(media.getBytes()));
        }
    }

}

Great, works! Your blog really helps. I actually just start to use JSF2, so I dont have too much experience on identifying category of this problem. I am still absorbing.

jsf - primefaces update pdf media not working - Stack Overflow

jsf pdf jsf-2 primefaces
Rectangle 27 0

It is not a browser or primefaces problem, just a funny getter problem.

The getter is called twice by p:media (or if you refresh page than more times), but only the 1st call gets the correct data. StreamedContent encapsulates an InputStream, which has the property that it will give no bytes if the stream is at the end of the file. First time it is read to its end (data is ok), but every next call will get no data. :)

private StreamedContent streamedContent;
            private InputStream stream;


            public void somewhere(){
                byte[] b = ...
                stream = new ByteArrayInputStream( b );
                stream.mark(0); //remember to this position!
                streamedContent = new DefaultStreamedContent(stream, "application/pdf");
            }


            public StreamedContent getStreamedContent() {
                if (streamedContent != null)
                    streamedContent.getStream().reset(); //reset stream to the start position!
                return streamedContent;
            }

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media
Rectangle 27 0

I hope my little contribution can help anyone who can't display pdf preview in Firefox. I was using Primefaces 6 + Spring and I had the same problem but maybe not due the same reason. Indeed, I tried the proposed solution by Balus C. It helped me to display the pdf in Chrome and IE11 but it still was not working in Firefox 52.

I noticed an error in the Firefox console: Load denied by X-Frame-Options: http://localhost:8080/myapp/ does not permit framing

In my case, it was because spring-security configuration and the solution was edit spring-context.xml in this way:

<sec:http ...>
...
<sec:headers>        		
         <sec:frame-options policy="SAMEORIGIN" />
</sec:headers>
...
</sec:http>

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media
Rectangle 27 0

It is not a browser or primefaces problem, just a funny getter problem.

The getter is called twice by p:media (or if you refresh page than more times), but only the 1st call gets the correct data. StreamedContent encapsulates an InputStream, which has the property that it will give no bytes if the stream is at the end of the file. First time it is read to its end (data is ok), but every next call will get no data. :)

private StreamedContent streamedContent;
            private InputStream stream;


            public void somewhere(){
                byte[] b = ...
                stream = new ByteArrayInputStream( b );
                stream.mark(0); //remember to this position!
                streamedContent = new DefaultStreamedContent(stream, "application/pdf");
            }


            public StreamedContent getStreamedContent() {
                if (streamedContent != null)
                    streamedContent.getStream().reset(); //reset stream to the start position!
                return streamedContent;
            }

jsf 2 - Unable to show PDF in p:media generated from streamed content ...

pdf jsf-2 primefaces stream media