/*
* Copyright 2000-2016 Vaadin Ltd.
*
* 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 com.vaadin.v7.data.validator;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import com.vaadin.data.Binder;
import com.vaadin.data.HasValue;
import com.vaadin.v7.data.Validator;
/**
* The <code>CompositeValidator</code> allows you to chain (compose) many
* validators to validate one field. The contained validators may be required to
* all validate the value to validate or it may be enough that one contained
* validator validates the value. This behaviour is controlled by the modes
* <code>AND</code> and <code>OR</code>.
*
* @author Vaadin Ltd.
* @since 3.0
*
* @deprecated As of 8.0, no direct replacement available. See {@link Binder#forField(HasValue)} and various methods for
* validation and conversion chaining: {@code withValidator(...)}, {@code withConverter(...)},
* {@code withNullRepresentation(...)}
*/
@SuppressWarnings("serial")
@Deprecated
public class CompositeValidator implements Validator {
@Deprecated
public enum CombinationMode {
/**
* The validators are combined with <code>AND</code> clause: validity of
* the composite implies validity of the all validators it is composed
* of must be valid.
*/
AND,
/**
* The validators are combined with <code>OR</code> clause: validity of
* the composite implies that some of validators it is composed of must
* be valid.
*/
OR;
}
/**
* @deprecated As of 7.0, use {@link CombinationMode#AND} instead
*/
@Deprecated
public static final CombinationMode MODE_AND = CombinationMode.AND;
/**
* @deprecated As of 7.0, use {@link CombinationMode#OR} instead
*/
@Deprecated
public static final CombinationMode MODE_OR = CombinationMode.OR;
private String errorMessage;
/**
* Operation mode.
*/
private CombinationMode mode = CombinationMode.AND;
/**
* List of contained validators.
*/
private final List<Validator> validators = new LinkedList<Validator>();
/**
* Construct a composite validator in <code>AND</code> mode without error
* message.
*/
public CompositeValidator() {
this(CombinationMode.AND, "");
}
/**
* Constructs a composite validator in given mode.
*
* @param mode
* @param errorMessage
*/
public CompositeValidator(CombinationMode mode, String errorMessage) {
setErrorMessage(errorMessage);
setMode(mode);
}
/**
* Validates the given value.
* <p>
* The value is valid, if:
* <ul>
* <li><code>MODE_AND</code>: All of the sub-validators are valid
* <li><code>MODE_OR</code>: Any of the sub-validators are valid
* </ul>
*
* If the value is invalid, validation error is thrown. If the error message
* is set (non-null), it is used. If the error message has not been set, the
* first error occurred is thrown.
* </p>
*
* @param value
* the value to check.
* @throws Validator.InvalidValueException
* if the value is not valid.
*/
@Override
public void validate(Object value) throws Validator.InvalidValueException {
switch (mode) {
case AND:
for (Validator validator : validators) {
validator.validate(value);
}
return;
case OR:
Validator.InvalidValueException first = null;
for (Validator v : validators) {
try {
v.validate(value);
return;
} catch (final Validator.InvalidValueException e) {
if (first == null) {
first = e;
}
}
}
if (first == null) {
return;
}
final String em = getErrorMessage();
if (em != null) {
throw new Validator.InvalidValueException(em);
} else {
throw first;
}
}
}
/**
* Gets the mode of the validator.
*
* @return Operation mode of the validator: {@link CombinationMode#AND} or
* {@link CombinationMode#OR}.
*/
public final CombinationMode getMode() {
return mode;
}
/**
* Sets the mode of the validator. The valid modes are:
* <ul>
* <li>{@link CombinationMode#AND} (default)
* <li>{@link CombinationMode#OR}
* </ul>
*
* @param mode
* the mode to set.
*/
public void setMode(CombinationMode mode) {
if (mode == null) {
throw new IllegalArgumentException(
"The validator can't be set to null");
}
this.mode = mode;
}
/**
* Gets the error message for the composite validator. If the error message
* is null, original error messages of the sub-validators are used instead.
*/
public String getErrorMessage() {
if (errorMessage != null) {
return errorMessage;
}
// TODO Return composite error message
return null;
}
/**
* Adds validator to the interface.
*
* @param validator
* the Validator object which performs validation checks on this
* set of data field values.
*/
public void addValidator(Validator validator) {
if (validator == null) {
return;
}
validators.add(validator);
}
/**
* Removes a validator from the composite.
*
* @param validator
* the Validator object which performs validation checks on this
* set of data field values.
*/
public void removeValidator(Validator validator) {
validators.remove(validator);
}
/**
* Gets sub-validators by class.
*
* <p>
* If the component contains directly or recursively (it contains another
* composite containing the validator) validators compatible with given type
* they are returned. This only applies to <code>AND</code> mode composite
* validators.
* </p>
*
* <p>
* If the validator is in <code>OR</code> mode or does not contain any
* validators of given type null is returned.
* </p>
*
* @param validatorType
* The type of validators to return
*
* @return Collection<Validator> of validators compatible with given type
* that must apply or null if none found.
*/
public Collection<Validator> getSubValidators(Class validatorType) {
if (mode != CombinationMode.AND) {
return null;
}
final HashSet<Validator> found = new HashSet<Validator>();
for (Validator v : validators) {
if (validatorType.isAssignableFrom(v.getClass())) {
found.add(v);
}
if (v instanceof CompositeValidator
&& ((CompositeValidator) v).getMode() == MODE_AND) {
final Collection<Validator> c = ((CompositeValidator) v)
.getSubValidators(validatorType);
if (c != null) {
found.addAll(c);
}
}
}
return found.isEmpty() ? null : found;
}
/**
* Sets the message to be included in the exception in case the value does
* not validate. The exception message is typically shown to the end user.
*
* @param errorMessage
* the error message.
*/
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}