0

i've a problem when i try to use primefaces messages in my code. When i just do a test, the message works well, but when i do a stream file and try to send a message in my xhtml, the process works well, but the message not grows up.

My Code:

public void cadastrar () throws KeyStoreException, CADoesntExistsException,        NoSuchAlgorithmException, CertificateException, IOException      
{           
    FacesContext fc = FacesContext.getCurrentInstance();            
    if((controlador.checkUserIfExist(certificadoModel.getUsername()) == false) || (controlador.checkUserIfExist(certificadoModel.getUsername()) == true && authorization == true))
    {
        System.out.println("Revoke: " + authorization);
        System.out.println("Check: " + controlador.checkUserIfExist(certificadoModel.getUsername()));
        //KeyStore keyStore = controlador.cadastrar(certificadoModel);      
        System.out.println("Bean Class: " + certificadoModel.getMensagem());
        /*       
        ExternalContext ec = fc.getExternalContext();

        ec.responseReset(); 
        ec.setResponseContentType("application/x-pkcs12"); 
        //ec.setResponseContentLength(contentLength); 
        ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + certificadoModel.getUsername() + ".p12" + "\""); 

        OutputStream output = ec.getResponseOutputStream();
        keyStore.store(output, certificadoModel.getPassword().toCharArray());
          */
        fc.addMessage("mensagem", new FacesMessage(FacesMessage.SEVERITY_INFO, "Teste", "")); 
        //fc.responseComplete();            
        controlador.clean(certificadoModel);            
    }else           
        fc.addMessage("mensagem", new     FacesMessage(FacesMessage.SEVERITY_ERROR, "Um usuário com o mesmo username já está     cadastrado!", ""));  
        controlador.clean(certificadoModel);
}

My page code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui"> 
    <ui:decorate template="/resources/template/default.xhtml">
        <ui:define name="centro"> 
            <h:form id="cadastro"> 
                <p:panel id="painelCadastro" header="Novo Cadastro" style="margin-bottom:10px;">         
                    <p:messages id="mensagem" autoUpdate="true" closable="true" />   

                    <p:commandButton action="#{certificadoBean.cadastrar}"  ajax="false" value="Cadastrar" update="mensagem" />                   
                    <p:commandButton outcome="homePage" ajax="false" value="Home Page"/>                                  
                </p:panel>       
            </h:form>  
        </ui:define>
    </ui:decorate>
</html>

@BalusC, this is what i did.

xhtml

                <p:commandButton value="Cadastrar" action="#{downloadBean.prepareDownload}" update="mensagem" />
                <p:messages globalOnly="true" />
                <h:outputScript rendered="#{not empty downloadBean.downloadKey}">
                    window.location = '#{request.contextPath}/download?key=#{downloadBean.downloadKey}';
                </h:outputScript>   

                <p:commandButton outcome="homePage" ajax="false" value="Home Page"/>                                  
            </p:panel>       
        </h:form>  

DownloadBean class

public class DownloadBean {

private String downloadKey; 

public void prepareDownload() throws NamingException {
    FacesContext context = FacesContext.getCurrentInstance();

    CertificadoModel certificadoModel = new CertificadoModel();
    CertificadoControlador controlador = new CertificadoControlador();      

    if ((controlador.checkUserIfExist(certificadoModel.getUsername()) == false)) 
    {
        downloadKey = UUID.randomUUID().toString();     
        context.getExternalContext().getSessionMap().put(downloadKey, certificadoModel);
        context.addMessage("mensagem", new FacesMessage(FacesMessage.SEVERITY_INFO, "Usuário cadastrado com sucesso!", "")); 
    }else {
        context.addMessage("mensagem", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Um usuário com o mesmo username já está cadastrado!", ""));  
    }           
}

public String getDownloadKey() {
    return downloadKey;
}

DownloadServlet class

public class DownloadServlet extends HttpServlet {

/****/
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
    String downloadKey = request.getParameter("key");
    CertificadoModel certificadoModel = (CertificadoModel) request.getSession().getAttribute(downloadKey);

    System.out.println("Teste!");

    CertificadoControlador controlador = null;
    try {
        controlador = new CertificadoControlador();
    } catch (NamingException e) {
        e.printStackTrace();
    }
    request.getSession().removeAttribute(downloadKey);

    KeyStore keyStore = null;
    try {
        keyStore = controlador.cadastrar(certificadoModel);
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CADoesntExistsException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }  

    response.reset();
    response.setContentType("application/x-pkcs12"); 
    //response.setContentLength(contentLength); 
    response.setHeader("Content-Disposition", "attachment; filename=\"" + certificadoModel.getUsername() + ".p12" + "\""); 

    try {
        keyStore.store(response.getOutputStream(), certificadoModel.getPassword().toCharArray());
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (IOException e) {           
        e.printStackTrace();
    }
}

And in the web.xml

<servlet>
    <servlet-name>DownloadServlet</servlet-name>
    <servlet-class>br.com.certificado.beans.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>DownloadServlet</servlet-name>
    <url-pattern>/download</url-pattern>
</servlet-mapping>
casperOne
  • 73,706
  • 19
  • 184
  • 253
  • when you say "the process works well" do you mean that the `cadastrar` method completes without throwing an exception and you are getting the expected result? In that case you probably forgot to update the component that is supposed to display the message – gordonk Apr 08 '13 at 17:49
  • Yes, when i said the process works well the method cadastrar complete, in the 2 ways i got no exception, but when i try do uncoment the code to stream the file, the message not grows up, but without the stream, the message grows normaly. And i've the update code on my page. – Marcos Fontana Apr 08 '13 at 18:11

1 Answers1

2

You're basically attempting to return 2 HTTP responses to 1 HTTP request. This is plain impossible.

Your best bet is to conditionally render a JavaScript window.location call on the URL which sends a new HTTP request returning the desired file download. A simple servlet is a very good tool for the job. You can access managed beans in a servlet using one of the ways listed in this answer: Get JSF managed bean by name in any Servlet related class or you can just generate an unique session attribute key and pass it as request parameter.

Here's a kickoff example using the last approach:

<h:form>
    ...
    <p:commandButton ... action="#{bean.prepareDownload}" update="@form" />
    <p:messages globalOnly="true" />
    <h:outputScript rendered="#{not empty bean.downloadKey}">
        window.location = '#{request.contextPath}/download?key=#{bean.downloadKey}';
    </h:outputScript>
</h:form>

(note: /download has to exactly match servlet's URL pattern)

with this bean:

private String downloadKey; // +Getter.

public void prepareDownload() {
    FacesContext context = FacesContext.getCurrentInstance();

    if (canDownload) {
        downloadKey = UUID.randomUUID.toString();
        context.getExternalContext().getSessionMap().put(downloadKey, certificadoModel);
        context.addMessage(null, infoMessage);
    } else {
        context.addMessage(null, errorMessage);
    }
}

and this servlet:

@WebServlet("/download")
public class DownloadServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String downloadKey = request.getParameter("key");
        CertificadoModel certificadoModel = (CertificadoModel) request.getSession().getAttribute(downloadKey);
        request.getSession().removeAttribute(downloadKey);

        // ...

        response.reset();
        response.setContentType("application/x-pkcs12"); 
        response.setContentLength(contentLength); 
        response.setHeader("Content-Disposition", "attachment; filename=\"" + certificadoModel.getUsername() + ".p12" + "\""); 
        keyStore.store(response.getOutputStream(), certificadoModel.getPassword().toCharArray());
    }

}
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Wow, that is very hard, i'm trying to adapt my code on this, and i'm really confused about all of that. I'll try, but thanks for the help. – Marcos Fontana Apr 08 '13 at 19:07
  • I do not understand this part: "#{not empty bean.downloadKey}". – Marcos Fontana Apr 08 '13 at 19:12
  • This means that the script will be rendered if the `downloadKey` property of the bean is not null nor empty. Which thus means that the `canDownload` check in the example has passed. – BalusC Apr 08 '13 at 19:14
  • Hmm, good, another question, the @WebServlet cannot be imported, just have the WebService annotations. – Marcos Fontana Apr 08 '13 at 19:22
  • Apparently you're not targeting a Servlet 3.0 compatible container, but instead an legacy Servlet 2.5 or older one. In that case, just register it the usual way as `` in `web.xml`. See also http://stackoverflow.com/tags/servlets/info – BalusC Apr 08 '13 at 19:39
  • The message worked fine, but i think thats not working in this part window.location = '#{request.ContextPath}/download?key=#{downloadBean.downloadKey}'; – Marcos Fontana Apr 08 '13 at 19:57
  • It must be `#{request.contextPath}` with lowercase `C`. Sorry for typo. It would also be helpful if you just look at HTTP traffic monitor. You should have noticed that it returned a 404 which is much more clear information than "thats not working". – BalusC Apr 08 '13 at 19:59
  • No, returned nothing, just the message on the page, even with the modification. I put a print on the class, and the get is not been called. – Marcos Fontana Apr 08 '13 at 20:18
  • Well, apparently ajax update just went wrong. Maybe you did things differntly from the answer. Hard to tell without seeing the code. Just debugging HTTP response of ajax request should give sufficient insights. – BalusC Apr 08 '13 at 20:40