/* * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided * that the following conditions are met: * * 1. Redistributions of source code must retain copyright * statements and notices. Redistributions must also contain a * copy of this document. * * 2. Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. The name "Exolab" must not be used to endorse or promote * products derived from this Software without prior written * permission of Intalio, Inc. For written permission, * please contact info@exolab.org. * * 4. Products derived from this Software may not be called "Exolab" * nor may "Exolab" appear in their names without prior written * permission of Intalio, Inc. Exolab is a registered * trademark of Intalio, Inc. * * 5. Due credit should be given to the Exolab Project * (http://www.exolab.org/). * * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved. * * * $Id$ */ package org.exolab.castor.builder; //--Castor imports import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.castor.core.util.AbstractProperties; import org.castor.core.util.Messages; import org.castor.xml.JavaNaming; import org.castor.xml.JavaNamingImpl; import org.castor.xml.XMLProperties; /** * The configuration for the SourceGenerator. * HACK this class is a configuration but does not base on Castor * Configuration! Raised CASTOR-2195 to solve this issue. * * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a> * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a> * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $ */ public class BuilderConfiguration { /** * The <a href="http://jakarta.apache.org/commons/logging/">Jakarta * Commons Logging</a> instance used for all logging. */ private static final Log LOG = LogFactory.getLog(BuilderConfiguration.class); /** String representation of directory self pointer. */ private static final String SELF_DIRECTORY = "./"; /** Length of string representation of directory self pointer. */ private static final int SELF_DIRECTORY_LENGTH = SELF_DIRECTORY.length(); /** String representation of directory parent pointer. */ private static final String PARENT_DIRECTORY = "../"; /** Length of string representation of directory parent pointer. */ private static final int PARENT_DIRECTORY_LENGTH = PARENT_DIRECTORY.length(); /** * Names of properties used in the configuration file. */ public static class Property { /** * Property specifying whether or not to generate source code for bound * properties. Currently all properties will be treated as bound * properties if this flag is set to true. A value of 'true' enables * bound properties. * * <pre> * org.exolab.castor.builder.boundproperties * </pre> */ public static final String BOUND_PROPERTIES = "org.exolab.castor.builder.boundproperties"; /** * Property specifying whether to implement EnumeratedTypeAccess * interface for all generated enumerated type classes. * * <pre> * org.exolab.castor.builder.enumTypeAccessInterface * </pre> */ public static final String ENUM_TYPE_ACCESS_INTERFACE = "org.exolab.castor.builder.enumTypeAccessInterface"; /** * Property specifying whether or not to generate source code for extra * collection methods. * * <pre> * org.exolab.castor.builder.extraCollectionMethods * </pre> */ public static final String EXTRA_COLLECTION_METHODS = "org.exolab.castor.builder.extraCollectionMethods"; /** * Property specifying the super class for all generated classes. * * <pre> * org.exolab.castor.builder.superclass * </pre> */ public static final String SUPER_CLASS = "org.exolab.castor.builder.superclass"; /** * Property specifying how element's and type's are mapped into a Java * class hierarchy by the Source Generator. The value must contain one * of the following. 'element' outputs a Java class hierarchy based on * element names used in the XML Schema. This is the default. 'type' * outputs a Java class hierarchy based on the type information defined * in the XML Schema. * * <pre> * org.exolab.castor.builder.javaclassmapping * </pre> */ public static final String JAVA_CLASS_MAPPING = "org.exolab.castor.builder.javaclassmapping"; /** * Property listing mapping between XML namespaces and Java packages. */ public static final String NAMESPACE_PACKAGES_OLD = "org.exolab.castor.builder.nspackages"; /** * Property listing mapping between XML namespaces and Java packages. */ public static final String NAMESPACE_PACKAGES = "org.exolab.castor.xml.nspackages"; /** * Property specifying if we want to have the equals method generated * for each generated class. */ public static final String EQUALS_METHOD = "org.exolab.castor.builder.equalsmethod"; /** * Property specifying if we want to use Wrapper Objects instead of * primitives (eg java.lang.Float instead of float). */ public static final String WRAPPER = "org.exolab.castor.builder.primitivetowrapper"; /** * Property specifying if we want to have a 'public static final String' * generated for each attribute and element name used within a class * descriptor. */ public static final String CLASS_DESC_FIELD_NAMES = "org.exolab.castor.builder.classdescfieldnames"; /** * Property specifying whether the Java sources generated should be 1.4 * or 5.0 compliant. */ public static final String JAVA_VERSION = "org.exolab.castor.builder.javaVersion"; /** * Forces the code generator to create 'old' Java 1.4 enumeration classes instead * of Java 5 enums for <simpleType> enumerations, even in Java 5 mode. */ public static final String FORCE_JAVA4_ENUMS = "org.exolab.castor.builder.forceJava4Enums"; /** * The name of the configuration file. * * <pre> * castor.properties * </pre> */ public static final String CONFIG_FILENAME_PROPERTY = "castorbuilder.properties"; /** * Maximum number of constant definitions within one file. This property * is used to allow the user to configure the maximum number of * constant definitions (within a Java class as generated as a result of * an enumeration); default is 1000. Is this number if exceeded, no constants * will be generated anymore. * * <pre> * org.exolab.castor.builder.maxNumberOfConstants * </pre> */ public static final String MAX_CONSTANTS_PROPERTY = "org.exolab.castor.builder.maxNumberOfConstants"; /** * Resource to load from the JAR file to load our defaults. */ static final String RESOURCE_NAME = "/org/exolab/castor/builder/castorbuilder.properties"; /** * Registered class name conflict resolution strategies. * * <pre> * org.exolab.castor.builder.nameConflictStrategies * </pre> */ public static final String NAME_CONFLICT_STRATEGIES = "org.exolab.castor.builder.nameConflictStrategies"; /** * Property specifying whether automatic class name conflict resolution * should be used or not; defaults to false. * * <pre> * org.exolab.castor.builder.automaticConflictResolution * </pre> */ public static final String AUTOMATIC_CONFLICT_RESOLUTION = "org.exolab.castor.builder.automaticConflictResolution"; /** * Property specifying the 'string' used in type strategy to be inserted * between the actual element name and the type name (during automatic class name * conflict resolution); defaults to 'By'. * * <pre> * org.exolab.castor.builder.automaticConflictResolutionTypeSuffix * </pre> */ public static final String AUTOMATIC_CONFLICT_RESOLUTION_TYPE_SUFFIX = "org.exolab.castor.builder.automaticConflictResolutionTypeSuffix"; /** * Property enlisting the supported {@link JClassPrinterFactory} instances available * for creating {@link JClassPrinter} instances. */ public static final String JCLASSPRINTER_FACTORIES = "org.exolab.castor.builder.jclassPrinterFactories"; /** * Property specifying whether extra members/methods for extracting XML schema * documentation should be made available; defaults to false. * <pre> * org.exolab.castor.builder.extraDocumentationMethods=false * </pre> */ public static final String EXTRA_DOCUMENTATION_METHODS = "org.exolab.castor.builder.extraDocumentationMethods"; /** * Property specifying whether cycle breaker code should be added to * generated methods 'equals' and 'hashcode'; defaults to <i>true</i>. * * <pre> * org.exolab.castor.builder.useCycleBreaker = true * </pre> */ public static final String USE_CYCLE_BREAKER = "org.exolab.castor.builder.useCycleBreaker"; } //--Property /** * String value of false. */ private static final String FALSE = "false"; /** * String value of true. */ private static final String TRUE = "true"; /** * String value of element binding property. */ private static final String ELEMENT_VALUE = "element"; /** * String value of type binding property. */ private static final String TYPE_VALUE = "type"; /** * The default properties loaded from the configuration file. */ private Properties _defaultProps = null; /** * Our properties after all configuration has been loaded. */ private Properties _localProps = null; /** * Namespace URL to Java package mapping. */ private Hashtable<String, String> _nspackages = new Hashtable<String, String>(); /** * schemaLocation to Java package mapping. */ private Hashtable<String, String> _locpackages = new Hashtable<String, String>(); /** JavaNaming to be used. */ private JavaNaming _javaNaming; /** * hooks for (external) tools to add custom * annotations to fields, classes and enumConstants * during source generation. */ private List<AnnotationBuilder> _annotationBuilders = new ArrayList<AnnotationBuilder>(); //------------------/ /** * Creates a default BuilderConfiguration. */ public BuilderConfiguration() { super(); getDefault(); _localProps = new Properties(_defaultProps); } //-- BuilderConfiguration /** * Returns the default configuration file. Changes to the returned * properties set will affect all Castor functions relying on the default * configuration. * * @return The default configuration */ public final synchronized Properties getDefault() { if (_defaultProps == null) { load(); } return _defaultProps; } //-- getDefault /** * Returns a property from the default configuration file. Equivalent to * calling <tt>getProperty</tt> on the result of {@link #getDefault}. * * @param name * The property name * @param defValue * The property's default value * @return The property's value */ public final String getProperty(final String name, final String defValue) { return _localProps.getProperty(name, defValue); } //-- getProperty /** * Returns true if bound properties are enabled. * <p> * Enabling bound properties is controlled via the * org.exolab.castor.builder.boundproperties item in the * castorbuilder.properties file. The value is either 'true' or 'false'. * * @return true if bound properties are enabled. */ public final boolean boundPropertiesEnabled() { return TRUE.equalsIgnoreCase(_localProps.getProperty(Property.BOUND_PROPERTIES)); } //-- boundPropertiesEnabled /** * Returns true if we generate an 'equals' method for each generated class. * <p> * Enabling this property is controlled via the * org.exolab.castor.builder.equalsmethod item in the * castorbuilder.properties file. The value is either 'true' or 'false'. * * @return true if bound properties are enabled. */ public final boolean equalsMethod() { return TRUE.equalsIgnoreCase(_localProps.getProperty(Property.EQUALS_METHOD)); } //-- equalsMethod /** * Sets the 'equalsmethod' property. * * @param equals The value we want to use. */ public final void setEqualsMethod(final boolean equals) { String value = (equals) ? TRUE : FALSE; _localProps.setProperty(Property.EQUALS_METHOD, value); } //-- setEqualsMethod /** * Returns true if we generate a 'public static final String' for the name * of each attribute and element described by the class descriptor * <p> * Enabling this property is controlled via the * org.exolab.castor.builder.classdescfieldnames item in the * castorbuilder.properties file. The value is either 'true' or 'false'. * * @return true if bound properties are enabled. */ public final boolean classDescFieldNames() { return _localProps.getProperty(Property.CLASS_DESC_FIELD_NAMES, "").equalsIgnoreCase(TRUE); } //-- classDescFieldNames /** * Returns true if extra methods for collection fields should be generated. * Such methods include set/get methods for the actual collection in * addition to the array methods. * <p> * Enabling extra collection methods is controlled via the * org.exolab.castor.builder.extraCollectionMethods property in the * castorbuilder.properties file. The value is either 'true' or 'false'. * * @return true if extra collection methods are enabled. */ public final boolean generateExtraCollectionMethods() { return _localProps.getProperty(Property.EXTRA_COLLECTION_METHODS, "") .equalsIgnoreCase(TRUE); } //-- generateExtraCollectionMethods /** * Sets the 'classDescFieldNames' property. * * @param classDescFieldNames * the value we want to ues */ public final void setClassDescFieldNames(final boolean classDescFieldNames) { String value = (classDescFieldNames) ? TRUE : FALSE; _localProps.setProperty(Property.CLASS_DESC_FIELD_NAMES, value); } //-- setClassDescFieldNames /** * Returns true if primitive types have to be used as Objects (eg. * replacing <code>float</code> by <code>java.lang.Float</code>). * @return true if primitive types have to be used as Objects. */ public final boolean usePrimitiveWrapper() { return _localProps.getProperty(Property.WRAPPER, "").equalsIgnoreCase(TRUE); } //-- usePrimitiveWrapper /** * Sets the 'primitivetowrapper' property. * * @param wrapper the value we want to use. */ public final void setPrimitiveWrapper(final boolean wrapper) { String value = (wrapper) ? TRUE : FALSE; _localProps.setProperty(Property.WRAPPER, value); } //-- setPrimitiveWrapper /** * Returns true if we generate the implements EnumeratedTypeAccess interface * for enumerated type classes. The value is either 'true' or 'false' * * @return true if use enumerated type interface is enabled */ public final boolean useEnumeratedTypeInterface() { return TRUE.equalsIgnoreCase(_localProps.getProperty(Property.ENUM_TYPE_ACCESS_INTERFACE)); } //-- useEnumeratedTypeInterface /** * Returns true if we generate the implements EnumeratedTypeAccess interface * for enumerated type classes. The value is either 'true' or 'false' * * @return true if use enumerated type interface is enabled */ public final boolean useJava50() { return "5.0".equalsIgnoreCase(_localProps.getProperty(Property.JAVA_VERSION, "1.4")); } //-- useEnumeratedTypeInterface /** * Indicates what kind of enumeration should be created for * <xs:simpleType> enumerations. * * @return true if Java 5 source code should be generated. */ public final boolean useJava5Enums() { return useJava50() && FALSE.equalsIgnoreCase( _localProps.getProperty(Property.FORCE_JAVA4_ENUMS, FALSE)); } /** * Add support to set java version programmatically. */ public final void forceUseJava50() { _localProps.setProperty(Property.JAVA_VERSION, "5.0"); } /** * Returns true if extra methods for accessing XML schema documentation should * be generated; default to 'false'. * * @return true if if extra methods for accessing XML schema documentation should be generated */ public final boolean generateExtraDocumentationMethods() { String extraDocumentationMethods = _localProps.getProperty(Property.EXTRA_DOCUMENTATION_METHODS, "false"); return new Boolean(extraDocumentationMethods).booleanValue(); } /** * Returns true if the class {@link CycleBreaker} should be used during code generation; * defaults to 'true'. * * @return true if the class {@link CycleBreaker} should be used during code generation */ public final boolean useCycleBreaker() { return Boolean.valueOf(_localProps.getProperty(Property.USE_CYCLE_BREAKER, "true")); } /** * Returns the maximum number of static constant definitions that are * acceptable within one class file; default is 1000. * * @return the maximum number of static constant definitions acceptable within * one class file */ public final int getMaximumNumberOfConstants() { String property = _localProps.getProperty(Property.MAX_CONSTANTS_PROPERTY, "1000"); return Integer.valueOf(property).intValue(); } /** * Sets the 'enumTypeAccessInterface' property. * * @param flag the value we want to use */ public final void setUseEnumeratedTypeInterface(final boolean flag) { String value = (flag) ? TRUE : FALSE; _localProps.setProperty(Property.ENUM_TYPE_ACCESS_INTERFACE, value); } //-- setUseEnumeratedTypeInterface /** * Tests the org.exolab.castor.builder.javaclassmapping property for the * 'element' value. * * @return True if the Source Generator is mapping schema elements to Java * classes. */ public boolean mappingSchemaElement2Java() { String value = _localProps.getProperty(Property.JAVA_CLASS_MAPPING, ""); return ELEMENT_VALUE.equalsIgnoreCase(value); } //-- mappingSchemaElement2Java /** * Tests the org.exolab.castor.builder.javaclassmapping property for the 'type' value. * * @return True if the Source Generator is mapping schema types to Java classes. */ public boolean mappingSchemaType2Java() { String value = _localProps.getProperty(Property.JAVA_CLASS_MAPPING, ""); return TYPE_VALUE.equalsIgnoreCase(value); } //-- mappingSchemaType2Java /** * Overrides the current set of properties with the given properties. Once * the properties are set, only a copy will be uses, so any changes to the * given properties file after the fact will go unnoticed. * * @param properties * the Properties file */ public final void setDefaultProperties(final Properties properties) { Properties defaults = null; if (properties == null) { defaults = _defaultProps; } else { defaults = new Properties(_defaultProps); Enumeration<?> enumeration = properties.keys(); while (enumeration.hasMoreElements()) { String name = (String) enumeration.nextElement(); defaults.setProperty(name, properties.getProperty(name)); } } _localProps = new Properties(defaults); processNamespacePackageMappings( _localProps.getProperty(Property.NAMESPACE_PACKAGES_OLD, "")); processNamespacePackageMappings( _localProps.getProperty(Property.NAMESPACE_PACKAGES, "")); } //-- setDefaultProperties /** * Sets the namespace to package mapping. * * @param ns the namespace URI to map * @param packageName the package name */ public final void setNamespacePackageMapping(final String ns, final String packageName) { _nspackages.put(ns, packageName); } //-- setNamespcaePackageMapping /** * Sets the schemaLocation to package mapping. * * @param schemaLocation the schemaLocation to map * @param packageName the package name to map to */ public final void setLocationPackageMapping( final String schemaLocation, final String packageName) { _locpackages.put(schemaLocation, packageName); } /** * Returns a String representing the list of {@link JClassPrinterFactory} instances * configured in the Castor XML code generator property file. * @return the list of {@link JClassPrinterFactory} instances as configured, as string. */ public final String getJClassPrinterFactories() { return _localProps.getProperty(Property.JCLASSPRINTER_FACTORIES); } /** * Called by {@link #getDefault} to load the configuration the first time. * Will not complain about inability to load configuration file from one of * the default directories, but if it cannot find the JAR's configuration * file, will throw a run time exception. */ protected final synchronized void load() { if (_defaultProps == null) { //-- load defaults from JAR _defaultProps = loadProperties( Property.RESOURCE_NAME, Property.CONFIG_FILENAME_PROPERTY); //-- load local defaults boolean found = false; // Get overriding configuration from the classpath, ignore if not found. // If found, merge any existing properties. try { InputStream is = SourceGenerator.class.getResourceAsStream( "/" + Property.CONFIG_FILENAME_PROPERTY); if (is != null) { found = true; _defaultProps.load(is); is.close(); } } catch (Exception except) { //-- do nothing } //-- if not found, either it doesn't exist, or "." is not part of the //-- class path, try looking at local working directory if (!found) { try { File file = new File(Property.CONFIG_FILENAME_PROPERTY); if (file.exists() && file.canRead()) { InputStream is = new FileInputStream(file); _defaultProps.load(is); is.close(); } } catch (Exception except) { //-- do nothing } } } AbstractProperties rtconf = XMLProperties.newInstance(); // Parse XML namespace and package list from both castor.properties and // castorbuilder.properties processNamespacePackageMappings(rtconf.getString(Property.NAMESPACE_PACKAGES_OLD, "")); processNamespacePackageMappings(rtconf.getString(Property.NAMESPACE_PACKAGES, "")); processNamespacePackageMappings(_defaultProps.getProperty( Property.NAMESPACE_PACKAGES_OLD, "")); processNamespacePackageMappings(_defaultProps.getProperty( Property.NAMESPACE_PACKAGES, "")); //-- backward compatibility with 0.9.3.9 String prop = _defaultProps.getProperty( JavaNamingImpl.UPPER_CASE_AFTER_UNDERSCORE_PROPERTY, null); if (prop != null) { /* * TODO: joachim: Argh! this shouldn't exist and it shouldn't be here! Setting a * static attribute into a class because somewhere later the class is instantiated * and use but then the attribute is required... I need to sort out the order how * objects are created... */ JavaNamingImpl._upperCaseAfterUnderscore = Boolean.valueOf(prop).booleanValue(); } } //-- load /** * Gets a Java package to an XML namespace URL. * @param nsURL the XML namespace URL to convert into a Java package name * @return a Java package name */ public final String lookupPackageByNamespace(final String nsURL) { String namespaceURL = (nsURL == null) ? "" : nsURL; // Lookup Java package via NS String javaPackage = _nspackages.get(namespaceURL); if (javaPackage == null) { return ""; } return javaPackage; } //-- lookupPackageNamespace /** * Converts a schema location into a Java package. * * @param schemaLocation * the Schema location to use to look up the Java package * @return a Java package name */ public final String lookupPackageByLocation(final String schemaLocation) { if (schemaLocation == null) { return ""; } // Lookup Java package via schemaLocation //--Full path String javaPackage = _locpackages.get(schemaLocation); if (javaPackage == null) { String cleanedSchemaLocation = schemaLocation; //--maybe a relative schemaLocation was given while (schemaLocation.startsWith(".")) { if (schemaLocation.startsWith(SELF_DIRECTORY)) { cleanedSchemaLocation = schemaLocation.substring(SELF_DIRECTORY_LENGTH); } else if (schemaLocation.startsWith(PARENT_DIRECTORY)) { cleanedSchemaLocation = schemaLocation.substring(PARENT_DIRECTORY_LENGTH); } } Enumeration<String> keys = _locpackages.keys(); boolean found = false; while (keys.hasMoreElements() && !found) { String key = keys.nextElement(); if (cleanedSchemaLocation.endsWith(key)) { javaPackage = _locpackages.get(key); found = true; } } if (javaPackage == null) { javaPackage = ""; } } return javaPackage; } //-- lookupPackageLocation /** * processes the given String which contains namespace-to-package mappings. * * @param mappings the namespace-to-package mappings */ protected final void processNamespacePackageMappings(final String mappings) { if (mappings == null) { return; } StringTokenizer tokens = new StringTokenizer(mappings, ","); while (tokens.hasMoreTokens()) { String token = tokens.nextToken(); int sepIdx = token.indexOf('='); if (sepIdx < 0) { continue; } String ns = token.substring(0, sepIdx).trim(); String javaPackage = token.substring(sepIdx + 1).trim(); _nspackages.put(ns, javaPackage); } } //-- processNamespacePackageMappings /** * indicates whether automatic class name conflict resolution during * XML code generation should take place or not. * @return True if automatic mode should be used. */ public boolean isAutomaticConflictResolution() { String automaticConflictResolutionProperty = _localProps.getProperty(Property.AUTOMATIC_CONFLICT_RESOLUTION, "false"); return "true".equalsIgnoreCase(automaticConflictResolutionProperty); } /** * Returns the type 'suffix' used for the type strategy during automatic class name * conflict resolution during XML code generation; default to "" unless a value is specified. * @return The type suffix to be inserted between element name and type name */ public String getAutomaticConflictResolutionTypeSuffix() { return _localProps.getProperty(Property.AUTOMATIC_CONFLICT_RESOLUTION_TYPE_SUFFIX, ""); } /** * To set the {@link JavaNaming} implementation to be used. * @param javaNaming JavaNaming implementation to be used * @since 1.1.3 */ public void setJavaNaming(final JavaNaming javaNaming) { _javaNaming = javaNaming; } /** * To get the {@link JavaNaming} implementation to be used. * @return JavaNaming implementation to be used * @since 1.1.3 */ public JavaNaming getJavaNaming() { return _javaNaming; } /** * adds a custom annotation builder. * @param annotationBuilder the builder */ public void addAnnotationBuilder(final AnnotationBuilder annotationBuilder) { this._annotationBuilders.add(annotationBuilder); } /** * returns all applied annotation builders. * @return a array of builders for type convenience */ public AnnotationBuilder[] getAnnotationBuilders() { return this._annotationBuilders.toArray( new AnnotationBuilder[this._annotationBuilders.size()]); } /** * Load the configuration will not complain about inability to load * configuration file from one of the default directories, but if * it cannot find the JAR's configuration file, will throw a * run time exception. * * @param resourceName Name of the source. * @param fileName Name of the configuration file. * @return A {@link Properties} instance holding the actual XML code generator configuration. */ public static Properties loadProperties(final String resourceName, final String fileName) { File file; Properties properties = new Properties(); boolean found = false; // Get detault configuration from the Castor JAR. // Complain if not found. InputStream resourceStream = null; try { resourceStream = AbstractProperties.class.getResourceAsStream(resourceName); properties.load(resourceStream); //-- debug information: //URL url = Configuration.class.getResource( resourceName ); //System.out.println("loading configuration: " + url.toExternalForm()); //-- end debug information found = true; } catch (Exception except) { // Do nothing as we will check classpath // and java lib directory below } finally { if (resourceStream != null) { try { resourceStream.close(); } catch (IOException e) { LOG.warn("Problem closing stream for " + resourceName); } } } // Get overriding configuration from the Java // library directory, ignore if not found. If // found merge existing properties. String javaHome = null; try { javaHome = System.getProperty("java.home"); } catch (SecurityException e) { // Not a critical error, but users will need to know if they need to // change their config. LOG.warn(Messages.format("conf.privilegesError", e)); } catch (Exception e) { // As we will be trying something else later, record the error for setup purposes, // but do not actually treat as a critical failure. LOG.warn(Messages.format("conf.nonCriticalError", e)); } if (javaHome != null) { InputStream fileStream = null; try { file = new File(javaHome, "lib"); file = new File(file, fileName); if (file.exists()) { properties = new Properties(properties); fileStream = new FileInputStream(file); properties.load(fileStream); found = true; } } catch (SecurityException e) { // Not a critical error, but users will need to know if they need to change // their config. LOG.warn(Messages.format("conf.privilegesError", e)); } catch (IOException e) { // Report that we were unable to load the resource. LOG.warn(Messages.format("conf.nonCriticalError", e)); } finally { if (fileStream != null) { try { fileStream.close(); } catch (IOException e) { LOG.warn("Problem closing stream for " + fileName); } } } } //-- Cannot find any castor.properties file(s). if (!found) { throw new RuntimeException(Messages.format("conf.noDefaultConfigurationFile", fileName)); } return properties; } }