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

Quick Search    Search Deep

Source code: com/further/jaudit/SystemConfiguration.java


1   /*
2    * SystemConfiguration.java
3    * Copyright (c) 2001, Kristopher Wehner
4    * Created on September 16, 2001, 12:59 AM
5    */
6   
7   package com.further.jaudit;
8   
9   import java.io.IOException;
10  import java.io.File;
11  import java.util.Map;
12  import java.util.HashMap;
13  import java.util.Iterator;
14  import java.util.List;
15  import java.util.LinkedList;
16  import java.util.Set;
17  import java.util.HashSet;
18  
19  import javax.xml.parsers.SAXParser;
20  import javax.xml.parsers.SAXParserFactory;
21  import javax.xml.parsers.ParserConfigurationException;
22  import org.xml.sax.helpers.DefaultHandler;
23  import org.xml.sax.SAXParseException;
24  import org.xml.sax.Attributes;
25  import org.xml.sax.SAXException;
26  import org.apache.log4j.Category;
27  import org.apache.log4j.BasicConfigurator;
28  
29  /**
30   * The system configuration holds the static configuration for the audit
31   * system, including what metrics are collected and what their names are,
32   * and the base directory of the source tree that is to be audited. The
33   * configuration itself is done using XML and parsed using xerces SAX2
34   * parser. DTD and an example configuration are in jaudit/resource/xml.
35   *
36   * @author Kris Wehner <kris@further.com>
37   * @version $Id: SystemConfiguration.java,v 1.1.1.1 2001/10/11 16:42:08 krisw Exp $
38   * @since 1.0
39   */
40  public class SystemConfiguration {
41      /**
42       * log4j audit channel
43       */
44      private static Category category =
45          Category.getInstance(SystemConfiguration.class.getName());
46      
47      /**
48       * The root source directory. Every directory under this directory
49       * is assumed to contain source, and all files in this directory are
50       * candidates for audit if they have the correct file extension.
51       */
52      private static String rootSourceDirectory;
53      
54      /**
55       * The set of ignored directories when doing a directory listing. 
56       * This is used, among other things, to ignore the CVS directories
57       * that many projects have
58       */
59      private static Set ignoredDirectories = new HashSet();
60      /**
61       * Should the output source be formatted using a pretty printer, 
62       * or should it come out as text/plain
63       */
64      private static boolean formatSource = false;
65      
66      
67      /**
68       * The number of milliseconds between source audits. An audit older than
69       * this value is flagged as "expired", and the file is considered to be
70       * equivilent to unaudited
71       */
72      private static long auditFrequency;
73      /**
74       * The user specified foreground color
75       */
76      private static String foregroundColor;
77      /**
78       * The user specified background color
79       */
80      private static String backgroundColor;
81      /**
82       * The user specified keyword color
83       */
84      private static String keywordColor;
85      /**
86       * The user specified comment color
87       */
88      private static String commentColor;
89      /**
90       * The color for a file that has passed audit
91       */
92      private static String passedAuditColor;
93      /**
94       * The color for a file that has failed audit
95       */
96      private static String failedAuditColor;
97      /**
98       * The color for a file that needs to be audited, either due to
99       * age or complete lack of all audits
100      */
101     private static String unauditedColor;
102     /**
103      * The color for links in the html page
104      */
105     private static String linkColor;
106     /**
107      * The color for viewed links in the html output
108      */
109     private static String vlinkColor;    
110     
111     /**
112      * The map of active MetricCreator objects in the system. These are
113      * built during configuration parsing, then used in the factory
114      * methods to create the metric sets used in the system. The map 
115      * keys are the metric abbreviations and the values are the MetricCreators.
116      */
117     private static Map metricCreatorMap = new HashMap();
118     
119     /**
120      * The metric creator is responsible for receiving raw unparsed
121      * string values from the SAX parser, then assembling them to 
122      * produce concrete metric instances.
123      *
124      */
125     private static class MetricCreator {
126         /**
127          * The value for the metric name
128          */
129         private String metricName;
130         /**
131          * The value for the metric abbreviation
132          */
133         private String abbreviation;
134         /**
135          * The metric type. Allowable values are boolean and fixed-range
136          */
137         private String metricType;
138         /**
139          * The metric default value
140          */
141         private String defaultValue;
142         /**
143          * The required metric value to ensure that a metric "passes" for a
144          * source file
145          */
146         private String requiredValue;
147         /**
148          * The low end of the acceptable range for fixed-range
149          */
150         private String lowerLimit;
151         /**
152          * The high end of the acceptable range for fixed-range
153          */
154         private String upperLimit;
155         /**
156          * The description for the given metric
157          */
158         private String description;
159         /**
160          * The list of possible values, if the metric is an enumeration
161          */
162         private LinkedList possibleValues = new LinkedList();
163         
164         /**
165          * Set the name of the metric
166          *
167          * @param name The non-null metric name, as contained in the <name> tag
168          */
169         public void setMetricName(String name) {
170             metricName = name;
171         }
172         
173         /**
174          * Set the metric abbreviation. This is the primary id used for referencing
175          * the metric, and, as such, must be unique across all the metric instances.
176          *
177          * @param abbrev The non-null metric abbreviation, from the <abbreviation> tag
178          */
179         public void setMetricAbbreviation(String abbrev) {
180             abbreviation = abbrev;
181         }
182         
183         /**
184          * Get the metric abbreviation, used for registering the metric creator
185          * in the creator map.
186          *
187          * @return The abbreviation for the metric.
188          */
189         public String getMetricAbbreviation() {
190             return abbreviation;
191         }
192                         
193         /**
194          * Set the metric type, one of "boolean" or "fixed-range". This determines
195          * the concrete metric subclass that will be produced.
196          *
197          * @param type The metric type
198          */
199         public void setMetricType(String type) {
200             metricType = type;
201         }
202         
203         /**
204          * Set the description for the metric, which is the longer bit of
205          * text that explains the purpose of the metric.
206          *
207          * @param description The description for the metric
208          */
209         public void setDescription(String description) {
210             this.description = description;
211         }
212         
213         /** 
214          * Set the default value for the metric. This must be consistent 
215          * with the metric type, and is used when a new metric is created.
216          *
217          * @param defaultValue The default value for the metric as a string
218          */
219         public void setDefaultValue(String defaultValue) {
220             this.defaultValue = defaultValue;
221         }
222         
223         /**
224          * Set the required value for the metric. For the rules governing
225          * the format of this value, see {@link #setDefaultValue(String)}
226          * 
227          * @param requiredValue The required value for the metric as a string
228          */
229         public void setRequiredValue(String requiredValue) {
230             this.requiredValue = requiredValue;
231         }
232         
233         /**
234          * Set the lower limit for a fixed-range metric.
235          *
236          * @param lower The lower limit for a fixed range metric
237          */
238         public void setLowerLimit(String lower) {
239             lowerLimit = lower;
240         }
241         
242         /**
243          * Set the upper limit for a fixed-range metric
244          *
245          * @param upper The upper limit for a fixed range metric
246          */
247         public void setUpperLimit(String upper) {
248             upperLimit = upper;
249         }
250         
251         /**
252          * Add a value for an enumerated type metric
253          *
254          * @param value The possible value for the metric to add
255          */
256         public void addValue(String value) {
257             possibleValues.addLast(value);
258         }
259         
260         /**
261          * Utility method to convert a string value into a boolean. 
262          * This performs the requisite validation to ensure that
263          * the value is consistent with the metric.
264          *
265          * @param value The string value to convert to boolean
266          * @return The boolean value represented by the string
267          * @throws ConfigurationExpection If the string is not a valid boolean
268          */
269         private boolean booleanValue(String value) 
270             throws ConfigurationException {
271                 if ("true".equalsIgnoreCase(value) ||
272                     "false".equalsIgnoreCase(value))
273                     return Boolean.valueOf(value).booleanValue();
274                 else
275                     throw new ConfigurationException("Invalid value for boolean: " + value);
276         }
277         
278         /**
279          * Utility method to convert a string value into a double.
280          * This performs the requisite validation to ensure that the 
281          * value is consistent with a valid double
282          *
283          * @param value The string value to convert to double
284          * @return The double value represented by the string
285          * @throws ConfigurationException If the string value is not a valid double
286          */
287         private double doubleValue(String value) 
288             throws ConfigurationException {
289                 try {
290                     return Double.valueOf(value).doubleValue();
291                 } catch (NumberFormatException nfe) {
292                     throw new ConfigurationException(nfe.toString());
293                 }
294         }
295                         
296         /**
297          * Validate that the configuration is consistent with the 
298          * specified metric type. If this method returns true, then
299          * the metric creator will be able to succesfully create
300          * metrics with createMetric() 
301          *
302          * @throws ConfigurationException If the configuration is not 
303          *         consistent with metric type
304          */
305         public void validate() 
306             throws ConfigurationException {
307                 if ("fixed-range".equals(metricType)) {
308                     if ((defaultValue == null) ||
309                         (lowerLimit == null) ||
310                         (requiredValue == null) ||
311                         (upperLimit == null)) 
312                             throw new ConfigurationException("Missing required tag value");
313                     doubleValue(defaultValue);
314                     doubleValue(lowerLimit);
315                     doubleValue(upperLimit);
316                     doubleValue(requiredValue);
317                 }
318                 else if ("boolean".equals(metricType)) {
319                     if (defaultValue == null)
320                         throw new ConfigurationException("Default value cannot be null");
321                     if (requiredValue == null)
322                         throw new ConfigurationException("Required value cannot be null");                    
323                     booleanValue(defaultValue);
324                     booleanValue(requiredValue);
325                 } else if ("enumeration".equals(metricType)) {
326                     if (defaultValue == null)
327                         throw new ConfigurationException("Default value cannot be null");
328                     if (requiredValue == null)
329                         throw new ConfigurationException("Required value cannot be null");
330                     if (!possibleValues.contains(defaultValue))
331                         throw new ConfigurationException("Default value not in values list");
332                     if (!possibleValues.contains(requiredValue))
333                         throw new ConfigurationException("Required value not in values list");                    
334                 } else
335                     throw new ConfigurationException("Unknown metric type: " + metricType);
336         }
337                     
338         
339         
340         /** 
341          * Factory method to produce concrete metric instances for
342          * the given metric type string. This attempts to initialize
343          * the metric, and if it is unable,  a runtime error is raised
344          * Clients are expected to validate the configuration values with
345          * validate() before ever calling createMetric().
346          *
347          * @return An initialized metric instance
348          * @throws Error If the data is inconsistent to allow the metric
349          *         to be created
350          */
351         public SourceMetric createMetric() {
352             try {
353                 // FIXME: I'd really like to be rid of this if block. This
354                 //        is an admission of a chink in the design.
355                 if ("fixed-range".equals(metricType)) {
356                     double lower = doubleValue(lowerLimit);
357                     double upper = doubleValue(upperLimit);
358                     double defaultDouble =
359                         doubleValue(defaultValue);
360                     double required =
361                         doubleValue(requiredValue);
362                     FixedRangeMetric metric = 
363                         new FixedRangeMetric(metricName, abbreviation, description,
364                                              lower,upper,required);
365                     metric.setMetricValue(defaultDouble);
366                     return metric;
367                 }
368                 if ("boolean".equals(metricType)) {
369                     boolean defaultBoolean =
370                         booleanValue(defaultValue);
371                     boolean required =
372                         booleanValue(requiredValue);
373                     BooleanMetric metric = 
374                         new BooleanMetric(metricName, abbreviation, description,required);
375                     metric.setMetricValue(defaultBoolean);
376                     return metric;
377                 }
378                 if ("enumeration".equals(metricType)) {
379                     EnumeratedTypeMetric metric = 
380                         new EnumeratedTypeMetric(metricName, abbreviation, 
381                                                  description, possibleValues, requiredValue);
382                     metric.setMetricValue(defaultValue);
383                     return metric;
384                 }
385                 throw new Error("Invalid metric type: " + metricType);                
386             } catch (ConfigurationException ce) {
387                 throw new Error(ce.toString());
388             }            
389         }
390         
391     }
392     
393     /** 
394      * Configuration file parser handler. This is the SAX2 parser
395      * handler for parsing the XML configuration files for the system.
396      * It makes callbacks onto private methods on  SystemConfiguration
397      * to set the configuration data.
398      *
399      * @author kris wehner <kris@further.com>
400      */
401     private static class ConfigurationHandler extends DefaultHandler {        
402         /**
403          * The elementContents string contains the last parsed character
404          * data from the previous tag that was processed. This is used 
405          * to set specific data values when an endElement event is received.
406          */
407         private String elementContents;
408         
409         /**
410          * The current metric creator. This is used to register the configuration
411          * values as they are parsed, and then registered in the metric creator
412          * map when a </metric> is encountered.
413          */
414         private MetricCreator metricCreator;        
415         
416         /**
417          * The start element handler for the parser. 
418          */
419         public void startElement(String uri, String localName, 
420                                  String qName, Attributes attributes) {
421                                      
422            if ("config".equals(qName)) {
423                // Start of the configuration, extract the source root
424                rootSourceDirectory = 
425                 attributes.getValue("srcroot");
426                category.debug("Root source directory is " + rootSourceDirectory);
427            }
428            if ("metric".equals(qName)) {
429                // Start metric, create a new metric creator and register
430                // the metric type
431                metricCreator = new MetricCreator();
432                metricCreator.setMetricType(attributes.getValue("type"));
433                category.debug("New metric, type is " + attributes.getValue("type"));
434            }
435            if ("source".equals(qName)) {
436                // This is the source formatting flag, and has to be either 
437                // "true" or "false"
438                formatSource = Boolean.valueOf(attributes.getValue("format")).booleanValue();
439                category.debug("Format source is " + formatSource);
440            }
441         }
442         
443         public void characters(char[] ch, int start, int length) {
444             char[] chars = new char[length];
445             int j = 0;
446             for (int i = start; i < length; i++) {
447                 chars[j++] = ch[i];
448             }
449             elementContents = new String(chars);
450             category.debug("Element contents = " + elementContents);
451         }
452         
453         public void endElement(String uri, String localName, String qName) {
454             if ("metric".equals(qName)) {
455                 metricCreatorMap.put(metricCreator.getMetricAbbreviation(),metricCreator);
456                 category.debug("Register metric creator for " + metricCreator.getMetricAbbreviation());
457             }
458             if ("name".equals(qName)) {
459                 metricCreator.setMetricName(elementContents);
460                 category.debug("Metric name is " + elementContents);
461             }
462             if ("abbreviation".equals(qName)) {
463                 metricCreator.setMetricAbbreviation(elementContents);
464                 category.debug("Metric abbreviation is " + elementContents);
465             }
466             if ("description".equals(qName)) {
467                 metricCreator.setDescription(elementContents);
468                 category.debug("Metric description is " + elementContents);
469             }
470             if ("default".equals(qName)) {
471                 metricCreator.setDefaultValue(elementContents);
472                 category.debug("Default value is " + elementContents);
473             }
474             if ("required-value".equals(qName)) {
475                 metricCreator.setRequiredValue(elementContents);
476                 category.debug("Required value is " + elementContents);
477             }
478             if ("value".equals(qName)) {
479                 metricCreator.addValue(elementContents);
480                 category.debug("Possible value is " + elementContents);
481             }
482             if ("lowerlimit".equals(qName)) {
483                 metricCreator.setLowerLimit(elementContents);
484                 category.debug("Lower limit is " + elementContents);
485             }
486             if ("upperlimit".equals(qName)) {
487                 metricCreator.setUpperLimit(elementContents);
488                 category.debug("Upper limit is " + elementContents);
489             }
490             if ("audit-frequency".equals(qName)) {
491                 try {
492                     auditFrequency = Long.valueOf(elementContents).longValue();
493                 } catch (NumberFormatException nfe) {
494                     auditFrequency = 0;
495                 }
496                 category.debug("Audit frequency is " + auditFrequency);
497             }
498             if ("srcext".equals(qName)) {
499                 SourceFilenameFilter.registerSourceExtension(elementContents);
500                 category.debug("Register source extension: " + elementContents);
501             }                      
502             if ("ignore-directory".equals(qName)) {
503                 addIgnoredDirectory(elementContents);
504                 category.debug("Register ignored directory " + elementContents);
505             }
506             if ("foreground-color".equals(qName)) {
507                 foregroundColor = elementContents;
508                 category.debug("Foreground color is set to " + foregroundColor);
509             }
510             if ("background-color".equals(qName)) {
511                 backgroundColor = elementContents;
512                 category.debug("Background color is set to " + backgroundColor);
513             }
514             if ("link-color".equals(qName)) {
515                 linkColor = elementContents;
516                 category.debug("Link color is set to " + linkColor);
517             }
518             if ("vlink-color".equals(qName)) {
519                 vlinkColor = elementContents;
520                 category.debug("VLink color is set to " + vlinkColor);
521             }
522             if ("keyword-color".equals(qName)) {
523                 keywordColor = elementContents;
524                 category.debug("Keyword color is set to " + keywordColor);
525             }
526             if ("comment-color".equals(qName)) {
527                 commentColor = elementContents;
528                 category.debug("Comment color is set to " + commentColor);
529             }
530             if ("passed-color".equals(qName)) {
531                 passedAuditColor = elementContents;
532                 category.debug("Passing audit color is set to " + passedAuditColor);
533             }
534             if ("failed-color".equals(qName)) {
535                 failedAuditColor = elementContents;
536                 category.debug("Failing audit color is set to " + failedAuditColor);
537             }
538             if ("unaudited-color".equals(qName)) {
539                 unauditedColor = elementContents;
540                 category.debug("Unaudited color is set to " + unauditedColor);
541             }            
542         }
543         
544         public void fatalError(SAXParseException ex) {
545             System.out.println("Error parsing configuration: line " + ex.getLineNumber() + " col " + ex.getColumnNumber() + ": " + ex.toString());
546         }
547         
548         public void error(SAXParseException ex) {
549             System.out.println("Error parsing configuration: line " + ex.getLineNumber() + " col " + ex.getColumnNumber() + ": " + ex.toString());
550         }
551     }        
552     
553     /**
554      * Set the given directory name as an ignored directory, so it will not
555      * show up in source listings.
556      *
557      * @param directory The name of the directory to ignore
558      */
559     private static void addIgnoredDirectory(String directory) {
560         ignoredDirectories.add(directory);
561     }
562     
563     /**
564      * Is the given directory an ignored directory? If it is ignored, it 
565      * should not show up in directory listings.
566      *
567      * @param directory The directory to check for being in the ignore list
568      * @return true if the directory is ignored, false otherwise
569      */
570     public static boolean isIgnoredDirectory(String directory) {
571         return ignoredDirectories.contains(directory);
572     }
573     
574     /**
575      * Validate the entire set of metric creators and the root source directory.
576      * This is done at bootstrap
577      * to ensure configuration integrity, and causes the system to not start
578      * up if it fails. Once run, we can be sure that the metric creators are
579      * logically consistent and can be used in the factory methods.
580      */
581     private static void validateConfiguration() 
582         throws ConfigurationException {
583             for (Iterator i = metricCreatorMap.values().iterator(); i.hasNext(); ) {
584                 MetricCreator creator =
585                     (MetricCreator)i.next();
586                 creator.validate();
587             }
588             File rootDirectory = new File(rootSourceDirectory);
589             if (!rootDirectory.exists())
590                 throw new ConfigurationException("Root source directory does not exist");
591     }    
592     
593     /**
594      * Retreive the audit frequency for the source files in milliseconds. If the 
595      * source file audit is older than this value, the file should be reaudited.
596      *
597      * @return The audit frequency for the file, in milliseconds
598      */
599     public static long getAuditFrequency()  {
600         return auditFrequency;
601     }    
602     
603     /**
604      * Should the displayed source code be formatted using a pretty printer,
605      * or should it be displayed entirely unformatted as text/plain?
606      *
607      * @return true if the source should be displayed formatted and colored
608      */
609     public static boolean getFormatSource() {
610         return formatSource;
611     }
612     
613     /**
614      * Retreive the root directory for the source code to collect metrics for.
615      * This is the base of the source directory, and must exist.
616      *
617      * @return The string name of the root source directory
618      */
619     public static String getRootSourceDirectory() {
620         return rootSourceDirectory;
621     }
622     
623     /** 
624      * Get the foreground color that the user selected, in the format 
625      * XXXXXX, which is the hex RGB of the color without the leading #
626      * 
627      * @return The user configured foreground color
628      */
629     public static String getForegroundColor() {
630         return foregroundColor;
631     }
632     
633     /**
634      * Get the background color that the user selected.
635      *
636      * @return The user configured background color
637      * @see #getForegroundColor
638      */
639     public static String getBackgroundColor() {
640         return backgroundColor;
641     }
642 
643     /**
644      * Get the link color that the user selected.
645      *
646      * @return The user configured link color
647      * @see #getForegroundColor
648      */
649     public static String getLinkColor() {
650         return linkColor;
651     }    
652 
653     /**
654      * Get the vlink color that the user selected.
655      *
656      * @return The user configured vlink color
657      * @see #getForegroundColor
658      */
659     public static String getVlinkColor() {
660         return vlinkColor;
661     }        
662     
663     /**
664      * Get the keyword color that the user selected.
665      *
666      * @return The user configured keyword color
667      * @see #getForegroundColor
668      */
669     public static String getKeywordColor() {
670         return keywordColor;
671     }
672 
673     /**
674      * Get the comment color that the user selected.
675      *
676      * @return The user configured comment color
677      * @see #getForegroundColor
678      */
679     public static String getCommentColor() {
680         return commentColor;
681     }    
682     
683     /**
684      * Get the passing audit color the user selected
685      *
686      * @return The user configured passing audit color
687      * @see #getForegroundColor
688      */
689     public static String getPassedAuditColor() {
690         return passedAuditColor;
691     }
692 
693     /**
694      * Get the failing audit color the user selected
695      *
696      * @return The user configured failing audit color
697      * @see #getForegroundColor
698      */
699     public static String getFailedAuditColor() {
700         return failedAuditColor;
701     }    
702     
703     /**
704      * Get the unaudited color the user selected
705      *
706      * @return The user configured unaudited color
707      * @see #getForegroundColor
708      */
709     public static String getUnauditedColor() {
710         return unauditedColor;
711     }    
712     
713     /**
714      * Create a new set of metrics, initializing defaults and ranges. This 
715      * set is determined by the system configuration, and will be used 
716      * for all source audits in the system. 
717      *
718      * @return A list of metrics, initialized and ordered in the same order
719      *         as they were specified in the configuration
720      */
721     public static List createMetrics() {
722         List metricList = new LinkedList();
723         for (Iterator i = metricCreatorMap.keySet().iterator(); i.hasNext(); ) {
724             String key = (String)i.next();
725             MetricCreator creator = (MetricCreator)metricCreatorMap.get(key);
726             metricList.add(creator.createMetric());
727         }
728         return metricList;
729     }
730     
731     /**
732      * Create a metric for a given metric abbreviation. This is the simple 
733      * factory method used for individual metric creation.
734      *
735      * @param id The abbreviation for the metric to create
736      * @throws IllegalArgumentException If the metric for the given abbreviation
737      *         is not found.
738      */
739     public static SourceMetric createMetric(String id) {
740         if (!metricCreatorMap.containsKey(id)) 
741             throw new IllegalArgumentException("Metric not found for " + id);
742         MetricCreator creator =
743             (MetricCreator)metricCreatorMap.get(id);
744         return creator.createMetric();
745     }
746     
747     
748     /** 
749      * Load the configuration file at the given path. This loads all
750      * the system configuration data, including the metric types to 
751      * load, and all of the source directory paths.
752      *
753      * @param configurationFile The configuration file to load and parse
754      * @throws ConfigurationException If the configuration file cannot be parsed
755      */
756     public static void parseConfiguration(String configurationFile) 
757         throws ConfigurationException {
758         try {            
759             // This is pure xerces boilerplate to initialize the XML parser
760             SAXParserFactory parserFactory = SAXParserFactory.newInstance();
761             SAXParser saxParser = parserFactory.newSAXParser();
762             // Perform the parsing, which leaves the system with a complete
763             // configuration (source extensions, a root directory and
764             // a set of possibly inconsistent metric creators)
765             saxParser.parse(configurationFile,new ConfigurationHandler());            
766             // Ensure the metric creators are logically consistent so they
767             // can be used in the factory methods. If this passes, we
768             // have a valid system.
769             validateConfiguration();
770         } catch (IOException ex) {
771             if (category.isDebugEnabled())
772                 ex.printStackTrace();
773             throw new ConfigurationException(ex.getMessage());
774         } catch (ParserConfigurationException ex) {
775             if (category.isDebugEnabled())
776                 ex.printStackTrace();
777             throw new ConfigurationException(ex.getMessage());
778         } catch (SAXException ex)  {
779             if (category.isDebugEnabled())
780                 ex.printStackTrace();
781             throw new ConfigurationException(ex.getMessage());
782         }                
783     }
784     
785     /** 
786      * SystemConfiguration objects are not creatable. All public functionality
787      * of the SystemConfiguration is accessed through static functions.
788      */
789     private SystemConfiguration() {
790     }
791 
792 }