KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > runtime > bean > AnnotationConstraintValidator


1 package org.apache.beehive.controls.runtime.bean;
2
3 /*
4  * Copyright 2004 The Apache Software Foundation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * $Header:$
19  */

20
21 import java.io.File JavaDoc;
22 import java.lang.annotation.Annotation JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.net.MalformedURLException JavaDoc;
25 import java.net.URI JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.text.ParseException JavaDoc;
28 import java.text.SimpleDateFormat JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Date JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Map.Entry;
35
36 import org.apache.beehive.controls.api.bean.AnnotationMemberTypes;
37 import org.apache.beehive.controls.api.bean.AnnotationConstraints.MembershipRule;
38 import org.apache.beehive.controls.api.bean.AnnotationConstraints.MembershipRuleValues;
39 import org.apache.beehive.controls.api.properties.PropertyKey;
40 import org.apache.beehive.controls.api.properties.PropertySet;
41
42 /**
43  * This class offers methods for validating values assigned to a control property.
44  * The validation process will ensure
45  * 1. The value is appropriate for the property's property type
46  * 2. The value satisfies the constraints defined on the property type
47  * 3. The value satisfies the constraints defined on the property set that the property is defined in.
48  * Refer to {@link org.apache.beehive.controls.api.bean.AnnotationMemberTypes AnnotationMemberTypes} and
49  * {@link org.apache.beehive.controls.api.bean.AnnotationConstraints AnnotationConstraints} for more
50  * information on property constraints.
51  */

52 public class AnnotationConstraintValidator
53 {
54
55     public AnnotationConstraintValidator()
56     {
57         super();
58     }
59
60     /**
61      * This method ensures that any control property value assignment satisfies
62      * all property constraints. This method should be called by control
63      * property setters to ensure values assigned to properties at runtime are
64      * validated.
65      *
66      * @param key
67      * The property that the specified key is assigned to
68      * @param value
69      * The value assigned to the specified property key
70      * @throws IllegalArgumentException
71      * when the value assigned to the specified property key does
72      * not satisfy a property constraint.
73      */

74     public static void validate(PropertyKey key, Object JavaDoc value)
75             throws IllegalArgumentException JavaDoc
76     {
77         validate(key.getAnnotations(), value);
78     }
79
80     /**
81      * This method ensures the membership constraints defined on a property set
82      * is satisfied.
83      *
84      * @param propertySet the property set to validate
85      */

86     public static void validateMembership(Annotation JavaDoc propertySet)
87     {
88         Class JavaDoc c = propertySet.annotationType();
89         MembershipRule rule = (MembershipRule) c
90                 .getAnnotation(MembershipRule.class);
91         if (rule == null)
92             return;
93         MembershipRuleValues ruleValue = rule.value();
94         String JavaDoc[] memberNames = rule.memberNames();
95         Method JavaDoc[] members = getMembers(c, memberNames);
96         int i = getNumOfMembersSet(propertySet, members);
97         if (ruleValue == MembershipRuleValues.ALL_IF_ANY)
98         {
99             if (i != 0 && i != members.length)
100                 throw new IllegalArgumentException JavaDoc("The membership rule on " + propertySet.toString() +
101                     " is not satisfied. Either all members must be set or none is set");
102         }
103         else if (ruleValue == MembershipRuleValues.EXACTLY_ONE)
104         {
105             if (i != 1)
106                 throw new IllegalArgumentException JavaDoc("The membership rule on " + propertySet.toString() +
107                     " is not satisfied. Exactly one member must be set");
108         }
109         else if (ruleValue == MembershipRuleValues.AT_LEAST_ONE)
110         {
111             if (i < 1)
112                 throw new IllegalArgumentException JavaDoc("The membership rule on " + propertySet.toString() +
113                     " is not satisfied. At least one member must be set");
114         }
115         else if (ruleValue == MembershipRuleValues.AT_MOST_ONE)
116         {
117             if (i > 1)
118                 throw new IllegalArgumentException JavaDoc("The membership rule on " + propertySet.toString() +
119                     " is not satisfied. At most one member may be set");
120         }
121     }
122
123     private static Method JavaDoc[] getMembers(Class JavaDoc<? extends Annotation JavaDoc> c, String JavaDoc[] memberNames)
124     {
125         Method JavaDoc[] methods = null;
126         if (memberNames == null || memberNames.length == 0)
127         {
128             methods = c.getDeclaredMethods();
129         }
130         else
131         {
132             methods = new Method JavaDoc[memberNames.length];
133             for (int i = 0; i < memberNames.length; i++)
134             {
135                 try
136                 {
137                     methods[i] = c.getMethod(memberNames[i], (Class JavaDoc[]) null);
138                 }
139                 catch (Exception JavaDoc e)
140                 {
141                     // method is not found, so the member is ignored.
142
}
143             }
144         }
145         return methods;
146     }
147
148     private static int getNumOfMembersSet(Annotation JavaDoc propertySet,
149             Method JavaDoc[] members)
150     {
151         int num = 0;
152         for (Method JavaDoc m : members)
153         {
154             Class JavaDoc returnType = m.getReturnType();
155             Object JavaDoc o = null;
156             try
157             {
158                 o = m.invoke(propertySet, (Object JavaDoc[]) null);
159             }
160             catch (Exception JavaDoc e)
161             {
162                 // This should never happen.
163
throw new RuntimeException JavaDoc(e);
164             }
165
166             if ((returnType == String JavaDoc.class && !((String JavaDoc) o)
167                     .equals(AnnotationMemberTypes.OPTIONAL_STRING))
168                     || (returnType == int.class && ((Integer JavaDoc) o).intValue() != AnnotationMemberTypes.OPTIONAL_INT)
169                     || (returnType == short.class && ((Short JavaDoc) o)
170                             .shortValue() != AnnotationMemberTypes.OPTIONAL_SHORT)
171                     || (returnType == long.class && ((Long JavaDoc) o).longValue() != AnnotationMemberTypes.OPTIONAL_LONG)
172                     || (returnType == float.class && ((Float JavaDoc) o)
173                             .floatValue() != AnnotationMemberTypes.OPTIONAL_FLOAT)
174                     || (returnType == double.class && ((Double JavaDoc) o)
175                             .doubleValue() != AnnotationMemberTypes.OPTIONAL_DOUBLE)
176                     || (returnType == char.class && ((Character JavaDoc) o)
177                             .charValue() != AnnotationMemberTypes.OPTIONAL_CHAR)
178                     || (returnType == byte.class && ((Byte JavaDoc) o).byteValue() != AnnotationMemberTypes.OPTIONAL_BYTE)
179                     || (returnType == boolean.class && !((Boolean JavaDoc) o)
180                             .booleanValue()))
181                     num++;
182         }
183         return num;
184     }
185
186     protected static synchronized void validate(Annotation JavaDoc[] annotations,
187             Object JavaDoc value) throws IllegalArgumentException JavaDoc
188     {
189
190         // Determine if the member is optional. This is done in a separate loop
191
// because a control property may have multiple constraints and the
192
// optional
193
// annotation may be declared after another constraint annotation.
194
boolean optional = false;
195         for (Annotation JavaDoc a : annotations)
196         {
197             if (a instanceof AnnotationMemberTypes.Optional)
198             {
199                 optional = true;
200                 break;
201             }
202         }
203
204         for (Annotation JavaDoc a : annotations)
205         {
206             if (a instanceof AnnotationMemberTypes.Text)
207                 validateText((AnnotationMemberTypes.Text) a, value, optional);
208             else if (a instanceof AnnotationMemberTypes.Decimal)
209                 validateDecimal((AnnotationMemberTypes.Decimal) a, value,
210                         optional);
211             else if (a instanceof AnnotationMemberTypes.Int)
212                 validateInt((AnnotationMemberTypes.Int) a, value, optional);
213             else if (a instanceof AnnotationMemberTypes.Date)
214                 validateDate((AnnotationMemberTypes.Date) a, value, optional);
215             else if (a instanceof AnnotationMemberTypes.FilePath)
216                 validateFilePath((AnnotationMemberTypes.FilePath) a, value,
217                         optional);
218             else if (a instanceof AnnotationMemberTypes.JndiName)
219                 validateJndiName((AnnotationMemberTypes.JndiName) a, value,
220                         optional);
221             else if (a instanceof AnnotationMemberTypes.QName)
222                 validateQName((AnnotationMemberTypes.QName) a, value, optional);
223             else if (a instanceof AnnotationMemberTypes.URI)
224                 validateURI((AnnotationMemberTypes.URI) a, value, optional);
225             else if (a instanceof AnnotationMemberTypes.URL)
226                 validateURL((AnnotationMemberTypes.URL) a, value, optional);
227             else if (a instanceof AnnotationMemberTypes.URN)
228                 validateURN((AnnotationMemberTypes.URN) a, value, optional);
229             else if (a instanceof AnnotationMemberTypes.XML)
230                 validateXML((AnnotationMemberTypes.XML) a, value, optional);
231         }
232     }
233
234     private static void validateXML(AnnotationMemberTypes.XML a, Object JavaDoc value,
235             boolean optional)
236     {
237     }
238
239     private static void validateURN(AnnotationMemberTypes.URN a, Object JavaDoc value,
240             boolean optional)
241     {
242         if (optional
243                 && (value == null || value
244                         .equals(AnnotationMemberTypes.OPTIONAL_STRING)))
245             return;
246
247         if (!(value instanceof String JavaDoc))
248         {
249             error("The value, "
250                     + value
251                     + ", assigned to an URN property must be of type java.lang.String.");
252         }
253
254         URI.create((String JavaDoc) value);
255     }
256
257     private static void validateURL(AnnotationMemberTypes.URL a, Object JavaDoc value,
258             boolean optional)
259     {
260         if (optional
261                 && (value == null || value
262                         .equals(AnnotationMemberTypes.OPTIONAL_STRING)))
263             return;
264
265         if (!(value instanceof String JavaDoc))
266         {
267             error("The value, "
268                     + value
269                     + ", assigned to an URL property must be of type java.lang.String.");
270         }
271
272         try
273         {
274             new URL JavaDoc((String JavaDoc) value);
275         }
276         catch (MalformedURLException JavaDoc mue)
277         {
278             error("The value, " + value
279                     + ", assigned to the URL property is a malformed URL.", mue);
280         }
281     }
282
283     private static void validateURI(AnnotationMemberTypes.URI a, Object JavaDoc value,
284             boolean optional)
285     {
286         if (optional
287                 && (value == null || value
288                         .equals(AnnotationMemberTypes.OPTIONAL_STRING)))
289             return;
290
291         if (!(value instanceof String JavaDoc))
292         {
293             error("The value, "
294                     + value
295                     + ", assigned to an URI property must be of type java.lang.String.");
296         }
297
298         URI.create((String JavaDoc) value);
299     }
300
301     private static void validateQName(AnnotationMemberTypes.QName a,
302             Object JavaDoc value, boolean optional)
303     {
304     }
305
306     private static void validateJndiName(AnnotationMemberTypes.JndiName a,
307             Object JavaDoc value, boolean optional)
308     {
309     }
310
311     private static void validateFilePath(AnnotationMemberTypes.FilePath a,
312             Object JavaDoc value, boolean optional)
313     {
314         if (optional
315                 && (value == null || value
316                         .equals(AnnotationMemberTypes.OPTIONAL_STRING)))
317             return;
318
319         if (!(value instanceof String JavaDoc))
320         {
321             error("The value, "
322                     + value
323                     + ", assigned to a FilePath property must be of type java.lang.String.");
324         }
325
326 //Temporarily commenting out the following check on FilePath until
327
//an agreement is reached on what is a valid FilePath.
328
//
329
// File file = new File((String) value);
330
// if (!file.isFile() || !file.canRead())
331
// {
332
// error("The value, "
333
// + value
334
// + ", assigned to a FilePath property must be a readable file.");
335
// }
336

337     }
338
339     private static void validateDate(AnnotationMemberTypes.Date a,
340             Object JavaDoc value, boolean optional)
341     {
342         if (optional
343                 && (value == null || value
344                         .equals(AnnotationMemberTypes.OPTIONAL_STRING)))
345             return;
346
347         if (!(value instanceof String JavaDoc))
348         {
349             error("The value, "
350                     + value
351                     + ", assigned to a date property must be of type java.lang.String.");
352         }
353
354         try
355         {
356             String JavaDoc format = a.format();
357             
358             Date JavaDoc date = parseDate(format , (String JavaDoc) value);
359
360             String JavaDoc minValue = a.minValue();
361             if (minValue != null && minValue.length() > 0)
362             {
363                 Date JavaDoc minDate = parseDate(format, a.minValue());
364                 if (minDate.compareTo(date) > 0)
365                 {
366                     error("The date, "
367                             + value
368                             + ", assigned to a date property is earlier than the earliest date allowed: "
369                             + minValue);
370                 }
371             }
372             String JavaDoc maxValue = a.maxValue();
373             if (maxValue != null && maxValue.length() > 0)
374             {
375                 Date JavaDoc maxDate = parseDate(format, a.maxValue());
376                 if (maxDate.compareTo(date) < 0)
377                 {
378                     error("The date, "
379                             + value
380                             + ", assigned to a date property is later than the latest date allowed: "
381                             + maxValue);
382                 }
383             }
384         }
385         catch (ParseException JavaDoc pe)
386         {
387             error("Value assigned to a date property is not in the specified format.");
388         }
389
390     }
391
392     public static Date JavaDoc parseDate(String JavaDoc format, String JavaDoc value) throws ParseException JavaDoc
393     {
394         SimpleDateFormat JavaDoc sdFormat = new SimpleDateFormat JavaDoc(format);
395         sdFormat.setLenient(false);
396         return sdFormat.parse(value);
397     }
398
399     /**
400      * @param value
401      * @return
402      */

403     private static void validateInt(AnnotationMemberTypes.Int a, Object JavaDoc value,
404             boolean optional)
405     {
406         if (optional
407                 && (value == null ||
408                         value.equals(AnnotationMemberTypes.OPTIONAL_STRING) ||
409                         value.equals(AnnotationMemberTypes.OPTIONAL_INT)))
410             return;
411
412         int intValue = 0;
413
414         if (value instanceof String JavaDoc)
415         {
416             try
417             {
418                 intValue = Integer.parseInt((String JavaDoc) value);
419             }
420             catch (NumberFormatException JavaDoc nfe)
421             {
422                 error("The value ,"
423                         + value
424                         + ", assigned to an int property does not represent an integer.");
425             }
426         }
427         else if (value instanceof Integer JavaDoc)
428         {
429             intValue = ((Integer JavaDoc) value).intValue();
430         }
431         else
432         {
433             error("The value, "
434                     + value
435                     + ", assigned to an int property must be of type java.lang.String or int.");
436         }
437
438         if (intValue < a.minValue())
439             error("The value, "
440                     + intValue
441                     + ", assigned to an int property is less than the minimum value allowed: "
442                     + a.minValue() + ".");
443         else if (intValue > a.maxValue())
444             error("The value, "
445                     + intValue
446                     + ", assigned to an int property exeeds the maximum value allowed: "
447                     + a.maxValue() + ".");
448     }
449
450     private static void validateDecimal(AnnotationMemberTypes.Decimal a,
451             Object JavaDoc value, boolean optional)
452     {
453         if (optional
454                 && (value == null ||
455                     value.equals(AnnotationMemberTypes.OPTIONAL_STRING) ||
456                     value.equals(AnnotationMemberTypes.OPTIONAL_FLOAT) ||
457                     value.equals(AnnotationMemberTypes.OPTIONAL_DOUBLE)))
458             return;
459
460         double doubleValue = 0;
461         String JavaDoc doubleString = null;
462         
463         if (value instanceof String JavaDoc)
464         {
465             doubleValue = Double.parseDouble((String JavaDoc)value);
466             doubleString = (String JavaDoc)value;
467         }
468         else if (value instanceof Float JavaDoc)
469         {
470             doubleValue = ((Float JavaDoc)value).doubleValue();
471             doubleString = ((Float JavaDoc)value).toString();
472         }
473         else if (value instanceof Double JavaDoc)
474         {
475             doubleValue = ((Double JavaDoc)value).doubleValue();
476             doubleString = ((Double JavaDoc)value).toString();
477         }
478         else
479         {
480             error("The value, "
481                     + value
482                     + ", assigned to a decimal property must be of type float, double, or java.lang.String.");
483         }
484
485         if (doubleValue < a.minValue())
486             error("The value, "
487                     + doubleValue
488                     + ", assigned to a decimal property is less than the the minimum value allowed: "
489                     + a.minValue() + ".");
490
491         if (doubleValue > a.maxValue())
492             error("The value, "
493                     + doubleValue
494                     + ", assigned to a decimal property exceeds the maximum value allowed: "
495                     + a.maxValue() + ".");
496
497         int decimalPos = doubleString.indexOf('.');
498
499         if (decimalPos == -1)
500             return;
501
502         if (doubleString.length() - decimalPos - 1 > a.places())
503             error("The decimal places in the value, " + doubleString
504                     + ", assigned to a decimal property exceeds " + a.places()
505                     + ", the number of decimal places allowed.");
506
507     }
508
509     private static void validateText(AnnotationMemberTypes.Text a,
510             Object JavaDoc value, boolean optional)
511     {
512         if (optional
513                 && (value == null || value
514                         .equals(AnnotationMemberTypes.OPTIONAL_STRING)))
515             return;
516
517         if (!(value instanceof String JavaDoc))
518             error("The value, "
519                     + value
520                     + ", assigned to a text property must be of type java.lang.String.");
521
522         String JavaDoc str = (String JavaDoc) value;
523         if (str.length() > a.maxLength())
524             error("The value, "
525                     + str
526                     + ", assigned to a text property exceeds the maximum length allowed: "
527                     + a.maxLength());
528
529         if (a.isLong())
530         {
531             try
532             {
533                 Long.parseLong(str);
534             }
535             catch (NumberFormatException JavaDoc nfe)
536             {
537                 error("The value, "
538                         + str
539                         + ", assigned to a text property with a long number constraint does not represent a long number.");
540             }
541         }
542
543     }
544
545     private static void error(String JavaDoc message)
546     {
547         error(message, null);
548     }
549
550     private static void error(String JavaDoc message, Throwable JavaDoc t)
551     {
552         throw new IllegalArgumentException JavaDoc(message, t);
553     }
554
555 }
556
Popular Tags