001: /* *************************************************************************
002:
003: Millstone(TM)
004: Open Sourced User Interface Library for
005: Internet Development with Java
006:
007: Millstone is a registered trademark of IT Mill Ltd
008: Copyright (C) 2000-2005 IT Mill Ltd
009:
010: *************************************************************************
011:
012: This library is free software; you can redistribute it and/or
013: modify it under the terms of the GNU Lesser General Public
014: license version 2.1 as published by the Free Software Foundation.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: *************************************************************************
026:
027: For more information, contact:
028:
029: IT Mill Ltd phone: +358 2 4802 7180
030: Ruukinkatu 2-4 fax: +358 2 4802 7181
031: 20540, Turku email: info@itmill.com
032: Finland company www: www.itmill.com
033:
034: Primary source for MillStone information and releases: www.millstone.org
035:
036: ********************************************************************** */
037:
038: package org.millstone.base.data.validator;
039:
040: import java.util.Collection;
041: import java.util.HashSet;
042: import java.util.Iterator;
043: import java.util.LinkedList;
044:
045: import org.millstone.base.data.*;
046:
047: /** Composite validator.
048: *
049: * This validator allows you to chain (compose) many validators
050: * to validate one field. The contained validators may be required
051: * to all validate the value to validate or it may be enough that
052: * one contained validator validates the value. This behaviour is
053: * controlled by the modes AND and OR.
054: *
055: * @author IT Mill Ltd.
056: * @version 3.1.1
057: * @since 3.0
058: */
059: public class CompositeValidator implements Validator {
060:
061: /** The validators are combined with AND clause: validity of the
062: * composite implies validity of the all validators it is composed of
063: * must be valid.
064: */
065: public static final int MODE_AND = 0;
066:
067: /** The validators are combined with OR clause: validity of the
068: * composite implies that some of validators it is composed of
069: * must be valid.
070: */
071: public static final int MODE_OR = 1;
072:
073: /** The validators are combined with and clause: validity of the
074: * composite implies validity of the all validators it is composed of
075: */
076: public static final int MODE_DEFAULT = MODE_AND;
077:
078: /** Operation mode */
079: private int mode = MODE_DEFAULT;
080:
081: /** List of contained validators */
082: private LinkedList validators = new LinkedList();
083:
084: /** Error message */
085: private String errorMessage;
086:
087: /** Construct composite validator in AND mode without error message */
088: public CompositeValidator() {
089: }
090:
091: /** Construct composite validator in given mode */
092: public CompositeValidator(int mode, String errorMessage) {
093: setMode(mode);
094: setErrorMessage(errorMessage);
095: }
096:
097: /** Validate the the given value.
098: * The value is valid, if:
099: * <ul>
100: * <li><code>MODE_AND</code>: All of the sub-validators are valid
101: * <li><code>MODE_OR</code>: Any of the sub-validators are valid
102: * </ul>
103: *
104: * If the value is invalid, validation error is thrown. If the
105: * error message is set (non-null), it is used. If the error message
106: * has not been set, the first error occurred is thrown.
107: */
108: public void validate(Object value)
109: throws Validator.InvalidValueException {
110: switch (mode) {
111: case MODE_AND:
112: for (Iterator i = validators.iterator(); i.hasNext();)
113: ((Validator) i.next()).validate(value);
114: return;
115:
116: case MODE_OR:
117: Validator.InvalidValueException first = null;
118: for (Iterator i = validators.iterator(); i.hasNext();)
119: try {
120: ((Validator) i.next()).validate(value);
121: return;
122: } catch (Validator.InvalidValueException e) {
123: if (first == null)
124: first = e;
125: }
126: if (first == null)
127: return;
128: String em = getErrorMessage();
129: if (em != null)
130: throw new Validator.InvalidValueException(em);
131: else
132: throw first;
133: }
134: throw new IllegalStateException(
135: "The valitor is in unsupported operation mode");
136: }
137:
138: /** Check the validity of the the given value.
139: * The value is valid, if:
140: * <ul>
141: * <li><code>MODE_AND</code>: All of the sub-validators are valid
142: * <li><code>MODE_OR</code>: Any of the sub-validators are valid
143: * </ul>
144: */
145: public boolean isValid(Object value) {
146: switch (mode) {
147: case MODE_AND:
148: for (Iterator i = validators.iterator(); i.hasNext();) {
149: Validator v = (Validator) i.next();
150: if (!v.isValid(value))
151: return false;
152: }
153: return true;
154:
155: case MODE_OR:
156: for (Iterator i = validators.iterator(); i.hasNext();) {
157: Validator v = (Validator) i.next();
158: if (v.isValid(value))
159: return true;
160: }
161: return false;
162: }
163: throw new IllegalStateException(
164: "The valitor is in unsupported operation mode");
165: }
166:
167: /** Get the mode of the validator.
168: * @return Operation mode of the validator:
169: * <code>MODE_AND</code> or <code>MODE_OR</code>.
170: */
171: public final int getMode() {
172: return mode;
173: }
174:
175: /** Set the mode of the validator. The valid modes are:
176: * <ul>
177: * <li><code>MODE_AND</code> (default)
178: * <li><code>MODE_OR</code>
179: * </ul>
180: */
181: public void setMode(int mode) {
182: if (mode != MODE_AND && mode != MODE_OR)
183: throw new IllegalArgumentException("Mode " + mode
184: + " unsupported");
185: this .mode = mode;
186: }
187:
188: /** Get the error message for the composite validator.
189: * If the error message is null, original error messages of the
190: * sub-validators are used instead.
191: */
192: public String getErrorMessage() {
193: return null;
194: }
195:
196: /** Set the error message for the composite validator.
197: * If the error message is null, original error messages of the
198: * sub-validators are used instead.
199: */
200: public void setErrorMessage(String errorMessage) {
201: this .errorMessage = errorMessage;
202: }
203:
204: /** Add validator to the interface */
205: public void addValidator(Validator validator) {
206: if (validator == null)
207: return;
208: validators.add(validator);
209: }
210:
211: /** Remove a validator from the composite */
212: public void removeValidator(Validator validator) {
213: validators.remove(validator);
214: }
215:
216: /** Get sub-validators by class.
217: *
218: * <p>If the component contains
219: * directly or recursively (it contains another composite
220: * containing the validator) validators compatible with given type they
221: * are returned. This only applies to AND mode composite
222: * validators.</p>
223: *
224: * <p>If the validator is in OR mode or does not contain any
225: * validators of given type null is returned. </p>
226: *
227: * @return Collection of validators compatible with given type that
228: * must apply or null if none fould.
229: */
230: public Collection getSubValidators(Class validatorType) {
231: if (mode != MODE_AND)
232: return null;
233:
234: HashSet found = new HashSet();
235: for (Iterator i = validators.iterator(); i.hasNext();) {
236: Validator v = (Validator) i.next();
237: if (validatorType.isAssignableFrom(v.getClass()))
238: found.add(v);
239: if (v instanceof CompositeValidator
240: && ((CompositeValidator) v).getMode() == MODE_AND) {
241: Collection c = ((CompositeValidator) v)
242: .getSubValidators(validatorType);
243: if (c != null)
244: found.addAll(c);
245: }
246: }
247:
248: return found.isEmpty() ? null : found;
249: }
250:
251: }
|