/**
* Copyright 2005-2016 hdiv.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hdiv.validators;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.component.html.HtmlInputHidden;
import javax.faces.component.html.HtmlInputSecret;
import javax.faces.component.html.HtmlInputText;
import javax.faces.component.html.HtmlInputTextarea;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hdiv.util.Constants;
import org.hdiv.util.HDIVErrorCodes;
import org.hdiv.util.HDIVUtil;
import org.hdiv.util.MessageFactory;
import org.hdiv.util.UtilsJsf;
import org.hdiv.validation.ValidationContext;
import org.hdiv.validator.EditableDataValidationProvider;
import org.hdiv.validator.EditableDataValidationResult;
/**
* Responsible for validating that the parameters coming from an editable component (InputText, Textarea, Secret) are logical
*
* @author Ugaitz Urien
*/
public class EditableValidator implements ComponentValidator {
private static final Log log = LogFactory.getLog(EditableValidator.class);
/**
* EditableDataValidationProvider
*/
private final EditableDataValidationProvider editableDataValidationProvider;
public EditableValidator(final EditableDataValidationProvider editableDataValidationProvider) {
this.editableDataValidationProvider = editableDataValidationProvider;
}
public boolean supports(final UIComponent component) {
return UIInput.class.isAssignableFrom(component.getClass()) && component.getFamily().equals("javax.faces.Input");
}
public void validate(final ValidationContext context, final UIComponent component) {
validateInput(context, (UIInput) component);
}
/**
* Configures variables to call validateContent
*
* @param validationContext Validation context
* @param inputComponent {@link UIInput} to validate
*/
protected void validateInput(final ValidationContext validationContext, final UIInput inputComponent) {
FacesContext context = validationContext.getFacesContext();
String clientId = inputComponent.getClientId(context);
String contentType = null;
if (inputComponent instanceof HtmlInputHidden) {
contentType = "hidden";
}
else if (inputComponent instanceof HtmlInputTextarea) {
contentType = "textarea";
}
else if (inputComponent instanceof HtmlInputText) {
contentType = "text";
}
else if (inputComponent instanceof HtmlInputSecret) {
contentType = "password";
}
List<String> parameters = getSubmittedClientId(validationContext, clientId);
for (String param : parameters) {
Object val = context.getExternalContext().getRequestParameterMap().get(param);
String value = null;
if (val == null) {
return;
}
else {
value = val.toString();
}
validateParameter(validationContext, inputComponent, contentType, param, value);
}
}
/**
* Get submitted parameters for this component.
* @param context Validation context
* @param clientId component client id
* @return client id
*/
protected List<String> getSubmittedClientId(final ValidationContext context, final String clientId) {
List<String> params = context.getParamsWithRowId().get(clientId);
if (params != null && params.size() > 0) {
return params;
}
return Collections.singletonList(clientId);
}
/**
* Validate a parameter.
* @param validationContext Validation context
* @param inputComponent Component to validate
* @param contentType Component type
* @param paramName the name of the component to validate
* @param paramValue the value of the parameter
*/
protected void validateParameter(final ValidationContext validationContext, final UIInput inputComponent, final String contentType,
final String paramName, final String paramValue) {
FacesContext context = validationContext.getFacesContext();
validationContext.acceptParameter(paramName, paramValue);
EditableDataValidationResult result = validateContent(context, paramName, paramValue, contentType);
if (!result.isValid()) {
// Add message
FacesMessage msg = createFacesMessage(context, inputComponent);
context.addMessage(paramName, msg);
// We can't do this in RestoreState phase. Store the component and do it later.
// inputComponent.setValid(false);
if (log.isDebugEnabled()) {
log.debug("Parameter '" + paramName + "' rejected in component '" + inputComponent.getClientId()
+ "' in ComponentValidator '" + this.getClass() + "'");
}
validationContext.rejectParameter(paramName, paramValue, HDIVErrorCodes.INVALID_EDITABLE_VALUE, result.getValidationId(),
inputComponent);
}
}
/**
* Uses HdivConfig to validate editable field content
*
* @param context Request context
* @param clientId clientId value of the component
* @param contentObj value of the component
* @param contentType type of content
* @return is the content valid?
*/
protected EditableDataValidationResult validateContent(final FacesContext context, final String clientId, final Object contentObj,
final String contentType) {
if (!(contentObj instanceof String)) {
return EditableDataValidationResult.VALIDATION_NOT_REQUIRED;
}
String target = UtilsJsf.getTargetUrl(context);
String[] content = { (String) contentObj };
EditableDataValidationResult result = editableDataValidationProvider.validate(target, clientId, content, contentType);
return result;
}
/**
* Create {@link FacesMessage} for error
*
* @param context Request context
* @param inputComponent {@link UIInput} to validate
* @return FacesMessage
*/
protected FacesMessage createFacesMessage(final FacesContext context, final UIInput inputComponent) {
String clientId = inputComponent.getClientId(context);
String label = null;
if (inputComponent instanceof HtmlInputTextarea) {
label = ((HtmlInputTextarea) inputComponent).getLabel();
}
else if (inputComponent instanceof HtmlInputText) {
label = ((HtmlInputText) inputComponent).getLabel();
}
else if (inputComponent instanceof HtmlInputSecret) {
label = ((HtmlInputSecret) inputComponent).getLabel();
}
label = label != null ? label : clientId;
// First, use component own message
String msg = inputComponent.getValidatorMessage();
if (msg == null) {
// Search in JSF resource bundle
Object[] params = { label };
FacesMessage facesMessage = MessageFactory.getMessage(Constants.HDIV_EDITABLE_ERROR_KEY, params);
if (facesMessage != null) {
return facesMessage;
}
}
if (msg == null) {
// Use Hdiv core message
Locale locale = context.getViewRoot().getLocale();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
msg = HDIVUtil.getMessage(request, Constants.HDIV_EDITABLE_ERROR_KEY, label, locale);
}
FacesMessage facesMessage = new FacesMessage(msg);
facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
return facesMessage;
}
}