themarcuz
themarcuz

Reputation: 2583

JSF PrimeFaces FileDownload problem

I'm using PrimeFaces for a new project and it's quite an impressive set of components. Anyway, I have problem with "real world" use of filedownload component. In my page I have a datalist that shows the attachments related to a particular document, and I want provide a link to directly download that file inside the datalist item. Here's my xhtml code:

<p:dataList id="ListaAllegati" value="#{documentBean.documento.allegati}" type="definition" var="attach" style="border: none" ">            
   <f:facet name="description">
      <h:outputText value="#{attach.name}" />                  
      <p:commandLink ajax="false" title="Download" action="#{documentBean.selectAttach}>  
         <h:graphicImage style="margin-left: 10px; border: none" value="./images/article.png" height="24" width="24" ></h:graphicImage>
         <p:fileDownload value="#{documentBean.downloadFile}"/>
         <f:setPropertyActionListener target="#{documentBean.selectedAttach}" value="#{attach}" />
      </p:commandLink>
   </f:facet>
</p:dataList>

and the relative java bean (request scoped):

private StreamedContent downloadFile;

public StreamedContent getDownloadFile() {      
    log.info("getter dell'allegato invocato");
    InputStream stream = null;
    byte[] rawFile = null;
    if (selectedAttach == null) {
        log.warn("Nessun allegato passato");
        return null;
    } else {
        try {
            log.info("Recupero del file " + selectedAttach.getGuid());
            rawFile = attachManager.retrieveFile(selectedAttach.getGuid());
        } catch (Exception e) {
            String msg = "Errore durante il recupero del file";
            log.error(msg, e);
            FacesMessage fmsg = new FacesMessage(msg, "");
            FacesContext.getCurrentInstance().addMessage(null, fmsg);
        }
        stream = new ByteArrayInputStream(rawFile);
        DefaultStreamedContent file = new DefaultStreamedContent(stream,
                selectedAttach.getMimeType(), selectedAttach.getName());
        return file;
    }
}

public void selectAttach() {
    log.info("commandLink action invocata");        
}

private Allegato selectedAttach;

public Allegato getSelectedAttach() {
   return selectedAttach;
}

public void setSelectedAttach(Allegato selectedAttach) {
   log.info("Allegato selezionato");
   if (selectedAttach==null) log.warn("L'allegato passato è nullo");
   this.selectedAttach = selectedAttach;
}

So, couple of question:

  1. Am I doing the right thing trying to pass the selected attachment that way? Otherwise, how can I pass a parameter to tell the bean wich attachment has been clicked?
  2. Why the first time I click the command link, nothing happen? It make a roundtrip with server, but nothing happens. Second time, it gives me an exception.
  3. Why documentBean.selectAttach is never called and the documentBean.selectedAttach property is never set (neither the second time)?

Thanks to anyone for any hint

Upvotes: 1

Views: 20890

Answers (2)

maple_shaft
maple_shaft

Reputation: 10463

Primefaces has its own dedicated servlet for file download and upload components that handle all of this asynchronously.

Try doing something like what I have in my code

<p:commandLink ajax="false" actionListener="#{managedBean.downloadAction(object)}">
  <span class="ui-icon icoFolderGo" style="padding-right: 1.5em;" />
  <p:fileDownload value="#{managedBean.downloadContentProperty}" />
</p:commandLink>

And in the managed bean,

public void downloadAction(Object object) {
  try {
    InputStream stream = // get input stream from argument  
    this.setDownloadContentProperty(new DefaultStreamedContent(stream, "application/pdf", "filename.pdf");
  } catch (Exception e) {
    log.error(e);
  }
}

public void setDownloadContentProperty(StreamedContent downloadContentProperty) {
  this.downloadContentProperty = downloadContentProperty;
}

public StreamedContent getDownloadContentProperty() {
  return downloadContentProperty;
}

Upvotes: 0

BalusC
BalusC

Reputation: 1108632

How to get the row object from the datatable is answered in this question:

This answers basically all the three questions.

As to the exception in the second click, that's likely because you didn't return from the catch block when an exception is been thrown in your getDownloadFile() method. You're continuing the remnant of the code flow while the rawFile is still null. Fix it accordingly as well. Add a return null to the end of catch or something. Better yet, you should be posting the entire stacktrace in the question as you don't seem to be able to understand it. It basically already contains the answer :)

Upvotes: 2

Related Questions