Validation messages rendered multiple times after upload
blebleskeble Apr 4, 2013 8:29 AMHi. I am facing strange problem with combination of client side validation and file upload.
On my page I have input with client side validation on blur event. When validation fails, message is correctly displayed by rich:messages component. then if I upload file via rich:fileUpload and trigger validation again, message is displayed twice. After next upload three times etc. Can anyone tell me what I am doing wrong? If i submit input via button, server validator is triggered and message is rendered only once regardless on how many files i have uploaded.
(RF 4.2.0, myfaces 2.1.9, tomcat 7.0.30)
here is my page:
<?xml version="1.0" encoding="UTF-8" ?>
<!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:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich">
<h:head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Upload and Messages</title>
</h:head>
<h:body>
    <h:outputScript library="js" name="scripts.js" target="head" />
    <h:form id="myForm">
        <h:inputText id="inp" value="#{upload.inputString}" >
            <f:validator validatorId="requiredValidator"/>
            <rich:validator event="blur" />
        </h:inputText>
        <a4j:commandButton id="button" execute="inp" render="envelope" />
        <br />
        <a4j:outputPanel id="envelope">
            <h:outputText value="#{upload.status}" />
            <br />
            <rich:fileUpload id="upload" fileUploadListener="#{upload.uploadListener}" >
                <a4j:ajax event="uploadcomplete" render="envelope" />
            </rich:fileUpload>
        </a4j:outputPanel>
    </h:form>
    <rich:popupPanel id="messagePopup" left="500" top="20" show="true" modal="false" >
        <rich:messages id="mess" />
    </rich:popupPanel>
</h:body>
</html>
and here my managed bean
package bleble.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.richfaces.event.FileUploadEvent;
@SuppressWarnings("serial")
@ManagedBean(name = "upload")
@ViewScoped
public class UploadController implements Serializable {
    
    private String inputString;
    
    private File f = null;
    private String status = "Waiting for file.";
    
    public UploadController() {
        
    }
    public void uploadListener(final FileUploadEvent event) {
        System.out.println("uploading");
        String filename = event.getUploadedFile().getName();
        try {
            if (filename.contains("\\")) {
                    filename = filename.substring( event.getUploadedFile().getName().lastIndexOf("\\") + 1, event.getUploadedFile().getName().length());
            }
            f = File.createTempFile(filename , "");
            FileOutputStream fos = new FileOutputStream(f);
            FileInputStream fis = (FileInputStream) event.getUploadedFile().getInputStream();
            byte buf[] = new byte[524288];
            int len;
            while ((len = fis.read(buf)) > 0) {
                fos.write(buf, 0, len);
            }
            fos.close();
            fis.close();
        } catch (IOException e1) {
            
        } finally {
            if (f != null) {
                status = "File " + f.getName() + " uploaded.";
            }
        }
    }
    
    public String getStatus() {
        return status;
    }
    public String getInputString() {
        return inputString;
    }
    public void setInputString(final String inputString) {
        this.inputString = inputString;
    }
}
this i my faces validator
package bleble.validator;
import java.io.Serializable;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.faces.application.FacesMessage;
import javax.faces.application.ResourceDependency;
@SuppressWarnings("serial")
@FacesValidator(value = "requiredValidator")
@org.richfaces.javascript.ClientSideScript(function = "validateMandatory", resources = @ResourceDependency(name = "scripts.js", library = "js", target = "head"))
public class RequiredValidator implements Serializable, Validator {
    @Override
    public final void validate(final FacesContext context, final UIComponent component, final Object value) throws ValidatorException {
        FacesMessage message = new FacesMessage();
        message.setDetail("field is mandatory");
        message.setSummary("Validation failed: field is mandatory! (server)");
        message.setSeverity(FacesMessage.SEVERITY_ERROR);
        
        if (value == null || "".equals(value.toString().trim())) {
            throw new ValidatorException(message);
        }
    }
}
and its client implementation in scripts.js
function mymessage(summary, detail, severity){
    this.summary=summary;
    this.detail=detail; 
    this.severity=severity;
}
function validateMandatory(value, label, params, msg) {
    if (jQuery().trim(value) != "") {
        return;
    } else {
        var myMess = new mymessage("Validation failed: field is mandatory! (client)", "field is mandatory", 2);
        throw myMess;
    }
}
all files are also attached in archive
- 
            
                            
            messagesAndUpload.zip 2.5 KB
 
    