/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.core.gui.validator;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.StateHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.DoubleRangeValidator;
import javax.faces.validator.LengthValidator;
import javax.faces.validator.LongRangeValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple;
import org.rhq.core.domain.configuration.definition.constraint.Constraint;
import org.rhq.core.domain.configuration.definition.constraint.FloatRangeConstraint;
import org.rhq.core.domain.configuration.definition.constraint.IntegerRangeConstraint;
import org.rhq.core.domain.configuration.definition.constraint.RegexConstraint;
import org.rhq.core.gui.util.FacesComponentUtility;
import org.rhq.core.gui.util.FacesContextUtility;
import org.rhq.core.gui.configuration.ConfigRenderer;
/**
* A JSF validator that validates a String, which represents the value of a JON simple property (i.e.
* {@link PropertySimple}). A definition for the simple property {@link PropertyDefinitionSimple} can optionally be
* specified when this validator is instantiated. If a definition was specified, the value will be validated against the
* definition's type (i.e. {@link org.rhq.core.domain.configuration.definition.PropertySimpleType}) and any constraints
* (i.e. {@link Constraint}s) included in the definition.
*
* @author Ian Springer
*/
public class PropertySimpleValueValidator implements Validator, StateHolder {
private static final String INPUT_ERROR_STYLE_CLASS = "inputerror";
private PropertyDefinitionSimple propertyDefinition;
private boolean transientValue;
// A public no-arg constructor is required by the JSF spec.
public PropertySimpleValueValidator() {
}
public PropertySimpleValueValidator(@Nullable
PropertyDefinitionSimple propertyDefinition) {
this.propertyDefinition = propertyDefinition;
}
public void validate(FacesContext facesContext, UIComponent component, Object value) throws ValidatorException {
String stringValue = (String) value;
String refresh = FacesContextUtility.getOptionalRequestParameter("refresh");
if (refresh != null && refresh.equals(ConfigRenderer.PROPERTY_SET_COMPONENT_ID))
return;
// An optional property with a null value is always valid.
if (!this.propertyDefinition.isRequired() && value == null)
return;
// Don't validate if it's not being updated.
if (!FacesComponentUtility.isOverride(component))
return;
List<Validator> subValidators = createSubValidators();
for (Validator subValidator : subValidators) {
try {
subValidator.validate(facesContext, component, stringValue);
}
catch (ValidatorException e) {
component.getAttributes().put("styleClass", INPUT_ERROR_STYLE_CLASS);
if (" ".equals(stringValue)) {
((UIInput)component).setSubmittedValue("");
}
throw e;
}
}
}
private List<Validator> createSubValidators() {
List<Validator> subValidators = new ArrayList<Validator>();
subValidators.add(new LengthValidator(PropertySimple.MAX_VALUE_LENGTH));
if (this.propertyDefinition != null) {
switch (this.propertyDefinition.getType()) {
case INTEGER: {
subValidators.add(new LongRangeValidator(Integer.MAX_VALUE, Integer.MIN_VALUE));
break;
}
case LONG: {
subValidators.add(new LongRangeValidator(Long.MAX_VALUE, Long.MIN_VALUE));
break;
}
case FLOAT: {
subValidators.add(new DoubleRangeValidator(Float.MAX_VALUE, Float.MIN_VALUE));
break;
}
case DOUBLE: {
subValidators.add(new DoubleRangeValidator(Double.MAX_VALUE, Double.MIN_VALUE));
break;
// There is no need for type-based validators for booleans or enums, because the UI input controls
// (e.g. radio buttons or pulldown menus) prevent invalid values from being entered.
}
}
for (Constraint constraint : this.propertyDefinition.getConstraints()) {
subValidators.add(createValidator(constraint));
}
}
return subValidators;
}
@NotNull
public static Validator createValidator(Constraint constraint) {
Validator validator;
if (constraint instanceof IntegerRangeConstraint) {
IntegerRangeConstraint integerRangeConstraint = (IntegerRangeConstraint) constraint;
LongRangeValidator longRangeValidator = new LongRangeValidator();
Long minValue = integerRangeConstraint.getMinimum();
if (minValue != null) {
longRangeValidator.setMinimum(minValue);
}
Long maxValue = integerRangeConstraint.getMaximum();
if (maxValue != null) {
longRangeValidator.setMaximum(maxValue);
}
validator = longRangeValidator;
} else if (constraint instanceof FloatRangeConstraint) {
FloatRangeConstraint floatRangeConstraint = (FloatRangeConstraint) constraint;
DoubleRangeValidator doubleRangeValidator = new DoubleRangeValidator();
Double minValue = floatRangeConstraint.getMinimum();
if (minValue != null) {
doubleRangeValidator.setMinimum(minValue);
}
Double maxValue = floatRangeConstraint.getMaximum();
if (maxValue != null) {
doubleRangeValidator.setMaximum(maxValue);
}
validator = doubleRangeValidator;
} else if (constraint instanceof RegexConstraint) {
RegexConstraint regexConstraint = (RegexConstraint) constraint;
validator = new RegexValidator(regexConstraint.getDetails());
} else {
throw new IllegalArgumentException("Unknown constraint type: " + constraint.getClass().getName());
}
return validator;
}
public void restoreState(FacesContext facesContext, Object state) {
Object[] values = (Object[]) state;
this.propertyDefinition = (PropertyDefinitionSimple) values[0];
}
public Object saveState(FacesContext facesContext) {
Object[] values = new Object[1];
values[0] = this.propertyDefinition;
return (values);
}
public boolean isTransient() {
return transientValue;
}
public void setTransient(boolean transientValue) {
this.transientValue = transientValue;
}
}