1

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

themarcuz
  • 2,573
  • 6
  • 36
  • 53

2 Answers2

2

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 :)

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I'm sorry but I don't understand what I'm doing wrong. I start from your blog post to build that page, but something is not working as expected and I don't understand why. The documentBean.selectAttach action is not invoked. Neither is the documentBean.setSelectedAttach bound to the setPropertyActionListener. Just the documentBean.getDownloadFile is invoked and, returning null, it throw an exception. I don't understand the reason of this behaviour.... moreover it's still true that the first time I click on che image, a round trip occurs, but none of the action method or setters is invoked :( – themarcuz Jun 06 '11 at 10:32
  • I also did some experiment, and everything seems to work as expected if I remove the primefaces filedownload tag: obviously no attach is downloaded :) but all the setters, the getters and the action is invoked as expected, even the first time I click on the image. It seems to me that there is an issue with the primefaces filedownload component... – themarcuz Jun 06 '11 at 10:49
  • @themarcuz: well, after the last instruction in your catch block, you just go on with rawFile most probably being null. Return before. Or better, don't catch Exception (too wide), and have an appropriate error page for anything uncaught. – ymajoros Feb 06 '12 at 14:14
0

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;
}
maple_shaft
  • 10,435
  • 6
  • 46
  • 74
  • The OP is already using ``. He's only doing the `StreamedContent` creation job in the getter instead of in the action method. – BalusC Jun 01 '11 at 15:56