/**
* 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.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.component.UIParameter;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialViewContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hdiv.components.UIParameterExtension;
import org.hdiv.util.HDIVErrorCodes;
import org.hdiv.validation.ValidationContext;
/**
* ComponentValidator that validates parameters of a component of type UICommand,
*
* @author Gotzon Illarramendi
*/
public class UICommandValidator extends AbstractComponentValidator {
private static final Log log = LogFactory.getLog(UICommandValidator.class);
public UICommandValidator() {
super(UICommand.class);
}
public void validate(final ValidationContext validationContext, final UIComponent component) {
UICommand command = (UICommand) component;
Clicked clicked = wasClicked(validationContext, command);
if (!clicked.isClicked()) {
// Only validate the executed command
return;
}
validateUICommand(validationContext, command, clicked);
}
// TODO add myfaces support, the parameter is different
protected Clicked wasClicked(final ValidationContext context, final UICommand command) {
String clientId = command.getClientId(context.getFacesContext());
String value = context.getFacesContext().getExternalContext().getRequestParameterMap().get(clientId);
if (value != null && (value.equals(clientId) || value.equals(command.getValue()))) {
return new Clicked(true, clientId);
}
Clicked clicked = wasComponentWithRowIdClicked(context, command, clientId);
if (clicked.isClicked()) {
return clicked;
}
PartialViewContext partialContext = context.getFacesContext().getPartialViewContext();
if (partialContext != null && partialContext.isPartialRequest()) {
// Is an ajax call partially processing the component tree
Collection<String> execIds = partialContext.getExecuteIds();
return new Clicked(execIds.contains(clientId));
}
return new Clicked(false);
}
/**
* If the UICommand component is inside a UIData component can have an index in the name. <br>
* For example: form:pets:1:button
* @param context validation context
* @param command {@link UICommand} instance
* @param clientId client id
* @return was this component clicked?
*/
protected Clicked wasComponentWithRowIdClicked(final ValidationContext context, final UICommand command, final String clientId) {
Map<String, List<String>> paramsWithRowId = context.getParamsWithRowId();
if (paramsWithRowId.containsKey(clientId)) {
List<String> params = paramsWithRowId.get(clientId);
if (params.size() == 1) {
String param = params.get(0);
if (context.getRequestParameters().containsKey(param) && context.getRequestParameters().get(param).equals(param)) {
return new Clicked(true, param);
}
}
}
return new Clicked(false);
}
protected void validateUICommand(final ValidationContext validationContext, final UICommand command, final Clicked clicked) {
validationContext.acceptParameter(command.getClientId(validationContext.getFacesContext()), command.getValue());
if (clicked.getParamName() != null) {
validationContext.acceptParameter(clicked.getParamName(),
validationContext.getFacesContext().getExternalContext().getRequestParameterMap().get(clicked.getParamName()));
}
// Check CommandLink's parameters
for (UIComponent childComp : command.getChildren()) {
if (childComp instanceof UIParameter) {
UIParameter param = (UIParameter) childComp;
processParam(validationContext, param, clicked);
}
}
}
/**
* Validates a parameter of component UICommand
*
* @param context Request context
* @param parameter UIParameter component to validate
* @return validation result
*/
private void processParam(final ValidationContext validationContext, final UIParameter parameter, final Clicked clicked) {
FacesContext context = validationContext.getFacesContext();
UIParameterExtension param = (UIParameterExtension) parameter;
Map<String, String> requestMap = context.getExternalContext().getRequestParameterMap();
String requestValue = requestMap.get(param.getName());
Collection<Object> stateValues = param.getStateValue(context, clicked.getParamName());
if (log.isDebugEnabled()) {
log.debug("UIParameter requestValue:" + requestValue);
log.debug("UIParameter stateValues:" + stateValues);
}
if (requestValue != null && isCorrectValue(requestValue, stateValues)) {
validationContext.acceptParameter(param.getName(), requestValue);
}
else if (requestValue == null) {
if (log.isDebugEnabled()) {
log.debug("Parameter '" + param.getName() + "' rejected in component '" + param.getClientId(context)
+ "' in ComponentValidator '" + this.getClass() + "'");
}
validationContext.rejectParameter(param.getName(), requestValue, HDIVErrorCodes.NOT_RECEIVED_ALL_REQUIRED_PARAMETERS);
}
else {
if (log.isDebugEnabled()) {
log.debug("Parameter '" + param.getName() + "' rejected in component '" + param.getClientId(context)
+ "' in ComponentValidator '" + this.getClass() + "'");
}
validationContext.rejectParameter(param.getName(), requestValue, HDIVErrorCodes.INVALID_PARAMETER_VALUE);
}
}
protected boolean isCorrectValue(final String requestValue, final Collection<Object> stateValues) {
Iterator<Object> it = stateValues.iterator();
while (it.hasNext()) {
Object value = it.next();
if (value != null) {
if (value.toString().equals(requestValue)) {
return true;
}
}
}
return false;
}
public static class Clicked {
private final boolean clicked;
private final String paramName;
public Clicked(final boolean clicked) {
this.clicked = clicked;
paramName = null;
}
public Clicked(final boolean clicked, final String paramName) {
this.clicked = clicked;
this.paramName = paramName;
}
public boolean isClicked() {
return clicked;
}
public String getParamName() {
return paramName;
}
}
}