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