001: package net.xoetrope.xui.validation;
002:
003: import java.lang.reflect.Method;
004: import java.util.Enumeration;
005: import java.util.Hashtable;
006: import java.util.Vector;
007:
008: import java.awt.Component;
009: import java.awt.Container;
010: import java.awt.event.FocusEvent;
011:
012: import net.xoetrope.debug.DebugLogger;
013: import net.xoetrope.xui.XEventHandler;
014: import net.xoetrope.xui.build.BuildProperties;
015:
016: /**
017: * <p>Provides a means of managing validations. This class is
018: * intended as a mixin class for the panel classes such as XPage. Validations
019: * are integrated with the event handler so that when the event with which the
020: * validation is associated is triggered the validation is invoked. Failure of
021: * a validation results in subsequent event handler methods being blocked.</p>
022: * <p>Validations are also invoked at page transition and all validations rules
023: * are checked. If all validations are not passed then the page transition
024: * can be blocked.</p><p>If a validation failes then an exception is thrown.
025: * The exception is by default handled by this class but it can be redirected to
026: * a custom exception handler with the setExceptionHandler method. This interface
027: * allows exceptions to handled in a variety of different ways.</p>
028: * <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003<br>
029: * License: see license.txt
030: * $Revision: 1.6 $
031: */
032: public class XValidationHandler implements XValidationExceptionHandler {
033: protected XValidationFactory validationFactory;
034: protected Hashtable validations;
035: protected XValidationExceptionHandler exceptionHandler;
036: protected XEventHandler eventHandler;
037: protected Container container;
038:
039: /**
040: * Create a new validation handler for the specified container. The container
041: * provides the context in which the validation operate. Therefore validation
042: * methods are found by reflection in the specified container. Normally the
043: * container is the current XPage or a derived class.
044: * @param c the container
045: */
046: public XValidationHandler(Container c) {
047: exceptionHandler = this ;
048:
049: container = c;
050: eventHandler = null;
051: }
052:
053: /**
054: * Set the event handler instance. This class needs to interact with the event
055: * handler to manage focus and to gain access to the current event
056: * @param eh the event handler
057: */
058: public void setEventHandler(XEventHandler eh) {
059: eventHandler = eh;
060:
061: clearValidations();
062: eventHandler.addFocusHandler(container, "validationHandler");
063: }
064:
065: /**
066: * Set the validation exception handler called when a validation exception is trapped
067: * @param eh
068: */
069: public void setExceptionHandler(XValidationExceptionHandler eh) {
070: exceptionHandler = eh;
071: }
072:
073: /**
074: * Reset/removes all validations
075: */
076: public void clearValidations() {
077: validations = new Hashtable(5);
078: }
079:
080: /**
081: * Adds a validation to this page.
082: * @param comp the component being validated
083: * @param validationName the name of the validation in the validation file
084: * @param method the method used to get the component's value if any
085: * @param mask the event mask used to filter the events that trigger the validation
086: * @return the new and initialized XValidator
087: */
088: public XValidator addValidation(Component comp,
089: String validationName, String method, int mask) {
090: XValidator validator = getValidation(validationName, method,
091: mask);
092: Vector v = (Vector) validations.get(new Long(
093: FocusEvent.FOCUS_LOST * comp.hashCode()));
094: if (v == null) {
095: v = new Vector();
096: v.addElement(comp);
097: validations.put(new Long(FocusEvent.FOCUS_LOST
098: * comp.hashCode()), v);
099:
100: switch (mask) {
101: case FocusEvent.FOCUS_GAINED:
102: case FocusEvent.FOCUS_LOST:
103: default:
104: eventHandler.addFocusHandler(comp, "validationHandler");
105: break;
106: }
107: }
108: v.addElement(validator);
109: return validator;
110: }
111:
112: /**
113: * Adds a validation to this page.
114: * @param comp the component being validated
115: * @param validationName the name of the validation in the validation file
116: * @param mask the event mask used to filter the events that trigger the validation
117: * @return the new and initialized XValidator
118: */
119: public XValidator getValidation(String validationName,
120: String method, int mask) {
121: Method m = null;
122: if ((method != null) && (method.length() > 0)) {
123: try {
124: m = container.getClass().getMethod(method, null);
125: } catch (Exception e) {
126: e.printStackTrace();
127: }
128: }
129:
130: if (BuildProperties.DEBUG) {
131: if (validationFactory == null) {
132: DebugLogger
133: .logError("No validation factory is set for the page. Cannot build the validation rule: "
134: + validationName);
135: return null;
136: }
137: }
138: XValidator validator = validationFactory.getValidation(
139: validationName, m, mask, container);
140: return validator;
141: }
142:
143: /**
144: * Gets a XValidator object. The parameters of the object are read from the
145: * validation file
146: * @param validationName the name of the validation in the validation file
147: * @param method the method used to get the component's value if any
148: * @return the new and initialized XValidator
149: */
150: public XValidator getValidation(String validationName, String method) {
151: return getValidation(validationName, method, 0);
152: }
153:
154: /**
155: * Gets all the validations installed for a component
156: * @param comp the target component
157: * @return a Vector of XValidators
158: */
159: public Vector getValidations(Component comp) {
160: XValidator validator = null;
161: int ret = 0;
162: try {
163: // Get the event source
164: if (eventHandler == null)
165: return null;
166:
167: // Get the list of validators for the component
168: Vector v = (Vector) validations.get(new Long(
169: FocusEvent.FOCUS_LOST * comp.hashCode()));
170: if (v != null)
171: return v;
172: } catch (Exception ex) {
173: }
174:
175: return null;
176: }
177:
178: /**
179: * Adds a validation to this page. It is assumed that the validation will be
180: * invoked in response to FocusEvent.FOCUS_LOST events
181: * @param comp the component being validated
182: * @param validationName the name of the validation in the validation file
183: * @param method the method used to get the component's value if any
184: * @return the new and initialized XValidator
185: */
186: public XValidator addValidation(Component comp,
187: String validationName, String method) {
188: return addValidation(comp, validationName, method,
189: FocusEvent.FOCUS_LOST);
190: }
191:
192: /**
193: * Adds a validation to this page. It is assumed that the validation will be
194: * invoked in response to FocusEvent.FOCUS_LOST events
195: * @param comp the component being validated
196: * @param validationName the name of the validation in the validation file
197: * @return the new and initialized XValidator
198: */
199: public XValidator addValidation(Component comp,
200: String validationName) {
201: return addValidation(comp, validationName, null,
202: FocusEvent.FOCUS_LOST);
203: }
204:
205: /**
206: * Sets the factory used to create XValidator objects
207: * @param vf
208: */
209: public void setValidationFactory(XValidationFactory vf) {
210: validationFactory = vf;
211: }
212:
213: /**
214: * Invoke the validators for the last event. Multiple validations are checked
215: * in the order in which they were added.
216: * @return the maximum level returned by the validators
217: */
218: public int validationHandler() {
219: Component comp = null;
220: XValidator validator = null;
221: int ret = 0;
222: try {
223: // Get the event source
224: comp = (Component) eventHandler.getCurrentEvent()
225: .getSource();
226:
227: // Get the list of validators for the component
228: Vector v = (Vector) validations.get(new Long(
229: FocusEvent.FOCUS_LOST * comp.hashCode()));
230: if (v != null) {
231:
232: // Iterate over the list of validations
233: for (int i = 1; i < v.size(); i++) {
234: validator = (XValidator) v.elementAt(i);
235: if (validator != null) {
236: // Check that the validator is to be used for this event
237: if (eventHandler.getCurrentEvent().getID() == validator
238: .getMask()) {
239: // Validate and get the maximum error level
240: ret = Math.max(ret, validator.getLevel());
241: validator.validate(comp, false);
242: }
243: }
244: }
245: }
246: } catch (Exception ex) {
247: exceptionHandler.handleException(comp, ex, validator);
248: return ret;
249: }
250: return XValidator.LEVEL_IGNORE;
251: }
252:
253: /**
254: * Check all validations for this page. Typically this method should be
255: * invoked prior to a page transition or a critical transaction.
256: * @return the maximum error level raised by the validators
257: */
258: public int checkValidations() {
259: // Initialize the error level
260: int ret = XValidator.LEVEL_IGNORE;
261:
262: // Iterate over all the validators
263: Enumeration e = validations.elements();
264: XValidator validator = null;
265: Component comp = null;
266: while (e.hasMoreElements()) {
267: Vector v = (Vector) e.nextElement();
268: if (v != null) {
269: // Check the validators for each component
270: comp = (Component) v.elementAt(0);
271: int numValidations = v.size();
272: for (int i = 1; i < numValidations; i++) {
273: try {
274: validator = (XValidator) v.elementAt(i);
275: if (validator != null)
276: validator.validate(comp, true);
277: } catch (Exception ex) {
278: // Record the maximum error level
279: ret = Math.max(ret, validator.getLevel());
280:
281: // Redirect error handling to the error handler.
282: exceptionHandler.handleException(comp, ex,
283: validator);
284: }
285: }
286: }
287: }
288:
289: return ret;
290: }
291:
292: /**
293: * informs the handler when a page validation is starting or stopping. Typically
294: * when it starts the page will begin to accumulate messages which are to be displayed.
295: * When the parameter is false the page will usually display the accumulated
296: * messages
297: * @param start boolean to indicate whether the accumulation is started or stopped.
298: */
299: public int accumulateMessages(boolean accumulate, int level) {
300: if (!exceptionHandler.equals(this ))
301: return exceptionHandler.accumulateMessages(accumulate,
302: level);
303:
304: return 0;
305: }
306:
307: /**
308: * A method called when a validation exeption has been trapped.
309: *
310: * @param c Component being validated
311: * @param ex The exception caused
312: * @param validator The validator being used to validate.
313: * @return true to continue with error validation or false to suppress further
314: * validation.
315: */
316: public boolean handleException(Component comp, Exception ex,
317: XValidator validator) {
318: ex.printStackTrace();
319:
320: return true;
321: }
322: }
|