You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CompositeValidator.java 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.itmill.toolkit.data.validator;
  5. import java.util.Collection;
  6. import java.util.HashSet;
  7. import java.util.Iterator;
  8. import java.util.LinkedList;
  9. import com.itmill.toolkit.data.Validator;
  10. /**
  11. * The <code>CompositeValidator</code> allows you to chain (compose) many
  12. * validators to validate one field. The contained validators may be required to
  13. * all validate the value to validate or it may be enough that one contained
  14. * validator validates the value. This behaviour is controlled by the modes
  15. * <code>AND</code> and <code>OR</code>.
  16. *
  17. * @author IT Mill Ltd.
  18. * @version
  19. * @VERSION@
  20. * @since 3.0
  21. */
  22. public class CompositeValidator implements Validator {
  23. /**
  24. * The validators are combined with <code>AND</code> clause: validity of
  25. * the composite implies validity of the all validators it is composed of
  26. * must be valid.
  27. */
  28. public static final int MODE_AND = 0;
  29. /**
  30. * The validators are combined with <code>OR</code> clause: validity of
  31. * the composite implies that some of validators it is composed of must be
  32. * valid.
  33. */
  34. public static final int MODE_OR = 1;
  35. /**
  36. * The validators are combined with and clause: validity of the composite
  37. * implies validity of the all validators it is composed of
  38. */
  39. public static final int MODE_DEFAULT = MODE_AND;
  40. /**
  41. * Operation mode.
  42. */
  43. private int mode = MODE_DEFAULT;
  44. /**
  45. * List of contained validators.
  46. */
  47. private final LinkedList validators = new LinkedList();
  48. /**
  49. * Error message.
  50. */
  51. private String errorMessage;
  52. /**
  53. * Construct a composite validator in <code>AND</code> mode without error
  54. * message.
  55. */
  56. public CompositeValidator() {
  57. }
  58. /**
  59. * Constructs a composite validator in given mode.
  60. */
  61. public CompositeValidator(int mode, String errorMessage) {
  62. setMode(mode);
  63. setErrorMessage(errorMessage);
  64. }
  65. /**
  66. * Validates the given value.
  67. * <p>
  68. * The value is valid, if:
  69. * <ul>
  70. * <li><code>MODE_AND</code>: All of the sub-validators are valid
  71. * <li><code>MODE_OR</code>: Any of the sub-validators are valid
  72. * </ul>
  73. *
  74. * If the value is invalid, validation error is thrown. If the error message
  75. * is set (non-null), it is used. If the error message has not been set, the
  76. * first error occurred is thrown.
  77. * </p>
  78. *
  79. * @param value
  80. * the value to check.
  81. * @throws Validator.InvalidValueException
  82. * if the value is not valid.
  83. */
  84. public void validate(Object value) throws Validator.InvalidValueException {
  85. switch (mode) {
  86. case MODE_AND:
  87. for (final Iterator i = validators.iterator(); i.hasNext();) {
  88. ((Validator) i.next()).validate(value);
  89. }
  90. return;
  91. case MODE_OR:
  92. Validator.InvalidValueException first = null;
  93. for (final Iterator i = validators.iterator(); i.hasNext();) {
  94. try {
  95. ((Validator) i.next()).validate(value);
  96. return;
  97. } catch (final Validator.InvalidValueException e) {
  98. if (first == null) {
  99. first = e;
  100. }
  101. }
  102. }
  103. if (first == null) {
  104. return;
  105. }
  106. final String em = getErrorMessage();
  107. if (em != null) {
  108. throw new Validator.InvalidValueException(em);
  109. } else {
  110. throw first;
  111. }
  112. }
  113. throw new IllegalStateException(
  114. "The validator is in unsupported operation mode");
  115. }
  116. /**
  117. * Checks the validity of the the given value. The value is valid, if:
  118. * <ul>
  119. * <li><code>MODE_AND</code>: All of the sub-validators are valid
  120. * <li><code>MODE_OR</code>: Any of the sub-validators are valid
  121. * </ul>
  122. *
  123. * @param value
  124. * the value to check.
  125. */
  126. public boolean isValid(Object value) {
  127. switch (mode) {
  128. case MODE_AND:
  129. for (final Iterator i = validators.iterator(); i.hasNext();) {
  130. final Validator v = (Validator) i.next();
  131. if (!v.isValid(value)) {
  132. return false;
  133. }
  134. }
  135. return true;
  136. case MODE_OR:
  137. for (final Iterator i = validators.iterator(); i.hasNext();) {
  138. final Validator v = (Validator) i.next();
  139. if (v.isValid(value)) {
  140. return true;
  141. }
  142. }
  143. return false;
  144. }
  145. throw new IllegalStateException(
  146. "The valitor is in unsupported operation mode");
  147. }
  148. /**
  149. * Gets the mode of the validator.
  150. *
  151. * @return Operation mode of the validator: <code>MODE_AND</code> or
  152. * <code>MODE_OR</code>.
  153. */
  154. public final int getMode() {
  155. return mode;
  156. }
  157. /**
  158. * Sets the mode of the validator. The valid modes are:
  159. * <ul>
  160. * <li><code>MODE_AND</code> (default)
  161. * <li><code>MODE_OR</code>
  162. * </ul>
  163. *
  164. * @param mode
  165. * the mode to set.
  166. */
  167. public void setMode(int mode) {
  168. if (mode != MODE_AND && mode != MODE_OR) {
  169. throw new IllegalArgumentException("Mode " + mode + " unsupported");
  170. }
  171. this.mode = mode;
  172. }
  173. /**
  174. * Gets the error message for the composite validator. If the error message
  175. * is null, original error messages of the sub-validators are used instead.
  176. */
  177. public String getErrorMessage() {
  178. if (errorMessage != null) {
  179. return errorMessage;
  180. }
  181. // TODO Return composite error message
  182. return null;
  183. }
  184. /**
  185. * Sets the error message for the composite validator. If the error message
  186. * is null, original error messages of the sub-validators are used instead.
  187. *
  188. * @param errorMessage
  189. * the Error Message to set.
  190. */
  191. public void setErrorMessage(String errorMessage) {
  192. this.errorMessage = errorMessage;
  193. }
  194. /**
  195. * Adds validator to the interface.
  196. *
  197. * @param validator
  198. * the Validator object which performs validation checks on
  199. * this set of data field values.
  200. */
  201. public void addValidator(Validator validator) {
  202. if (validator == null) {
  203. return;
  204. }
  205. validators.add(validator);
  206. }
  207. /**
  208. * Removes a validator from the composite.
  209. *
  210. * @param validator
  211. * the Validator object which performs validation checks on
  212. * this set of data field values.
  213. */
  214. public void removeValidator(Validator validator) {
  215. validators.remove(validator);
  216. }
  217. /**
  218. * Gets sub-validators by class.
  219. *
  220. * <p>
  221. * If the component contains directly or recursively (it contains another
  222. * composite containing the validator) validators compatible with given type
  223. * they are returned. This only applies to <code>AND</code> mode composite
  224. * validators.
  225. * </p>
  226. *
  227. * <p>
  228. * If the validator is in <code>OR</code> mode or does not contain any
  229. * validators of given type null is returned.
  230. * </p>
  231. *
  232. * @return Collection of validators compatible with given type that must
  233. * apply or null if none fould.
  234. */
  235. public Collection getSubValidators(Class validatorType) {
  236. if (mode != MODE_AND) {
  237. return null;
  238. }
  239. final HashSet found = new HashSet();
  240. for (final Iterator i = validators.iterator(); i.hasNext();) {
  241. final Validator v = (Validator) i.next();
  242. if (validatorType.isAssignableFrom(v.getClass())) {
  243. found.add(v);
  244. }
  245. if (v instanceof CompositeValidator
  246. && ((CompositeValidator) v).getMode() == MODE_AND) {
  247. final Collection c = ((CompositeValidator) v)
  248. .getSubValidators(validatorType);
  249. if (c != null) {
  250. found.addAll(c);
  251. }
  252. }
  253. }
  254. return found.isEmpty() ? null : found;
  255. }
  256. }