'How to use Streamed Content with p:fileDownload to Download Non class path File

I'm using Primefaces

p:fileDownload

to download a file which is not in class path.
So I'm passing FileInputStream as parameter to DefaultStreamedContent.
Every thing works fine when my bean is kept at @SessionScoped...,
But

java.io.NotSerializableException: java.io.FileInputStream

is thrown when I keep my bean in @Viewscoped.

My Code:

DownloadBean.java

@ManagedBean
@ViewScoped
public class DownloadBean implements Serializable {

    private StreamedContent dFile;

    public StreamedContent getdFile() {
        return dFile;
    }

    public void setdFile(StreamedContent dFile) {
        this.dFile = dFile;
    }

    /**
     * This Method will be called when download link is clicked
     */
    public void downloadAction()
    {
        File tempFile = new File("C:/temp.txt");
        try {
            dFile = new DefaultStreamedContent(new FileInputStream(tempFile), new MimetypesFileTypeMap().getContentType(tempFile));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

}

index.xhtml

<h:form>
    <h:commandLink action="#{downloadBean.downloadAction}">
        Download
        <p:fileDownload value="#{downloadBean.dFile}"/>
    </h:commandLink>
</h:form>

Isn't there any method to make it work?



Solution 1:[1]

@BalusC, for p:fileDownload, is there a way to offload the creation of the StreamedContent to another object which could then be called directly from JSF? Similar to the way you offload p:graphicImage here. If so what would be the scope of this special object? I'm guessing RequestScoped since there would be no connection between initDownload and getDownload. ApplicationScoped would not be able to keep track of all downloads within a single session, right? I also wonder if creating a new Apache FOP object in every Request is too expensive?

Here's an example:

jsf:

<h:commandButton value="print/download" action="#{streamhelper.initDownload()}">
                        <p:fileDownload value="#{streamhelper.download}"/>
                     <f:param name="html" value="#{bean.html}" />
                     <f:param name="idNum" value="#{bean.idNum}" />                         
                    </h:commandButton>

special object:

@Named("streamhelper") @RequestScoped @Getter @Setter @Slf4j
public class StreamedContentHelper
{
    @PostConstruct @SneakyThrows({NamingException.class})
    public void init(){
        fop = util.getLocator().getObject(util.getLocator().prependPortableName(FOPEngineImpl.class.getSimpleName()));
    }
    
    public void initDownload() throws Exception
    {
        FacesContext context = FacesContext.getCurrentInstance();

        log.trace("context PhaseID: {}", context.getCurrentPhaseId());
            
            String html = context.getExternalContext().getRequestParameterMap().get("html");            
            
            String idNum = context.getExternalContext().getRequestParameterMap().get("idNum");                                                            
                            
            byte[] attachBytes = fop.getPDFBytes(html);                
            InputStream stream = new ByteArrayInputStream(attachBytes);
            stream.mark(0); //remember to this position!
            String filename = String.format("%s-download.pdf", loadNum);
            download = new DefaultStreamedContent(stream, "application/pdf", filename);

    }        
    private StreamedContent download;
    private FOPEngineLocal fop;
    private @Inject Util util;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1