0
votes

I am trying to display pdf file using p:media but shows nothing (display the pdf previewer on the dialog box). The code works for display it directly on the browser and also for download the file. There is no error return while I click the preview link. Below is the code:

<h:form enctype="multipart/form-data">
    <p:dataTable id="files" var="file" value="#{viewBacking.getFileList()}">
        <p:column headerText="File">
            <h:outputText value="#{file.name}" />
        </p:column>

        <p:column style="width:5%">
            <p:commandLink id="downloadLink" value="download" title="Download File" ajax="false" actionListener="#{viewBacking.getFileSelected(file, 1)}" >
                <p:fileDownload value="#{viewBacking.file}" />
            </p:commandLink>
        </p:column>

        <p:column style="width:5%">
            <p:commandLink id="previewLink" value="preview" title="Preview File" ajax="false" actionListener="#{viewBacking.getFileSelected(file, 2)}" onclick="dialogPdf.show()">
            </p:commandLink>
        </p:column>
    </p:dataTable>

    <p:dialog header="Images" widgetVar="dialogPdf" modal="true" draggable="false" resizable="false" width="1040" height="500">
        <p:media value="#{viewBacking.file}" width="100%" height="300px">  
        </p:media>
    </p:dialog>
</h:form>

This is the backing bean:

public class ViewBacking {
    private StreamedContent file;  
    public StreamedContent getFile() {  
        return file;
    }

    public StreamedContent getFileSelected(final StreamedContent doc, int mode) throws Exception {
        //Mode: 1-download, 2-preview
        try {
            File localfile = new File(getPath(doc.getName()));
            FileInputStream fis = new FileInputStream(localfile);
            //If mode preview and extension <> `pdf`, convert to `pdf`
            if (mode == 2 && !(doc.getName().substring(doc.getName().lastIndexOf(".") + 1)).matches("pdf")) {
                localfile = DocumentConversionUtil.convert(doc.getName(), fis, doc.getName().substring(doc.getName().lastIndexOf(".") + 1), "pdf");
                fis = new FileInputStream(localfile.getPath());
            }

            if (localfile.exists()) {
                try {
                    PortletResponse portletResponse = (PortletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
                    HttpServletResponse res = PortalUtil.getHttpServletResponse(portletResponse);
                    if (mode == 1)      res.setHeader("Content-Disposition", "attachment; filename=\"" + doc.getName() + "\"");
                    else if (mode == 2) res.setHeader("Content-Disposition", "inline; filename=\"" + doc.getName().substring(0, doc.getName().lastIndexOf(".")) + ".pdf\"");
                    res.setHeader("Content-Transfer-Encoding", "binary");
                    res.setContentType(getMimeType(localfile.getName().substring(localfile.getName().lastIndexOf(".") + 1)));
                    res.flushBuffer();
                    OutputStream out = res.getOutputStream();
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        out.write(buffer, 0, bytesRead);
                        buffer = new byte[4096];
                    }
                    file = new DefaultStreamedContent(fis, "application/pdf", "file.pdf"); //--> I tried to add this line to return the file StreamedContent

                    out.flush();
                    out.close();
                    out = null;
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    fis.close();
                    fis = null;
                    System.gc();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }
}

Should you need further information, do not hesitate to ask me. Thanks.

1
The best way to do deliver up a binary resource like a PDF is to use a JSF 2 ResourceHandler. It will work in both a webapp and portlet environment. I would recommend that you look at the source of the jsf2-export-pdf-portlet demo to learn how to do it. - Neil Griffin
@NeilGriffin: Thanks, but I only need to show the generated pdf to a dialog box, not starting from the beginning how to produce the pdf file. - mrjimoy_05
The source code for the PrimeFaces MediaRenderer.java class indicates that the value attribute of p:media can be either an instance of StreamedContent (like you have) or a String-based URL. - Neil Griffin

1 Answers

2
votes

The source code for the PrimeFaces MediaRenderer.java class indicates that the value attribute of p:media can be either an instance of StreamedContent (like you have) or a String-based URL.

The problem that I see with your getFileSelected method is that it sets header/contenttype, etc. on the underlying HttpServletResponse. This is problematic for two reasons:

1) If you ever need to do stuff like this, you should use the methods on ResourceResponse (part of the Portlet API)

2) Depending on when the getFileSelected method is being called, you might be attempting to change the content type of an Ajax request. The PrimeFaces JavaScript in the client is expecting a JSF partial-response, but you might be changing that to binary application/pdf.

I think the best way to handle this is to avoid returning an instance of StreamedContent, and instead to have the value attribute specify a URL like this:

And then have a custom Resource and ResourceHandler like the jsf2-export-pdf-portlet does.