Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/aendvari/griffin/validation/ValidationReader.java


1   /*
2    * ValidationReader.java
3    *
4    * Copyright (c) 2001, 2002 Aendvari, Ltd. All Rights Reserved.
5    *
6    * See the file LICENSE for terms of use.
7    *
8    */
9   
10  package com.aendvari.griffin.validation;
11  
12  import java.io.*;
13  import java.util.*;
14  import java.beans.*;
15  
16  import java.lang.reflect.*;
17  import java.lang.NoSuchMethodException;
18  import java.lang.IllegalAccessException;
19  
20  import com.aendvari.common.util.MultiHashMap;
21  import com.aendvari.common.util.Debug;
22  import com.aendvari.common.util.ResourceLoader;
23  import com.aendvari.common.model.*;
24  
25  import com.aendvari.griffin.validation.validator.*;
26  import com.aendvari.griffin.validation.dataset.*;
27  
28  
29  /**
30   * <p>Constructs {@link Validation} from an XML file.</p>
31   *
32   * <p>The XML file defines a validator for a dataset.</p>
33   *
34   * <p>This class only reads the content of the XML file, it does not attempt to verify
35   * the definitions.
36   * </p>
37   *
38   * @author  Scott Milne
39   *
40   */
41  
42  public class ValidationReader
43  {
44    /* Constants. */
45  
46  
47    /** Constants for descriptor element names */
48    private interface NodeNames
49    {
50      public static String Include        = "include";
51  
52      public static String Name          = "name";
53      public static String Type          = "type";
54      public static String Parameter        = "param";
55      public static String ParameterDefinition  = "param-definition";
56  
57      public static String Dataset        = "dataset";
58      public static String Property        = "property";
59  
60      public static String Validator        = "validator";
61      public static String ValidatorObject    = "validator-object";
62      public static String ValidatorClass      = "validator-class";
63      public static String ValidateMethod      = "validate-method";
64  
65      public static String ErrorHandler      = "error-handler";
66      public static String ErrorObject      = "error-object";
67      public static String ErrorClass        = "error-class";
68      public static String ErrorMethod      = "error-method";
69    }
70  
71    /* Variables */
72  
73    /** An <code>ArrayList</code> of {@link Dataset} describing the properties to validate. */
74    private ArrayList datasets;
75  
76    /** The <code>HashMap</code> of {@link Validator} instances available. */
77    //private HashMap validators;
78    private MultiHashMap validators;
79  
80    /** An <code>HashMap</code> of {@link ValidationHandler}'s to use for looking up methods for validation/error calls. */
81    private HashMap handlers;
82  
83  
84    /* Constructors. */
85  
86  
87    /**
88     * Constructs a ValidationReader instance.
89     *
90     */
91  
92    public ValidationReader()
93    {
94      datasets = new ArrayList();
95      //validators = new HashMap();
96      validators = new MultiHashMap();
97      handlers = new HashMap();
98    }
99  
100   /* Accessors */
101 
102   /**
103    * Get the list of datasets.
104    *
105    * @return                  <code>Collection</code> of {@link Dataset} instances.
106    *
107    */
108 
109   public Collection getDatasets()
110   {
111     return datasets;
112   }
113 
114   /**
115    * Get the map of validators.
116    *
117    * @return                  <code>HashMap</code> of {@link Validator} instances.
118    *
119    */
120 
121   public MultiHashMap getValidators()
122   {
123     return validators;
124   }
125 
126   /**
127    * Get the map of handlers.
128    *
129    * @return                  <code>HashMap</code> of {@link ValidationHandler} instances.
130    *
131    */
132 
133   public HashMap getHandlers()
134   {
135     return handlers;
136   }
137 
138 
139   /* Parsing. */
140 
141   /**
142    * Parses the text node within the given node.
143    *
144    * @param    objectNode          The {@link ModelNode} containing the text.
145    *
146    */
147 
148   private String getTextValue(ModelNode objectNode)
149   {
150     ModelNode node = objectNode.getFirstChild();
151 
152     if( node != null )
153     {
154       return node.getNodeValue();
155     }
156 
157     return "";
158   }
159 
160   /**
161    * Create and parse a {@link MethodParameter} instance.
162    *
163    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
164    * @param    resourceLoader          A {@link ResourceLoader} class.
165    *
166    * @return                    A new completed {@link MethodParameter} instance.
167    *
168    */
169 
170   private MethodParameter parseMethodParameter( ModelNode objectNode, Class resourceLoader )
171     throws Exception
172   {
173     // <param name="propertyValue" type="int" value="0"/>
174 
175     // create a error method
176     MethodParameter methodParam = new MethodParameter();
177 
178     String name = objectNode.getAttribute("name");
179     if( name == null )
180     {
181       name = "";
182     }
183 
184     String value = objectNode.getAttribute("value");
185     if( value == null )
186     {
187       value = "";
188     }
189 
190     String type = objectNode.getAttribute("type");
191     if( type == null )
192     {
193       type = "java.lang.String";
194     }
195 
196     methodParam.setName( name );
197     methodParam.setValue( value );
198     methodParam.setType( type );
199 
200     return methodParam;
201   }
202 
203   /**
204    * Create and parse a {@link ErrorMethod} instance.
205    *
206    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
207    * @param    resourceLoader          A {@link ResourceLoader} class.
208    *
209    * @return                    A new completed {@link ErrorMethod} instance.
210    *
211    */
212 
213   private ErrorMethod parseErrorMethod( ModelNode objectNode, Class resourceLoader )
214     throws Exception
215   {
216     // create a error method
217     ErrorMethod errorMethod = new ErrorMethod();
218 
219     ModelNode node = objectNode.getFirstChild();
220 
221     while (node != null)
222     {
223       String nodeName = node.getNodeName();
224 
225       // process node types
226       if (nodeName.equals(NodeNames.Name))
227       {
228         errorMethod.setName(getTextValue(node));
229       }
230       else
231       if (nodeName.equals(NodeNames.Parameter))
232       {
233         MethodParameter param = parseMethodParameter(node, resourceLoader);
234         errorMethod.addParameter(param);
235       }
236 
237       // get next child node
238       node = node.getNextSibling();
239     }
240 
241     return errorMethod;
242   }
243 
244   /**
245    * Create and parse a {@link ErrorHandler} instance.
246    *
247    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
248    * @param    resourceLoader          A {@link ResourceLoader} class.
249    *
250    * @return                    A new completed {@link ErrorHandler} instance.
251    *
252    */
253 
254   private ErrorHandler parseErrorHandler( ModelNode objectNode, Class resourceLoader )
255     throws Exception
256   {
257     // create a validator
258     ErrorHandler handler = new ErrorHandler();
259 
260     ModelNode node = objectNode.getFirstChild();
261 
262     while (node != null)
263     {
264       String nodeName = node.getNodeName();
265 
266       // process node types
267       if (nodeName.equals(NodeNames.Name))
268       {
269         handler.setName(getTextValue(node));
270       }
271       else
272       if (nodeName.equals(NodeNames.ErrorObject))
273       {
274         handler.setHandlerObject(getTextValue(node));
275       }
276       else
277       if (nodeName.equals(NodeNames.ErrorClass))
278       {
279         String name = getTextValue(node);
280 
281         handler.setHandlerClass(name);
282 
283         // create a new (if not already there) ValidationHandler for this class
284         if ( !handlers.containsKey(name) )
285         {
286           try
287           {
288             ValidationHandler vhandler = new ValidationHandler(name, name);
289             handlers.put( name, vhandler );
290           }
291           catch( Exception exception )
292           {
293             throw exception;
294           }
295         }
296       }
297       else
298       if (nodeName.equals(NodeNames.ErrorMethod))
299       {
300         ErrorMethod method = parseErrorMethod(node, resourceLoader);
301         handler.setHandlerMethod(method);
302       }
303 
304       // get next child node
305       node = node.getNextSibling();
306     }
307 
308     return handler;
309   }
310 
311   /**
312    * Create and parse a {@link ValidateMethod} instance.
313    *
314    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
315    * @param    resourceLoader          A {@link ResourceLoader} class.
316    *
317    * @return                    A new completed {@link ValidateMethod} instance.
318    *
319    */
320 
321   private ValidateMethod parseValidateMethod( ModelNode objectNode, Class resourceLoader )
322     throws Exception
323   {
324     // create a validate method
325     ValidateMethod validateMethod = new ValidateMethod();
326 
327     ModelNode node = objectNode.getFirstChild();
328 
329     while (node != null)
330     {
331       String nodeName = node.getNodeName();
332 
333       // process node types
334       if (nodeName.equals(NodeNames.Name))
335       {
336         validateMethod.setName(getTextValue(node));
337       }
338       else
339       if (nodeName.equals(NodeNames.Parameter))
340       {
341         MethodParameter param = parseMethodParameter(node, resourceLoader);
342         validateMethod.addParameter(param);
343       }
344 
345       // get next child node
346       node = node.getNextSibling();
347     }
348 
349     return validateMethod;
350   }
351 
352   /**
353    * Create and parse a {@link Validator} instance.
354    *
355    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
356    * @param    resourceLoader          A {@link ResourceLoader} class.
357    *
358    * @return                    A new completed {@link Validator} instance.
359    *
360    */
361 
362   private Validator parseValidator( ModelNode objectNode, Class resourceLoader )
363     throws Exception
364   {
365     // create a validator
366     Validator validator = new Validator();
367 
368     ModelNode node = objectNode.getFirstChild();
369 
370     while (node != null)
371     {
372       String nodeName = node.getNodeName();
373 
374       // process node types
375       if (nodeName.equals(NodeNames.Name))
376       {
377         validator.setName(getTextValue(node));
378       }
379       else
380       if (nodeName.equals(NodeNames.ValidatorObject))
381       {
382         validator.setHandlerObject(getTextValue(node));
383       }
384       else
385       if (nodeName.equals(NodeNames.ValidatorClass))
386       {
387         String name = getTextValue(node);
388 
389         validator.setHandlerClass(name);
390 
391         // create a new (if not already there) ValidationHandler for this class
392         if ( !handlers.containsKey(name) )
393         {
394           try
395           {
396             ValidationHandler handler = new ValidationHandler(name, name);
397             handlers.put( name, handler );
398           }
399           catch( Exception exception )
400           {
401             throw exception;
402           }
403         }
404       }
405       else
406       if (nodeName.equals(NodeNames.ValidateMethod))
407       {
408         ValidateMethod method = parseValidateMethod(node, resourceLoader);
409         validator.setHandlerMethod(method);
410       }
411 
412       // get next child node
413       node = node.getNextSibling();
414     }
415 
416     return validator;
417   }
418 
419   /**
420    * Create and parse a {@link ParameterDefine} instance.
421    *
422    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
423    *
424    * @return                    A new completed {@link ParameterDefine} instance.
425    *
426    */
427 
428   private ParameterDefine parseParameterDefine( ModelNode objectNode )
429     throws Exception
430   {
431     ParameterDefine define = new ParameterDefine();
432 
433     String name = objectNode.getAttribute("name");
434 
435     if( name != null )
436     {
437       define.setName(name);
438     }
439 
440     String value = objectNode.getAttribute("value");
441     if( value != null )
442     {
443       define.setValue( value );
444     }
445 
446     String path = objectNode.getAttribute("path");
447     if( path != null )
448     {
449       define.setPath( path );
450     }
451 
452     String type = objectNode.getAttribute("type");
453     if( type != null )
454     {
455       define.setType( type );
456     }
457 
458     return define;
459   }
460 
461   /**
462    * Create and parse a {@link Property} instance.
463    *
464    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
465    * @param    resourceLoader          A {@link ResourceLoader} class.
466    *
467    * @return                    A new completed {@link Property} instance.
468    *
469    */
470 
471   private Property parseProperty( ModelNode objectNode, Class resourceLoader )
472     throws Exception
473   {
474     // create a property
475     Property property = new Property();
476 
477     String type = objectNode.getAttribute("type");
478     if (type != null)
479     {
480       property.setType(type);
481     }
482 
483     String path = objectNode.getAttribute("path");
484     if (path != null)
485     {
486       property.setPath(path);
487     }
488 
489     // scan child nodes
490     ModelNode node = objectNode.getFirstChild();
491 
492     while (node != null)
493     {
494       String nodeName = node.getNodeName();
495 
496       // process node types
497       if (nodeName.equals(NodeNames.Validator))
498       {
499         parsePropertyValidator(node, property, resourceLoader);
500       }
501       else
502       if (nodeName.equals(NodeNames.ErrorHandler))
503       {
504         parsePropertyErrorHandler(node, property, resourceLoader);
505       }
506 
507       // get next child node
508       node = node.getNextSibling();
509     }
510 
511     return property;
512   }
513 
514   /**
515    * Parse a validator for a property.
516    *
517    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
518    * @param    property            The {@link Property} instance to add to,
519    * @param    resourceLoader          A {@link ResourceLoader} class.
520    *
521    */
522 
523   private void parsePropertyValidator( ModelNode objectNode, Property property, Class resourceLoader )
524     throws Exception
525   {
526     ModelNode node = objectNode.getFirstChild();
527 
528     while (node != null)
529     {
530       String nodeName = node.getNodeName();
531 
532       // process params
533       if (nodeName.equals(NodeNames.Name))
534       {
535         property.setValidator(getTextValue(node));
536       }
537       else
538       if (nodeName.equals(NodeNames.Parameter))
539       {
540         // parse the define
541         ParameterDefine define = parseParameterDefine(node);
542 
543         // add the define to the property
544         property.setValidatorParameterDefine(define.getName(), define);
545       }
546 
547       // get next child node
548       node = node.getNextSibling();
549     }
550   }
551 
552   /**
553    * Parse an error handler for a property.
554    *
555    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
556    * @param    property            The {@link Property} instance to add to,
557    * @param    resourceLoader          A {@link ResourceLoader} class.
558    *
559    */
560 
561   private void parsePropertyErrorHandler( ModelNode objectNode, Property property, Class resourceLoader )
562     throws Exception
563   {
564     ModelNode node = objectNode.getFirstChild();
565 
566     while (node != null)
567     {
568       String nodeName = node.getNodeName();
569 
570       // process params
571       if (nodeName.equals(NodeNames.Name))
572       {
573         property.setErrorHandler(getTextValue(node));
574       }
575       else
576       if (nodeName.equals(NodeNames.Parameter))
577       {
578         // parse the define
579         ParameterDefine define = parseParameterDefine(node);
580 
581         // add the define to the property
582         property.setErrorHandlerParameterDefine(define.getName(), define);
583       }
584 
585       // get next child node
586       node = node.getNextSibling();
587     }
588   }
589 
590   /**
591    * Create and parse a {@link Dataset} instance.
592    *
593    * @param    objectNode            The {@link ModelNode} of which to start parsing at.
594    * @param    resourceLoader          A {@link ResourceLoader} class.
595    *
596    * @return                    A new completed {@link Dataset} instance.
597    *
598    */
599 
600   private Dataset parseDataset( ModelNode objectNode, Class resourceLoader )
601     throws Exception
602   {
603     // create a validator
604     Dataset dataset = new Dataset();
605 
606     ModelNode node = objectNode.getFirstChild();
607 
608     while (node != null)
609     {
610       String nodeName = node.getNodeName();
611 
612       // process node types
613       if (nodeName.equals(NodeNames.Property))
614       {
615         Property property = parseProperty(node, resourceLoader);
616         dataset.addProperty(property);
617       }
618 
619       // get next child node
620       node = node.getNextSibling();
621     }
622 
623     return dataset;
624   }
625 
626   /**
627    * Get the resource <code> from InputStream</code> the provided {@link ResourceLoader} class.
628    *
629    * @param    resourceLoader        A {@link ResourceLoader} class.
630    *
631    * @return                  {@link InputStream} of the xml descriptor file.
632    *
633    * @throws                  {@link Exception} if the lookup fails.
634    *
635    */
636 
637   private InputStream createDescriptorStream( Class resourceLoader )
638     throws Exception
639   {
640     Class[] listParam = {};
641     Object[] listArgs = {};
642 
643     // create an instance of the given resource class
644     Constructor constructor = resourceLoader.getConstructor(listParam);
645     ResourceLoader resource = (ResourceLoader)constructor.newInstance(listArgs);
646 
647     // get the resource stream from the class
648     // if this fails, and Exception will be thrown.
649     InputStream in = resource.getResourceAsStream();
650     return in;
651   }
652 
653   /**
654    * Read the content of the given file as an XML document containing descriptions.
655    *
656    * @param    modelTree            An empty/new {@link ModelTree} instance to load data into.
657    * @param    resourceLoader          A {@link ResourceLoader} class.
658    *
659    */
660 
661   public void read(ModelTree modelTree, Class resourceLoader)
662     throws Exception
663   {
664     // create the input stream
665     InputStream stream = createDescriptorStream(resourceLoader);
666 
667     // load the model tree with the resource input stream
668     modelTree.loadFromStream(stream);
669 
670     // get nodes within <descriptor>
671     //
672     // {Document}
673     //    <model>
674     //      <first_child>
675     //      <next_child>
676     //    </model>
677     // {/Document}
678     //
679     // The above describes the reason why we're calling getFirstChild twice.
680     // The call to getRootNode returns the {Document}. In order to get the
681     // <first_child> node we want, we have to make the following call:
682     ModelNode node = modelTree.getRootNode().getFirstChild().getFirstChild();
683 
684     while (node != null)
685     {
686       String nodeName = node.getNodeName();
687 
688       // process node types
689       if (nodeName.equals(NodeNames.Include))
690       {
691         //
692         // using the class path, load in the descriptor file
693         // the path points to and add it to this reader.
694         //
695 
696         String className = getTextValue(node);
697 
698         // lookup the class object by name
699         Class includeClass = null;
700 
701         try
702         {
703           includeClass = Class.forName(className);
704         }
705         catch(ClassNotFoundException ex)
706         {
707           throw ex;
708         }
709 
710         // make sure this class is a descriptor
711         if( !ResourceLoader.class.isAssignableFrom(includeClass) )
712         {
713           throw new Exception("The included descriptor is not a com.aendvari.common.util.ResourceLoader implementation.");
714         }
715 
716         // parse this descriptor aswell
717         read( modelTree, includeClass );
718       }
719       else if (nodeName.equals(NodeNames.Validator))
720       {
721         Validator validator = parseValidator(node, resourceLoader);
722         validators.put( validator.getName(), validator );
723       }
724       else if (nodeName.equals(NodeNames.ErrorHandler))
725       {
726         ErrorHandler handler = parseErrorHandler(node, resourceLoader);
727         handlers.put( handler.getName(), handler );
728       }
729       else if (nodeName.equals(NodeNames.Dataset))
730       {
731         Dataset dataset = parseDataset(node, resourceLoader);
732         datasets.add( dataset );
733       }
734 
735       // get next child node
736       node = node.getNextSibling();
737     }
738   }
739 }
740