View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
42   *
43   *
44   * $Id$
45   */
46  package org.exolab.castor.builder;
47  
48  //--Castor imports
49  import java.io.File;
50  import java.io.FileInputStream;
51  import java.io.IOException;
52  import java.io.InputStream;
53  import java.util.ArrayList;
54  import java.util.Enumeration;
55  import java.util.Hashtable;
56  import java.util.List;
57  import java.util.Properties;
58  import java.util.StringTokenizer;
59  
60  import org.apache.commons.logging.Log;
61  import org.apache.commons.logging.LogFactory;
62  import org.castor.core.util.AbstractProperties;
63  import org.castor.core.util.Messages;
64  import org.castor.xml.JavaNaming;
65  import org.castor.xml.JavaNamingImpl;
66  import org.castor.xml.XMLProperties;
67  
68  /**
69   * The configuration for the SourceGenerator.
70   * HACK this class is a configuration but does not base on Castor
71   * Configuration! Raised CASTOR-2195 to solve this issue.
72   *
73   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
74   * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
75   * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
76   */
77  public class BuilderConfiguration {
78      /**
79       * The <a href="http://jakarta.apache.org/commons/logging/">Jakarta
80       * Commons Logging</a> instance used for all logging.
81       */
82      private static final Log LOG = LogFactory.getLog(BuilderConfiguration.class);
83  
84      /** String representation of directory self pointer. */
85      private static final String SELF_DIRECTORY = "./";
86      
87      /** Length of string representation of directory self pointer. */
88      private static final int SELF_DIRECTORY_LENGTH = SELF_DIRECTORY.length();
89  
90      /** String representation of directory parent pointer. */
91      private static final String PARENT_DIRECTORY = "../";
92  
93      /** Length of string representation of directory parent pointer. */
94      private static final int PARENT_DIRECTORY_LENGTH = PARENT_DIRECTORY.length();
95  
96      /**
97       * Names of properties used in the configuration file.
98       */
99      public static class Property {
100         /**
101          * Property specifying whether or not to generate source code for bound
102          * properties. Currently all properties will be treated as bound
103          * properties if this flag is set to true. A value of 'true' enables
104          * bound properties.
105          *
106          * <pre>
107          * org.exolab.castor.builder.boundproperties
108          * </pre>
109          */
110         public static final String BOUND_PROPERTIES =
111             "org.exolab.castor.builder.boundproperties";
112 
113         /**
114          * Property specifying whether to implement EnumeratedTypeAccess
115          * interface for all generated enumerated type classes.
116          *
117          * <pre>
118          * org.exolab.castor.builder.enumTypeAccessInterface
119          * </pre>
120          */
121         public static final String ENUM_TYPE_ACCESS_INTERFACE =
122             "org.exolab.castor.builder.enumTypeAccessInterface";
123 
124         /**
125          * Property specifying whether or not to generate source code for extra
126          * collection methods.
127          *
128          * <pre>
129          * org.exolab.castor.builder.extraCollectionMethods
130          * </pre>
131          */
132         public static final String EXTRA_COLLECTION_METHODS =
133             "org.exolab.castor.builder.extraCollectionMethods";
134 
135         /**
136          * Property specifying the super class for all generated classes.
137          *
138          * <pre>
139          * org.exolab.castor.builder.superclass
140          * </pre>
141          */
142         public static final String SUPER_CLASS =
143             "org.exolab.castor.builder.superclass";
144 
145         /**
146          * Property specifying how element's and type's are mapped into a Java
147          * class hierarchy by the Source Generator. The value must contain one
148          * of the following. 'element' outputs a Java class hierarchy based on
149          * element names used in the XML Schema. This is the default. 'type'
150          * outputs a Java class hierarchy based on the type information defined
151          * in the XML Schema.
152          *
153          * <pre>
154          * org.exolab.castor.builder.javaclassmapping
155          * </pre>
156          */
157         public static final String JAVA_CLASS_MAPPING =
158             "org.exolab.castor.builder.javaclassmapping";
159 
160         /**
161          * Property listing mapping between XML namespaces and Java packages.
162          */
163         public static final String NAMESPACE_PACKAGES_OLD =
164             "org.exolab.castor.builder.nspackages";
165 
166         /**
167          * Property listing mapping between XML namespaces and Java packages.
168          */
169         public static final String NAMESPACE_PACKAGES =
170             "org.exolab.castor.xml.nspackages";
171 
172         /**
173          * Property specifying if we want to have the equals method generated
174          * for each generated class.
175          */
176         public static final String EQUALS_METHOD =
177             "org.exolab.castor.builder.equalsmethod";
178 
179         /**
180          * Property specifying if we want to use Wrapper Objects instead of
181          * primitives (eg java.lang.Float instead of float).
182          */
183         public static final String WRAPPER =
184             "org.exolab.castor.builder.primitivetowrapper";
185 
186         /**
187          * Property specifying if we want to have a 'public static final String'
188          * generated for each attribute and element name used within a class
189          * descriptor.
190          */
191         public static final String CLASS_DESC_FIELD_NAMES =
192             "org.exolab.castor.builder.classdescfieldnames";
193 
194         /**
195          * Property specifying whether the Java sources generated should be 1.4
196          * or 5.0 compliant.
197          */
198         public static final String JAVA_VERSION =
199             "org.exolab.castor.builder.javaVersion";
200         
201         /**
202          * Forces the code generator to create 'old' Java 1.4 enumeration classes instead 
203          * of Java 5 enums for &lt;simpleType&gt; enumerations, even in Java 5 mode.
204          */
205         public static final String FORCE_JAVA4_ENUMS =
206             "org.exolab.castor.builder.forceJava4Enums";
207 
208         /**
209          * The name of the configuration file.
210          *
211          * <pre>
212          * castor.properties
213          * </pre>
214          */
215         public static final String CONFIG_FILENAME_PROPERTY =
216             "castorbuilder.properties";
217 
218         /**
219          * Maximum number of constant definitions within one file. This property
220          * is used to allow the user to configure the maximum number of
221          * constant definitions (within a Java class as generated as a result of
222          * an enumeration); default is 1000. Is this number if exceeded, no constants
223          * will be generated anymore.
224          *
225          * <pre>
226          * org.exolab.castor.builder.maxNumberOfConstants
227          * </pre>
228          */
229         public static final String MAX_CONSTANTS_PROPERTY =
230             "org.exolab.castor.builder.maxNumberOfConstants";
231 
232         /**
233          * Resource to load from the JAR file to load our defaults.
234          */
235         static final String RESOURCE_NAME =
236             "/org/exolab/castor/builder/castorbuilder.properties";
237 
238         /**
239          * Registered class name conflict resolution strategies.
240          *
241          * <pre>
242          * org.exolab.castor.builder.nameConflictStrategies
243          * </pre>
244          */
245         public static final String NAME_CONFLICT_STRATEGIES =
246             "org.exolab.castor.builder.nameConflictStrategies";
247 
248         /**
249          * Property specifying whether automatic class name conflict resolution
250          * should be used or not; defaults to false.
251          *
252          * <pre>
253          * org.exolab.castor.builder.automaticConflictResolution
254          * </pre>
255          */
256         public static final String AUTOMATIC_CONFLICT_RESOLUTION = 
257             "org.exolab.castor.builder.automaticConflictResolution";
258 
259         /**
260          * Property specifying the 'string' used in type strategy to be inserted 
261          * between the actual element name and the type name (during automatic class name 
262          * conflict resolution); defaults to 'By'.
263          *
264          * <pre>
265          * org.exolab.castor.builder.automaticConflictResolutionTypeSuffix
266          * </pre>
267          */
268         public static final String AUTOMATIC_CONFLICT_RESOLUTION_TYPE_SUFFIX = 
269             "org.exolab.castor.builder.automaticConflictResolutionTypeSuffix";
270         
271         /**
272          * Property enlisting the supported {@link JClassPrinterFactory} instances available 
273          * for creating {@link JClassPrinter} instances.
274          */
275         public static final String JCLASSPRINTER_FACTORIES = 
276             "org.exolab.castor.builder.jclassPrinterFactories";
277 
278         /**
279          * Property specifying whether extra members/methods for extracting XML schema
280          * documentation should be made available; defaults to false.
281          * <pre>
282          * org.exolab.castor.builder.extraDocumentationMethods=false
283          * </pre>
284          */
285         public static final String EXTRA_DOCUMENTATION_METHODS = 
286             "org.exolab.castor.builder.extraDocumentationMethods";
287 
288         /**
289          * Property specifying whether cycle breaker code should be added to
290          * generated methods 'equals' and 'hashcode'; defaults to <i>true</i>.
291          * 
292          * <pre>
293          * org.exolab.castor.builder.useCycleBreaker = true
294          * </pre>
295          */
296         public static final String USE_CYCLE_BREAKER = "org.exolab.castor.builder.useCycleBreaker";
297 
298         /**
299          * Property specifying whether for Java field names the old naming conventions
300          * should be used; defaults to <i>true</i>.
301          * 
302          * <pre>
303          * org.exolab.castor.builder.field-naming.old = true
304          * </pre>
305          */
306         public static final String USE_OLD_FIELD_NAMING = "org.exolab.castor.builder.field-naming.old";
307         
308     } //--Property
309 
310     /**
311      * String value of false.
312      */
313     private static final String FALSE = "false";
314 
315     /**
316      * String value of true.
317      */
318     private static final String TRUE = "true";
319 
320     /**
321      * String value of element binding property.
322      */
323     private static final String ELEMENT_VALUE = "element";
324 
325     /**
326      * String value of type binding property.
327      */
328     private static final String TYPE_VALUE = "type";
329 
330     /**
331      * The default properties loaded from the configuration file.
332      */
333     private Properties _defaultProps = null;
334 
335     /**
336      * Our properties after all configuration has been loaded.
337      */
338     private Properties _localProps = null;
339 
340     /**
341      * Namespace URL to Java package mapping.
342      */
343     private Hashtable<String, String> _nspackages = new Hashtable<String, String>();
344 
345     /**
346      * schemaLocation to Java package mapping.
347      */
348     private Hashtable<String, String> _locpackages = new Hashtable<String, String>();
349 
350     /** JavaNaming to be used. */
351     private JavaNaming _javaNaming;
352    
353     /**
354      * hooks for (external) tools to add custom
355      * annotations to fields, classes and enumConstants 
356      * during source generation.
357      */
358     private List<AnnotationBuilder> _annotationBuilders = new ArrayList<AnnotationBuilder>();
359 
360     //------------------/
361 
362     /**
363      * Creates a default BuilderConfiguration.
364      */
365     public BuilderConfiguration() {
366         super();
367         getDefault();
368         _localProps = new Properties(_defaultProps);
369     } //-- BuilderConfiguration
370 
371     /**
372      * Returns the default configuration file. Changes to the returned
373      * properties set will affect all Castor functions relying on the default
374      * configuration.
375      *
376      * @return The default configuration
377      */
378     public final synchronized Properties getDefault() {
379         if (_defaultProps == null) {
380             load();
381         }
382         return _defaultProps;
383     } //-- getDefault
384 
385     /**
386      * Returns a property from the default configuration file. Equivalent to
387      * calling <tt>getProperty</tt> on the result of {@link #getDefault}.
388      *
389      * @param name
390      *            The property name
391      * @param defValue
392      *            The property's default value
393      * @return The property's value
394      */
395     public final String getProperty(final String name, final String defValue) {
396         return _localProps.getProperty(name, defValue);
397     } //-- getProperty
398 
399     /**
400      * Returns true if bound properties are enabled.
401      * <p>
402      * Enabling bound properties is controlled via the
403      * org.exolab.castor.builder.boundproperties item in the
404      * castorbuilder.properties file. The value is either 'true' or 'false'.
405      *
406      * @return true if bound properties are enabled.
407      */
408     public final boolean boundPropertiesEnabled() {
409         return TRUE.equalsIgnoreCase(_localProps.getProperty(Property.BOUND_PROPERTIES));
410     } //-- boundPropertiesEnabled
411 
412     /**
413      * Returns true if we generate an 'equals' method for each generated class.
414      * <p>
415      * Enabling this property is controlled via the
416      * org.exolab.castor.builder.equalsmethod item in the
417      * castorbuilder.properties file. The value is either 'true' or 'false'.
418      *
419      * @return true if bound properties are enabled.
420      */
421     public final boolean equalsMethod() {
422         return TRUE.equalsIgnoreCase(_localProps.getProperty(Property.EQUALS_METHOD));
423     } //-- equalsMethod
424 
425     /**
426      * Sets the 'equalsmethod' property.
427      *
428      * @param equals The value we want to use.
429      */
430      public final void setEqualsMethod(final boolean equals) {
431         String value = (equals) ? TRUE : FALSE;
432         _localProps.setProperty(Property.EQUALS_METHOD, value);
433      } //-- setEqualsMethod
434 
435     /**
436      * Returns true if we generate a 'public static final String' for the name
437      * of each attribute and element described by the class descriptor
438      * <p>
439      * Enabling this property is controlled via the
440      * org.exolab.castor.builder.classdescfieldnames item in the
441      * castorbuilder.properties file. The value is either 'true' or 'false'.
442      *
443      * @return true if bound properties are enabled.
444      */
445     public final boolean classDescFieldNames() {
446         return _localProps.getProperty(Property.CLASS_DESC_FIELD_NAMES, "").equalsIgnoreCase(TRUE);
447     } //-- classDescFieldNames
448 
449     /**
450      * Returns true if extra methods for collection fields should be generated.
451      * Such methods include set/get methods for the actual collection in
452      * addition to the array methods.
453      * <p>
454      * Enabling extra collection methods is controlled via the
455      * org.exolab.castor.builder.extraCollectionMethods property in the
456      * castorbuilder.properties file. The value is either 'true' or 'false'.
457      *
458      * @return true if extra collection methods are enabled.
459      */
460     public final boolean generateExtraCollectionMethods() {
461         return _localProps.getProperty(Property.EXTRA_COLLECTION_METHODS, "")
462                 .equalsIgnoreCase(TRUE);
463     } //-- generateExtraCollectionMethods
464 
465     /**
466      * Sets the 'classDescFieldNames' property.
467      *
468      * @param classDescFieldNames
469      *            the value we want to ues
470      */
471      public final void setClassDescFieldNames(final boolean classDescFieldNames) {
472         String value = (classDescFieldNames) ? TRUE : FALSE;
473         _localProps.setProperty(Property.CLASS_DESC_FIELD_NAMES, value);
474      } //-- setClassDescFieldNames
475 
476      /**
477       * Returns true if primitive types have to be used as Objects (eg.
478       * replacing <code>float</code> by <code>java.lang.Float</code>).
479       * @return true if primitive types have to be used as Objects.
480       */
481     public final boolean usePrimitiveWrapper() {
482         return _localProps.getProperty(Property.WRAPPER, "").equalsIgnoreCase(TRUE);
483     } //-- usePrimitiveWrapper
484 
485     /**
486      * Sets the 'primitivetowrapper' property.
487      *
488      * @param wrapper the value we want to use.
489      */
490     public final void setPrimitiveWrapper(final boolean wrapper) {
491         String value = (wrapper) ? TRUE : FALSE;
492         _localProps.setProperty(Property.WRAPPER, value);
493     } //-- setPrimitiveWrapper
494 
495     /**
496      * Returns true if we generate the implements EnumeratedTypeAccess interface
497      * for enumerated type classes. The value is either 'true' or 'false'
498      *
499      * @return true if use enumerated type interface is enabled
500      */
501     public final boolean useEnumeratedTypeInterface() {
502         return TRUE.equalsIgnoreCase(_localProps.getProperty(Property.ENUM_TYPE_ACCESS_INTERFACE));
503     } //-- useEnumeratedTypeInterface
504 
505     /**
506      * Returns true if we generate the implements EnumeratedTypeAccess interface
507      * for enumerated type classes. The value is either 'true' or 'false'
508      *
509      * @return true if use enumerated type interface is enabled
510      */
511     public final boolean useJava50() {
512         return "5.0".equalsIgnoreCase(_localProps.getProperty(Property.JAVA_VERSION, "1.4"));
513     } //-- useEnumeratedTypeInterface
514     
515     /**
516      * Indicates what kind of enumeration should be created for 
517      * &lt;xs:simpleType&gt; enumerations.
518      *
519      * @return true if Java 5 source code should be generated.
520      */
521     public final boolean useJava5Enums() {
522         return useJava50() && FALSE.equalsIgnoreCase(
523                 _localProps.getProperty(Property.FORCE_JAVA4_ENUMS, FALSE));
524     }
525 
526     /**
527      * Add support to set java version programmatically.
528      */
529     public final void forceUseJava50() {
530         _localProps.setProperty(Property.JAVA_VERSION, "5.0");
531     }
532         
533     /**
534      * Returns true if extra methods for accessing XML schema documentation should
535      * be generated; default to 'false'.
536      *
537      * @return true if if extra methods for accessing XML schema documentation should be generated
538      */
539     public final boolean generateExtraDocumentationMethods() {
540         String extraDocumentationMethods = 
541             _localProps.getProperty(Property.EXTRA_DOCUMENTATION_METHODS, "false");
542         return new Boolean(extraDocumentationMethods).booleanValue();
543     }
544 
545     /**
546      * Returns true if the class {@link CycleBreaker} should be used during code generation; 
547      * defaults to 'true'.
548      *
549      * @return true if the class {@link CycleBreaker} should be used during code generation
550      */
551     public final boolean useCycleBreaker() {
552         return Boolean.valueOf(_localProps.getProperty(Property.USE_CYCLE_BREAKER, "true"));
553     }
554 
555     /**
556      * Returns the maximum number of static constant definitions that are
557      * acceptable within one class file; default is 1000.
558      *
559      * @return the maximum number of static constant definitions acceptable within
560      *    one class file
561      */
562     public final int getMaximumNumberOfConstants() {
563         String property = _localProps.getProperty(Property.MAX_CONSTANTS_PROPERTY, "1000");
564         return Integer.valueOf(property).intValue();
565     }
566 
567     /**
568      * Sets the 'enumTypeAccessInterface' property.
569      *
570      * @param flag the value we want to use
571      */
572     public final void setUseEnumeratedTypeInterface(final boolean flag) {
573         String value = (flag) ? TRUE : FALSE;
574         _localProps.setProperty(Property.ENUM_TYPE_ACCESS_INTERFACE, value);
575     } //-- setUseEnumeratedTypeInterface
576 
577     /**
578      * Tests the org.exolab.castor.builder.javaclassmapping property for the
579      * 'element' value.
580      *
581      * @return True if the Source Generator is mapping schema elements to Java
582      *         classes.
583      */
584     public boolean mappingSchemaElement2Java() {
585         String value = _localProps.getProperty(Property.JAVA_CLASS_MAPPING, "");
586         return ELEMENT_VALUE.equalsIgnoreCase(value);
587     } //-- mappingSchemaElement2Java
588 
589     /**
590      * Tests the org.exolab.castor.builder.javaclassmapping property for the 'type' value.
591      *
592      * @return True if the Source Generator is mapping schema types to Java classes.
593      */
594     public boolean mappingSchemaType2Java() {
595         String value = _localProps.getProperty(Property.JAVA_CLASS_MAPPING, "");
596         return TYPE_VALUE.equalsIgnoreCase(value);
597     } //-- mappingSchemaType2Java
598 
599     /**
600      * Overrides the current set of properties with the given properties. Once
601      * the properties are set, only a copy will be uses, so any changes to the
602      * given properties file after the fact will go unnoticed.
603      *
604      * @param properties
605      *            the Properties file
606      */
607     public final void setDefaultProperties(final Properties properties) {
608         Properties defaults = null;
609         if (properties == null) {
610             defaults = _defaultProps;
611         } else {
612             defaults = new Properties(_defaultProps);
613             Enumeration<?> enumeration = properties.keys();
614             while (enumeration.hasMoreElements()) {
615                 String name = (String) enumeration.nextElement();
616                 defaults.setProperty(name, properties.getProperty(name));
617             }
618         }
619         _localProps = new Properties(defaults);
620         processNamespacePackageMappings(
621                 _localProps.getProperty(Property.NAMESPACE_PACKAGES_OLD, ""));
622         processNamespacePackageMappings(
623                 _localProps.getProperty(Property.NAMESPACE_PACKAGES, ""));
624     } //-- setDefaultProperties
625 
626     /**
627      * Sets the namespace to package mapping.
628      *
629      * @param ns the namespace URI to map
630      * @param packageName the package name
631      */
632     public final void setNamespacePackageMapping(final String ns, final String packageName) {
633         _nspackages.put(ns, packageName);
634     } //-- setNamespcaePackageMapping
635 
636     /**
637      * Sets the schemaLocation to package mapping.
638      *
639      * @param schemaLocation the schemaLocation to map
640      * @param packageName the package name to map to
641      */
642     public final void setLocationPackageMapping(
643             final String schemaLocation, final String packageName) {
644         _locpackages.put(schemaLocation, packageName);
645     }
646     
647     /**
648      * Returns a String representing the list of {@link JClassPrinterFactory} instances
649      * configured in the Castor XML code generator property file.
650      * @return the list of {@link JClassPrinterFactory} instances as configured, as string.
651      */
652     public final String getJClassPrinterFactories() {
653         return _localProps.getProperty(Property.JCLASSPRINTER_FACTORIES);
654     }
655 
656 
657     /**
658      * Called by {@link #getDefault} to load the configuration the first time.
659      * Will not complain about inability to load configuration file from one of
660      * the default directories, but if it cannot find the JAR's configuration
661      * file, will throw a run time exception.
662      */
663     protected final synchronized void load() {
664         if (_defaultProps == null) {
665             //-- load defaults from JAR
666             _defaultProps = loadProperties(
667                     Property.RESOURCE_NAME, Property.CONFIG_FILENAME_PROPERTY);
668 
669             //-- load local defaults
670 
671             boolean found = false;
672 
673             // Get overriding configuration from the classpath, ignore if not found.
674             // If found, merge any existing properties.
675             try {
676                 InputStream is = SourceGenerator.class.getResourceAsStream(
677                         "/" + Property.CONFIG_FILENAME_PROPERTY);
678                 if (is != null) {
679                     found = true;
680                     _defaultProps.load(is);
681                     is.close();
682                 }
683             } catch (Exception except) {
684                 //-- do nothing
685             }
686 
687             //-- if not found, either it doesn't exist, or "." is not part of the
688             //-- class path, try looking at local working directory
689             if (!found) {
690                 try {
691                     File file = new File(Property.CONFIG_FILENAME_PROPERTY);
692                     if (file.exists() && file.canRead()) {
693                         InputStream is = new FileInputStream(file);
694                         _defaultProps.load(is);
695                         is.close();
696                     }
697                 } catch (Exception except) {
698                     //-- do nothing
699                 }
700             }
701         }
702 
703         AbstractProperties rtconf =  XMLProperties.newInstance();
704 
705         // Parse XML namespace and package list from both castor.properties and
706         // castorbuilder.properties
707         processNamespacePackageMappings(rtconf.getString(Property.NAMESPACE_PACKAGES_OLD, ""));
708         processNamespacePackageMappings(rtconf.getString(Property.NAMESPACE_PACKAGES, ""));
709         processNamespacePackageMappings(_defaultProps.getProperty(
710                 Property.NAMESPACE_PACKAGES_OLD, ""));
711         processNamespacePackageMappings(_defaultProps.getProperty(
712                 Property.NAMESPACE_PACKAGES, ""));
713 
714         //-- backward compatibility with 0.9.3.9
715         String prop = _defaultProps.getProperty(
716                 JavaNamingImpl.UPPER_CASE_AFTER_UNDERSCORE_PROPERTY, null);
717         if (prop != null) {
718             /*
719              * TODO: joachim: Argh! this shouldn't exist and it shouldn't be here! Setting a
720              * static attribute into a class because somewhere later the class is instantiated
721              * and use but then the attribute is required... I need to sort out the order how
722              * objects are created...
723              */
724             JavaNamingImpl._upperCaseAfterUnderscore = Boolean.valueOf(prop).booleanValue();
725         }
726     } //-- load
727 
728     /**
729      * Gets a Java package to an XML namespace URL.
730      * @param nsURL the XML namespace URL to convert into a Java package name
731      * @return a Java package name
732      */
733     public final String lookupPackageByNamespace(final String nsURL) {
734         String namespaceURL = (nsURL == null) ? "" : nsURL;
735 
736         // Lookup Java package via NS
737         String javaPackage = _nspackages.get(namespaceURL);
738         if (javaPackage == null) {
739             return "";
740         }
741         return javaPackage;
742     } //-- lookupPackageNamespace
743 
744     /**
745      * Converts a schema location into a Java package.
746      *
747      * @param schemaLocation
748      *            the Schema location to use to look up the Java package
749      * @return a Java package name
750      */
751     public final String lookupPackageByLocation(final String schemaLocation) {
752         if (schemaLocation == null) {
753             return "";
754         }
755 
756         // Lookup Java package via schemaLocation
757         //--Full path
758         String javaPackage = _locpackages.get(schemaLocation);
759         if (javaPackage == null) {
760             String cleanedSchemaLocation = schemaLocation;
761             //--maybe a relative schemaLocation was given
762             while (schemaLocation.startsWith(".")) {
763                  if (schemaLocation.startsWith(SELF_DIRECTORY)) {
764                      cleanedSchemaLocation = schemaLocation.substring(SELF_DIRECTORY_LENGTH);
765                  } else if (schemaLocation.startsWith(PARENT_DIRECTORY)) {
766                      cleanedSchemaLocation = schemaLocation.substring(PARENT_DIRECTORY_LENGTH);
767                  }
768             }
769             Enumeration<String> keys = _locpackages.keys();
770             boolean found = false;
771             while (keys.hasMoreElements() && !found) {
772                 String key = keys.nextElement();
773                 if (cleanedSchemaLocation.endsWith(key)) {
774                     javaPackage = _locpackages.get(key);
775                     found = true;
776                 }
777             }
778             if (javaPackage == null) {
779                 javaPackage = "";
780             }
781         }
782 
783         return javaPackage;
784     } //-- lookupPackageLocation
785 
786     /**
787      * processes the given String which contains namespace-to-package mappings.
788      *
789      * @param mappings the namespace-to-package mappings
790      */
791     protected final void processNamespacePackageMappings(final String mappings) {
792         if (mappings == null) {
793             return;
794         }
795 
796         StringTokenizer tokens = new StringTokenizer(mappings, ",");
797         while (tokens.hasMoreTokens()) {
798             String token = tokens.nextToken();
799             int sepIdx = token.indexOf('=');
800             if (sepIdx < 0) {
801                 continue;
802             }
803 
804             String ns = token.substring(0, sepIdx).trim();
805             String javaPackage = token.substring(sepIdx + 1).trim();
806             _nspackages.put(ns, javaPackage);
807         }
808     } //-- processNamespacePackageMappings
809 
810     /**
811      * indicates whether automatic class name conflict resolution during 
812      * XML code generation should take place or not.
813      * @return True if automatic mode should be used.
814      */
815     public boolean isAutomaticConflictResolution() {
816         String automaticConflictResolutionProperty = 
817             _localProps.getProperty(Property.AUTOMATIC_CONFLICT_RESOLUTION, "false");
818         return "true".equalsIgnoreCase(automaticConflictResolutionProperty);
819     }
820 
821     /**
822      * Returns the type 'suffix' used for the type strategy during automatic class name 
823      * conflict resolution during XML code generation; default to "" unless a value is specified.
824      * @return The type suffix to be inserted between element name and type name
825      */
826     public String getAutomaticConflictResolutionTypeSuffix() {
827         return _localProps.getProperty(Property.AUTOMATIC_CONFLICT_RESOLUTION_TYPE_SUFFIX, "");
828     }
829 
830     /**
831      * To set the {@link JavaNaming} implementation to be used.
832      * @param javaNaming JavaNaming implementation to be used
833      * @since 1.1.3
834      */
835     public void setJavaNaming(final JavaNaming javaNaming) {
836         _javaNaming = javaNaming;
837     }
838     
839     /**
840      * To get the {@link JavaNaming} implementation to be used.
841      * @return JavaNaming implementation to be used
842      * @since 1.1.3
843      */
844     public JavaNaming getJavaNaming() {
845         return _javaNaming;
846     }
847     
848     /**
849      * adds a custom annotation builder.
850      * @param annotationBuilder the builder
851      */
852     public void addAnnotationBuilder(final AnnotationBuilder annotationBuilder) {
853         this._annotationBuilders.add(annotationBuilder);
854     }
855     
856     /**
857      * returns all applied annotation builders.
858      * @return a array of builders for type convenience
859      */
860     public AnnotationBuilder[] getAnnotationBuilders() {
861         return
862             this._annotationBuilders.toArray(
863                     new AnnotationBuilder[this._annotationBuilders.size()]);
864     }
865 
866     /**
867      * Load the configuration will not complain about inability to load
868      * configuration file from one of the default directories, but if
869      * it cannot find the JAR's configuration file, will throw a
870      * run time exception.
871      * 
872      * @param resourceName Name of the source.
873      * @param fileName Name of the configuration file.
874      * @return A {@link Properties} instance holding the actual XML code generator configuration.
875      */
876     public static Properties loadProperties(final String resourceName, final String fileName) {
877         File        file;
878         Properties properties = new Properties();
879 
880         boolean found = false;
881         
882         // Get detault configuration from the Castor JAR.
883         // Complain if not found.
884         InputStream resourceStream = null;
885         try {
886             resourceStream = AbstractProperties.class.getResourceAsStream(resourceName); 
887             properties.load(resourceStream);
888             
889             //-- debug information:
890             //URL url = Configuration.class.getResource( resourceName );
891             //System.out.println("loading configuration: " + url.toExternalForm());
892             //-- end debug information
893             
894             found = true;
895         } catch (Exception except) {
896             // Do nothing as we will check classpath 
897             // and java lib directory below
898         } finally {
899             if (resourceStream != null) {
900                 try {
901                     resourceStream.close();
902                 } catch (IOException e) {
903                     LOG.warn("Problem closing stream for " + resourceName);
904                 }
905             }
906         }
907 
908         // Get overriding configuration from the Java
909         // library directory, ignore if not found. If
910         // found merge existing properties.
911         String javaHome = null;
912         try {
913             javaHome = System.getProperty("java.home");
914         } catch (SecurityException e) {
915             // Not a critical error, but users will need to know if they need to 
916             // change their config.   
917             LOG.warn(Messages.format("conf.privilegesError", e));
918         } catch (Exception e) {
919             // As we will be trying something else later, record the error for setup purposes,
920             // but do not actually treat as a critical failure.
921             LOG.warn(Messages.format("conf.nonCriticalError", e));
922         }
923         
924         if (javaHome != null) {
925             InputStream fileStream = null;
926             try {      
927                 file = new File(javaHome, "lib");
928                 file = new File(file, fileName);
929                 if (file.exists()) {
930                     properties = new Properties(properties);
931                     fileStream = new FileInputStream(file);
932                     properties.load(fileStream);
933                     found = true;
934                 }      
935             } catch (SecurityException e) {
936                 // Not a critical error, but users will need to know if they need to change 
937                 // their config.   
938                 LOG.warn(Messages.format("conf.privilegesError", e));
939             } catch (IOException e) {
940                 // Report that we were unable to load the resource.
941                 LOG.warn(Messages.format("conf.nonCriticalError", e));
942             } finally {
943                 if (fileStream != null) {
944                     try {
945                         fileStream.close();
946                     } catch (IOException e) {
947                         LOG.warn("Problem closing stream for " + fileName);
948                     }
949                 }
950             }
951         }
952         
953 
954         //-- Cannot find any castor.properties file(s).
955         if (!found) {
956             throw new RuntimeException(Messages.format("conf.noDefaultConfigurationFile",
957                     fileName));
958         }
959 
960         return properties;
961     }
962 
963    public boolean useOldFieldNaming() {
964       return "true".equalsIgnoreCase(_localProps.getProperty(Property.USE_OLD_FIELD_NAMING, FALSE));
965    }
966 }