001/* 002 * Copyright (C) Christian Schulte, 2005-206 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions 007 * are met: 008 * 009 * o Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 012 * o Redistributions in binary form must reproduce the above copyright 013 * notice, this list of conditions and the following disclaimer in 014 * the documentation and/or other materials provided with the 015 * distribution. 016 * 017 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 018 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 019 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 020 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 027 * 028 * $JOMC: ToolsModelProvider.java 4852 2014-01-26 05:42:11Z schulte $ 029 * 030 */ 031package org.jomc.tools.modlet; 032 033import java.lang.reflect.Field; 034import java.text.MessageFormat; 035import java.util.ArrayList; 036import java.util.HashMap; 037import java.util.HashSet; 038import java.util.Locale; 039import java.util.Map; 040import java.util.ResourceBundle; 041import java.util.Set; 042import java.util.logging.Level; 043import javax.xml.bind.JAXBElement; 044import javax.xml.namespace.QName; 045import org.jomc.model.Dependencies; 046import org.jomc.model.Implementation; 047import org.jomc.model.InheritanceModel; 048import org.jomc.model.JavaTypeName; 049import org.jomc.model.Messages; 050import org.jomc.model.ModelObjectException; 051import org.jomc.model.Module; 052import org.jomc.model.Modules; 053import org.jomc.model.Properties; 054import org.jomc.model.Specification; 055import org.jomc.model.Specifications; 056import org.jomc.model.modlet.ModelHelper; 057import org.jomc.modlet.Model; 058import org.jomc.modlet.ModelContext; 059import org.jomc.modlet.ModelException; 060import org.jomc.modlet.ModelProvider; 061import org.jomc.tools.model.ObjectFactory; 062import org.jomc.tools.model.SourceFileType; 063import org.jomc.tools.model.SourceFilesType; 064import org.jomc.tools.model.SourceSectionType; 065import org.jomc.tools.model.SourceSectionsType; 066import static org.jomc.tools.modlet.ToolsModletConstants.ANNOTATIONS_SECTION_NAME; 067import static org.jomc.tools.modlet.ToolsModletConstants.CONSTRUCTORS_HEAD_TEMPLATE; 068import static org.jomc.tools.modlet.ToolsModletConstants.CONSTRUCTORS_SECTION_NAME; 069import static org.jomc.tools.modlet.ToolsModletConstants.CONSTRUCTORS_TAIL_TEMPLATE; 070import static org.jomc.tools.modlet.ToolsModletConstants.DEFAULT_CONSTRUCTOR_SECTION_NAME; 071import static org.jomc.tools.modlet.ToolsModletConstants.DEFAULT_CONSTRUCTOR_TEMPLATE; 072import static org.jomc.tools.modlet.ToolsModletConstants.DEPENDENCIES_SECTION_NAME; 073import static org.jomc.tools.modlet.ToolsModletConstants.DEPENDENCIES_TEMPLATE; 074import static org.jomc.tools.modlet.ToolsModletConstants.DOCUMENTATION_SECTION_NAME; 075import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_ANNOTATIONS_TEMPLATE; 076import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_DOCUMENTATION_TEMPLATE; 077import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_LICENSE_TEMPLATE; 078import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_TEMPLATE; 079import static org.jomc.tools.modlet.ToolsModletConstants.LICENSE_SECTION_NAME; 080import static org.jomc.tools.modlet.ToolsModletConstants.MESSAGES_SECTION_NAME; 081import static org.jomc.tools.modlet.ToolsModletConstants.MESSAGES_TEMPLATE; 082import static org.jomc.tools.modlet.ToolsModletConstants.PROPERTIES_SECTION_NAME; 083import static org.jomc.tools.modlet.ToolsModletConstants.PROPERTIES_TEMPLATE; 084import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_ANNOTATIONS_TEMPLATE; 085import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_DOCUMENTATION_TEMPLATE; 086import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_LICENSE_TEMPLATE; 087import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_TEMPLATE; 088 089/** 090 * Object management and configuration tools {@code ModelProvider} implementation. 091 * 092 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 093 * @version $JOMC: ToolsModelProvider.java 4852 2014-01-26 05:42:11Z schulte $ 094 * @see ModelContext#findModel(java.lang.String) 095 * @since 1.2 096 */ 097public class ToolsModelProvider implements ModelProvider 098{ 099 100 /** Constant for the qualified name of {@code source-files} elements. */ 101 private static final QName SOURCE_FILES_QNAME = new ObjectFactory().createSourceFiles( null ).getName(); 102 103 /** 104 * Constant for the name of the model context attribute backing property {@code enabled}. 105 * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 106 * @see ModelContext#getAttribute(java.lang.String) 107 */ 108 public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.tools.modlet.ToolsModelProvider.enabledAttribute"; 109 110 /** 111 * Constant for the name of the system property controlling property {@code defaultEnabled}. 112 * @see #isDefaultEnabled() 113 */ 114 private static final String DEFAULT_ENABLED_PROPERTY_NAME = 115 "org.jomc.tools.modlet.ToolsModelProvider.defaultEnabled"; 116 117 /** 118 * Default value of the flag indicating the provider is enabled by default. 119 * @see #isDefaultEnabled() 120 */ 121 private static final Boolean DEFAULT_ENABLED = Boolean.TRUE; 122 123 /** Flag indicating the provider is enabled by default. */ 124 private static volatile Boolean defaultEnabled; 125 126 /** Flag indicating the provider is enabled. */ 127 private Boolean enabled; 128 129 /** 130 * Constant for the name of the model context attribute backing property 131 * {@code modelObjectClasspathResolutionEnabled}. 132 * 133 * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 134 * @see ModelContext#getAttribute(java.lang.String) 135 */ 136 public static final String MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME = 137 "org.jomc.tools.modlet.ToolsModelProvider.modelObjectClasspathResolutionEnabledAttribute"; 138 139 /** 140 * Constant for the name of the system property controlling property 141 * {@code defaultModelObjectClasspathResolutionEnabled}. 142 * @see #isDefaultModelObjectClasspathResolutionEnabled() 143 */ 144 private static final String DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME = 145 "org.jomc.tools.modlet.ToolsModelProvider.defaultModelObjectClasspathResolutionEnabled"; 146 147 /** 148 * Default value of the flag indicating model object class path resolution is enabled by default. 149 * @see #isDefaultModelObjectClasspathResolutionEnabled() 150 */ 151 private static final Boolean DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED = Boolean.TRUE; 152 153 /** Flag indicating model object class path resolution is enabled by default. */ 154 private static volatile Boolean defaultModelObjectClasspathResolutionEnabled; 155 156 /** Flag indicating model object class path resolution is enabled. */ 157 private Boolean modelObjectClasspathResolutionEnabled; 158 159 /** 160 * Constant for the name of the model context attribute backing property {@code headComment}. 161 * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 162 * @see ModelContext#getAttribute(java.lang.String) 163 * @since 1.6 164 */ 165 public static final String HEAD_COMMENT_ATTRIBUTE_NAME = 166 "org.jomc.tools.modlet.ToolsModelProvider.headCommentAttribute"; 167 168 /** 169 * Constant for the name of the system property controlling property {@code defaultHeadComment}. 170 * @see #getDefaultHeadComment() 171 * @since 1.6 172 */ 173 private static final String DEFAULT_HEAD_COMMENT_PROPERTY_NAME = 174 "org.jomc.tools.modlet.ToolsModelProvider.defaultHeadComment"; 175 176 /** 177 * Default head comment the provider is providing by default. 178 * @see #getDefaultHeadComment() 179 * @since 1.6 180 */ 181 private static final String DEFAULT_HEAD_COMMENT = "//"; 182 183 /** 184 * Head comment the provider is providing by default. 185 * @since 1.6 186 */ 187 private static volatile String defaultHeadComment; 188 189 /** 190 * Head comment the provider is providing. 191 * @since 1.6 192 */ 193 private String headComment; 194 195 /** 196 * Constant for the name of the model context attribute backing property {@code tailComment}. 197 * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 198 * @see ModelContext#getAttribute(java.lang.String) 199 * @since 1.6 200 */ 201 public static final String TAIL_COMMENT_ATTRIBUTE_NAME = 202 "org.jomc.tools.modlet.ToolsModelProvider.tailCommentAttribute"; 203 204 /** 205 * Constant for the name of the system property controlling property {@code defaultTailComment}. 206 * @see #getDefaultTailComment() 207 * @since 1.6 208 */ 209 private static final String DEFAULT_TAIL_COMMENT_PROPERTY_NAME = 210 "org.jomc.tools.modlet.ToolsModelProvider.defaultTailComment"; 211 212 /** 213 * Default tail comment the provider is providing by default. 214 * @see #getDefaultTailComment() 215 * @since 1.6 216 */ 217 private static final String DEFAULT_TAIL_COMMENT = null; 218 219 /** 220 * Tail comment the provider is providing by default. 221 * @since 1.6 222 */ 223 private static volatile String defaultTailComment; 224 225 /** 226 * Tail comment the provider is providing. 227 * @since 1.6 228 */ 229 private String tailComment; 230 231 /** Creates a new {@code ToolsModelProvider} instance. */ 232 public ToolsModelProvider() 233 { 234 super(); 235 } 236 237 /** 238 * Gets a flag indicating the provider is enabled by default. 239 * <p>The default enabled flag is controlled by system property 240 * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultEnabled} holding a value indicating the provider is 241 * enabled by default. If that property is not set, the {@code true} default is returned.</p> 242 * 243 * @return {@code true}, if the provider is enabled by default; {@code false}, if the provider is disabled by 244 * default. 245 * 246 * @see #setDefaultEnabled(java.lang.Boolean) 247 */ 248 public static boolean isDefaultEnabled() 249 { 250 if ( defaultEnabled == null ) 251 { 252 defaultEnabled = Boolean.valueOf( System.getProperty( DEFAULT_ENABLED_PROPERTY_NAME, 253 Boolean.toString( DEFAULT_ENABLED ) ) ); 254 255 } 256 257 return defaultEnabled; 258 } 259 260 /** 261 * Sets the flag indicating the provider is enabled by default. 262 * 263 * @param value The new value of the flag indicating the provider is enabled by default or {@code null}. 264 * 265 * @see #isDefaultEnabled() 266 */ 267 public static void setDefaultEnabled( final Boolean value ) 268 { 269 defaultEnabled = value; 270 } 271 272 /** 273 * Gets a flag indicating the provider is enabled. 274 * 275 * @return {@code true}, if the provider is enabled; {@code false}, if the provider is disabled. 276 * 277 * @see #isDefaultEnabled() 278 * @see #setEnabled(java.lang.Boolean) 279 */ 280 public final boolean isEnabled() 281 { 282 if ( this.enabled == null ) 283 { 284 this.enabled = isDefaultEnabled(); 285 } 286 287 return this.enabled; 288 } 289 290 /** 291 * Sets the flag indicating the provider is enabled. 292 * 293 * @param value The new value of the flag indicating the provider is enabled or {@code null}. 294 * 295 * @see #isEnabled() 296 */ 297 public final void setEnabled( final Boolean value ) 298 { 299 this.enabled = value; 300 } 301 302 /** 303 * Gets a flag indicating model object class path resolution is enabled by default. 304 * <p>The model object class path resolution default enabled flag is controlled by system property 305 * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultModelObjectClasspathResolutionEnabled} holding a value 306 * indicating model object class path resolution is enabled by default. If that property is not set, the 307 * {@code true} default is returned.</p> 308 * 309 * @return {@code true}, if model object class path resolution is enabled by default; {@code false}, if model object 310 * class path resolution is disabled by default. 311 * 312 * @see #setDefaultModelObjectClasspathResolutionEnabled(java.lang.Boolean) 313 */ 314 public static boolean isDefaultModelObjectClasspathResolutionEnabled() 315 { 316 if ( defaultModelObjectClasspathResolutionEnabled == null ) 317 { 318 defaultModelObjectClasspathResolutionEnabled = Boolean.valueOf( System.getProperty( 319 DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME, 320 Boolean.toString( DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED ) ) ); 321 322 } 323 324 return defaultModelObjectClasspathResolutionEnabled; 325 } 326 327 /** 328 * Sets the flag indicating model object class path resolution is enabled by default. 329 * 330 * @param value The new value of the flag indicating model object class path resolution is enabled by default or 331 * {@code null}. 332 * 333 * @see #isDefaultModelObjectClasspathResolutionEnabled() 334 */ 335 public static void setDefaultModelObjectClasspathResolutionEnabled( final Boolean value ) 336 { 337 defaultModelObjectClasspathResolutionEnabled = value; 338 } 339 340 /** 341 * Gets a flag indicating model object class path resolution is enabled. 342 * 343 * @return {@code true}, if model object class path resolution is enabled; {@code false}, if model object class path 344 * resolution is disabled. 345 * 346 * @see #isDefaultModelObjectClasspathResolutionEnabled() 347 * @see #setModelObjectClasspathResolutionEnabled(java.lang.Boolean) 348 */ 349 public final boolean isModelObjectClasspathResolutionEnabled() 350 { 351 if ( this.modelObjectClasspathResolutionEnabled == null ) 352 { 353 this.modelObjectClasspathResolutionEnabled = isDefaultModelObjectClasspathResolutionEnabled(); 354 } 355 356 return this.modelObjectClasspathResolutionEnabled; 357 } 358 359 /** 360 * Sets the flag indicating model object class path resolution is is enabled. 361 * 362 * @param value The new value of the flag indicating model object class path resolution is enabled or {@code null}. 363 * 364 * @see #isModelObjectClasspathResolutionEnabled() 365 */ 366 public final void setModelObjectClasspathResolutionEnabled( final Boolean value ) 367 { 368 this.modelObjectClasspathResolutionEnabled = value; 369 } 370 371 /** 372 * Gets the head comment the provider is providing by default. 373 * <p>The default head comment is controlled by system property 374 * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultHeadComment} holding the head comment the provider is 375 * providing by default. If that property is not set, the {@code //} default is returned.</p> 376 * 377 * @return The head comment the provider is providing by default or {@code null}. 378 * 379 * @see #setDefaultHeadComment(java.lang.String) 380 * @since 1.6 381 */ 382 public static String getDefaultHeadComment() 383 { 384 if ( defaultHeadComment == null ) 385 { 386 defaultHeadComment = System.getProperty( DEFAULT_HEAD_COMMENT_PROPERTY_NAME, DEFAULT_HEAD_COMMENT ); 387 } 388 389 return defaultHeadComment; 390 } 391 392 /** 393 * Sets the head comment the provider is providing by default. 394 * 395 * @param value The new head comment the provider is providing by default or {@code null}. 396 * 397 * @see #getDefaultHeadComment() 398 * @since 1.6 399 */ 400 public static void setDefaultHeadComment( final String value ) 401 { 402 defaultHeadComment = value; 403 } 404 405 /** 406 * Gets the head comment the provider is providing. 407 * 408 * @return The head comment the provider is providing or {@code null}. 409 * 410 * @see #getDefaultHeadComment() 411 * @see #setDefaultHeadComment(java.lang.String) 412 * @since 1.6 413 */ 414 public final String getHeadComment() 415 { 416 if ( this.headComment == null ) 417 { 418 this.headComment = getDefaultHeadComment(); 419 } 420 421 return this.headComment; 422 } 423 424 /** 425 * Sets the head comment the provider is providing. 426 * 427 * @param value The new head comment the provider is providing or {@code null}. 428 * 429 * @see #getHeadComment() 430 * @since 1.6 431 */ 432 public final void setHeadComment( final String value ) 433 { 434 this.headComment = value; 435 } 436 437 /** 438 * Gets the tail comment the provider is providing by default. 439 * <p>The default tail comment is controlled by system property 440 * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultTailComment} holding the tail comment the provider is 441 * providing by default. If that property is not set, the {@code null} default is returned.</p> 442 * 443 * @return The tail comment the provider is providing by default or {@code null}. 444 * 445 * @see #setDefaultTailComment(java.lang.String) 446 * @since 1.6 447 */ 448 public static String getDefaultTailComment() 449 { 450 if ( defaultTailComment == null ) 451 { 452 defaultTailComment = System.getProperty( DEFAULT_TAIL_COMMENT_PROPERTY_NAME, DEFAULT_TAIL_COMMENT ); 453 } 454 455 return defaultTailComment; 456 } 457 458 /** 459 * Sets the tail comment the provider is providing by default. 460 * 461 * @param value The new tail comment the provider is providing by default or {@code null}. 462 * 463 * @see #getDefaultTailComment() 464 * @since 1.6 465 */ 466 public static void setDefaultTailComment( final String value ) 467 { 468 defaultTailComment = value; 469 } 470 471 /** 472 * Gets the tail comment the provider is providing. 473 * 474 * @return The tail comment the provider is providing or {@code null}. 475 * 476 * @see #getDefaultTailComment() 477 * @see #setDefaultTailComment(java.lang.String) 478 * @since 1.6 479 */ 480 public final String getTailComment() 481 { 482 if ( this.tailComment == null ) 483 { 484 this.tailComment = getDefaultTailComment(); 485 } 486 487 return this.tailComment; 488 } 489 490 /** 491 * Sets the tail comment the provider is providing. 492 * 493 * @param value The new tail comment the provider is providing or {@code null}. 494 * 495 * @see #getTailComment() 496 * @since 1.6 497 */ 498 public final void setTailComment( final String value ) 499 { 500 this.tailComment = value; 501 } 502 503 /** 504 * {@inheritDoc} 505 * 506 * @see #isEnabled() 507 * @see #isModelObjectClasspathResolutionEnabled() 508 * @see #getHeadComment() 509 * @see #getTailComment() 510 * @see #ENABLED_ATTRIBUTE_NAME 511 * @see #MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME 512 * @see #HEAD_COMMENT_ATTRIBUTE_NAME 513 * @see #TAIL_COMMENT_ATTRIBUTE_NAME 514 */ 515 public Model findModel( final ModelContext context, final Model model ) throws ModelException 516 { 517 if ( context == null ) 518 { 519 throw new NullPointerException( "context" ); 520 } 521 if ( model == null ) 522 { 523 throw new NullPointerException( "model" ); 524 } 525 526 Model provided = null; 527 528 boolean contextEnabled = this.isEnabled(); 529 if ( DEFAULT_ENABLED == contextEnabled && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean ) 530 { 531 contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME ); 532 } 533 534 boolean contextModelObjectClasspathResolutionEnabled = this.isModelObjectClasspathResolutionEnabled(); 535 if ( contextModelObjectClasspathResolutionEnabled == DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED 536 && context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME ) instanceof Boolean ) 537 { 538 contextModelObjectClasspathResolutionEnabled = 539 (Boolean) context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME ); 540 541 } 542 543 if ( contextEnabled ) 544 { 545 provided = model.clone(); 546 final Modules modules = ModelHelper.getModules( provided ); 547 548 if ( modules != null ) 549 { 550 Module classpathModule = null; 551 if ( contextModelObjectClasspathResolutionEnabled ) 552 { 553 classpathModule = modules.getClasspathModule( Modules.getDefaultClasspathModuleName(), 554 context.getClassLoader() ); 555 556 if ( classpathModule != null 557 && modules.getModule( Modules.getDefaultClasspathModuleName() ) == null ) 558 { 559 modules.getModule().add( classpathModule ); 560 } 561 else 562 { 563 classpathModule = null; 564 } 565 } 566 567 if ( modules.getSpecifications() != null ) 568 { 569 for ( int i = 0, s0 = modules.getSpecifications().getSpecification().size(); i < s0; i++ ) 570 { 571 final Specification specification = modules.getSpecifications().getSpecification().get( i ); 572 final SourceFileType sourceFileType = specification.getAnyObject( SourceFileType.class ); 573 final SourceFilesType sourceFilesType = specification.getAnyObject( SourceFilesType.class ); 574 575 if ( sourceFileType == null && specification.isClassDeclaration() ) 576 { 577 final SourceFilesType defaultSourceFiles = 578 this.getDefaultSourceFilesType( context, modules, specification ); 579 580 if ( sourceFilesType != null ) 581 { 582 this.overwriteSourceFiles( sourceFilesType, defaultSourceFiles, true ); 583 } 584 else 585 { 586 specification.getAny().add( 587 new ObjectFactory().createSourceFiles( defaultSourceFiles ) ); 588 589 } 590 } 591 } 592 } 593 594 if ( modules.getImplementations() != null ) 595 { 596 final Map<Implementation, SourceFilesType> userSourceFiles = 597 new HashMap<Implementation, SourceFilesType>( 598 modules.getImplementations().getImplementation().size() ); 599 600 InheritanceModel imodel = new InheritanceModel( modules ); 601 602 for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ ) 603 { 604 final Implementation implementation = modules.getImplementations().getImplementation().get( i ); 605 final SourceFileType sourceFileType = implementation.getAnyObject( SourceFileType.class ); 606 final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class ); 607 608 if ( sourceFileType == null ) 609 { 610 if ( sourceFilesType != null ) 611 { 612 userSourceFiles.put( implementation, sourceFilesType ); 613 } 614 else if ( implementation.isClassDeclaration() ) 615 { 616 final SourceFilesType defaultSourceFiles = 617 this.getDefaultSourceFilesType( context, modules, implementation ); 618 619 boolean finalAncestor = false; 620 621 final Set<InheritanceModel.Node<JAXBElement<?>>> sourceFilesNodes = 622 imodel.getJaxbElementNodes( implementation.getIdentifier(), SOURCE_FILES_QNAME ); 623 624 for ( final InheritanceModel.Node<JAXBElement<?>> sourceFilesNode : sourceFilesNodes ) 625 { 626 if ( sourceFilesNode.getModelObject().getValue() instanceof SourceFilesType ) 627 { 628 final SourceFilesType ancestorSourceFiles = 629 (SourceFilesType) sourceFilesNode.getModelObject().getValue(); 630 631 this.overwriteSourceFiles( defaultSourceFiles, ancestorSourceFiles, false ); 632 633 if ( ancestorSourceFiles.isFinal() ) 634 { 635 finalAncestor = true; 636 } 637 } 638 } 639 640 if ( !finalAncestor ) 641 { 642 implementation.getAny().add( 643 new ObjectFactory().createSourceFiles( defaultSourceFiles ) ); 644 645 } 646 } 647 } 648 } 649 650 for ( final Map.Entry<Implementation, SourceFilesType> e : userSourceFiles.entrySet() ) 651 { 652 this.overwriteSourceFiles( 653 e.getValue(), this.getDefaultSourceFilesType( context, modules, e.getKey() ), true ); 654 655 } 656 657 imodel = new InheritanceModel( modules ); 658 659 for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ ) 660 { 661 final Implementation implementation = modules.getImplementations().getImplementation().get( i ); 662 final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class ); 663 664 if ( sourceFilesType != null && !userSourceFiles.containsKey( implementation ) ) 665 { 666 boolean override = false; 667 668 final Set<InheritanceModel.Node<JAXBElement<?>>> sourceFilesNodes = 669 imodel.getJaxbElementNodes( implementation.getIdentifier(), SOURCE_FILES_QNAME ); 670 671 for ( final InheritanceModel.Node<JAXBElement<?>> e : sourceFilesNodes ) 672 { 673 if ( !e.getOverriddenNodes().isEmpty() ) 674 { 675 override = true; 676 break; 677 } 678 } 679 680 if ( override ) 681 { 682 sourceFilesType.setOverride( override ); 683 } 684 } 685 } 686 } 687 688 if ( classpathModule != null ) 689 { 690 modules.getModule().remove( classpathModule ); 691 } 692 } 693 } 694 else if ( context.isLoggable( Level.FINER ) ) 695 { 696 context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName(), 697 model.getIdentifier() ), null ); 698 699 } 700 701 return provided; 702 } 703 704 /** 705 * Gets the default source code file location for a given specification. 706 * <p>If the specification provides a Java type name, this method returns a Java source code file location based on 707 * that Java type name.</p> 708 * 709 * @param context The context to get the default location with. 710 * @param modules The model to get the default location with. 711 * @param specification The specification to get the default location for. 712 * 713 * @return The default location for {@code specification} or {@code null}. 714 * 715 * @throws NullPointerExeption if {@code context}, {@code modules} or {@code specification} is {@code null}. 716 * 717 * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification) 718 * @see SourceFileType#getLocation() 719 * @see Specification#getJavaTypeName() 720 * @since 1.6 721 */ 722 protected String getDefaultSourceFileLocation( final ModelContext context, final Modules modules, 723 final Specification specification ) 724 { 725 if ( context == null ) 726 { 727 throw new NullPointerException( "context" ); 728 } 729 if ( modules == null ) 730 { 731 throw new NullPointerException( "modules" ); 732 } 733 if ( specification == null ) 734 { 735 throw new NullPointerException( "specification" ); 736 } 737 738 String location = null; 739 740 try 741 { 742 if ( specification.getJavaTypeName() != null ) 743 { 744 location = specification.getJavaTypeName().getQualifiedName().replace( '.', '/' ) + ".java"; 745 } 746 } 747 catch ( final ModelObjectException e ) 748 { 749 context.log( Level.WARNING, getMessage( e ), null ); 750 } 751 752 return location; 753 } 754 755 /** 756 * Gets the default source code file location for a given implementation. 757 * <p>If the implementation provides a Java type name, this method returns a Java source code file location based on 758 * that Java type name.</p> 759 * 760 * @param context The context to get the default location with. 761 * @param modules The model to get the default location with. 762 * @param implementation The implementation to get the default location for. 763 * 764 * @return The default location for {@code implementation} or {@code null}. 765 * 766 * @throws NullPointerExeption if {@code context}, {@code modules} or {@code implementation} is {@code null}. 767 * 768 * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation) 769 * @see SourceFileType#getLocation() 770 * @see Implementation#getJavaTypeName() 771 * @since 1.6 772 */ 773 protected String getDefaultSourceFileLocation( final ModelContext context, final Modules modules, 774 final Implementation implementation ) 775 { 776 if ( context == null ) 777 { 778 throw new NullPointerException( "context" ); 779 } 780 if ( modules == null ) 781 { 782 throw new NullPointerException( "modules" ); 783 } 784 if ( implementation == null ) 785 { 786 throw new NullPointerException( "implementation" ); 787 } 788 789 String location = null; 790 791 try 792 { 793 if ( implementation.getJavaTypeName() != null ) 794 { 795 location = implementation.getJavaTypeName().getQualifiedName().replace( '.', '/' ) + ".java"; 796 } 797 } 798 catch ( final ModelObjectException e ) 799 { 800 context.log( Level.WARNING, getMessage( e ), null ); 801 } 802 803 return location; 804 } 805 806 /** 807 * Gets the default source section name for a given specification. 808 * <p>If the specification provides a Java type name, this method returns a section name based on that Java type 809 * name.</p> 810 * 811 * @param context The context to get the default section name with. 812 * @param modules The model to get the default section name with. 813 * @param specification The specification to get the default section name for. 814 * 815 * @return The default source section name for {@code specification} or {@code null}. 816 * 817 * @throws NullPointerExeption if {@code context}, {@code modules} or {@code specification} is {@code null}. 818 * 819 * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification) 820 * @see SourceSectionType#getName() 821 * @see Specification#getJavaTypeName() 822 * @since 1.6 823 */ 824 protected String getDefaultSourceSectionName( final ModelContext context, final Modules modules, 825 final Specification specification ) 826 { 827 if ( context == null ) 828 { 829 throw new NullPointerException( "context" ); 830 } 831 if ( modules == null ) 832 { 833 throw new NullPointerException( "modules" ); 834 } 835 if ( specification == null ) 836 { 837 throw new NullPointerException( "specification" ); 838 } 839 840 String sectionName = null; 841 842 try 843 { 844 final JavaTypeName javaTypeName = specification.getJavaTypeName(); 845 846 if ( javaTypeName != null ) 847 { 848 sectionName = javaTypeName.getName( false ); 849 } 850 } 851 catch ( final ModelObjectException e ) 852 { 853 context.log( Level.WARNING, getMessage( e ), null ); 854 } 855 856 return sectionName; 857 } 858 859 /** 860 * Gets the default source section name for a given implementation. 861 * <p>If the implementation provides a Java type name, this method returns a section name based that Java type 862 * name.</p> 863 * 864 * @param context The context to get the default section name with. 865 * @param modules The model to get the default section name with. 866 * @param implementation The implementation to get the default section name for. 867 * 868 * @return The default source section name for {@code implementation} or {@code null}. 869 * 870 * @throws NullPointerExeption if {@code context}, {@code modules} or {@code implementation} is {@code null}. 871 * 872 * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation) 873 * @see SourceSectionType#getName() 874 * @see Implementation#getJavaTypeName() 875 * @since 1.6 876 */ 877 protected String getDefaultSourceSectionName( final ModelContext context, final Modules modules, 878 final Implementation implementation ) 879 { 880 if ( context == null ) 881 { 882 throw new NullPointerException( "context" ); 883 } 884 if ( modules == null ) 885 { 886 throw new NullPointerException( "modules" ); 887 } 888 if ( implementation == null ) 889 { 890 throw new NullPointerException( "implementation" ); 891 } 892 893 String sectionName = null; 894 895 try 896 { 897 final JavaTypeName javaTypeName = implementation.getJavaTypeName(); 898 899 if ( javaTypeName != null ) 900 { 901 sectionName = javaTypeName.getName( false ); 902 } 903 } 904 catch ( final ModelObjectException e ) 905 { 906 context.log( Level.WARNING, getMessage( e ), null ); 907 } 908 909 return sectionName; 910 } 911 912 /** 913 * Creates a new default source files model for a given specification. 914 * 915 * @param context The context to create a new default source files model with. 916 * @param modules The model to create a new default source files model with. 917 * @param specification The specification to create a new default source files model for. 918 * 919 * @return A new default source files model for {@code specification}. 920 * 921 * @throws NullPointerExeption if {@code context}, {@code modules} or {@code specification} is {@code null}. 922 * 923 * @see #getDefaultSourceFileLocation(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification) 924 * @see #getDefaultSourceSectionName(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification) 925 * @since 1.6 926 */ 927 protected SourceFilesType getDefaultSourceFilesType( final ModelContext context, final Modules modules, 928 final Specification specification ) 929 { 930 if ( context == null ) 931 { 932 throw new NullPointerException( "context" ); 933 } 934 if ( modules == null ) 935 { 936 throw new NullPointerException( "modules" ); 937 } 938 if ( specification == null ) 939 { 940 throw new NullPointerException( "specification" ); 941 } 942 943 String contextHeadComment = this.getHeadComment(); 944 if ( ( DEFAULT_HEAD_COMMENT != null 945 ? DEFAULT_HEAD_COMMENT.equals( contextHeadComment ) 946 : contextHeadComment == null ) 947 && context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME ) instanceof String ) 948 { 949 contextHeadComment = (String) context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME ); 950 } 951 952 if ( contextHeadComment != null && contextHeadComment.length() == 0 ) 953 { 954 contextHeadComment = null; 955 } 956 957 String contextTailComment = this.getTailComment(); 958 if ( ( DEFAULT_TAIL_COMMENT != null 959 ? DEFAULT_TAIL_COMMENT.equals( contextTailComment ) 960 : contextTailComment == null ) 961 && context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME ) instanceof String ) 962 { 963 contextTailComment = (String) context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME ); 964 } 965 966 if ( contextTailComment != null && contextTailComment.length() == 0 ) 967 { 968 contextTailComment = null; 969 } 970 971 final Set<String> uniqueSectionNames = new HashSet<String>( 16 ); 972 final Set<String> sectionNames = new HashSet<String>( 16 ); 973 sectionNames.add( LICENSE_SECTION_NAME ); 974 sectionNames.add( ANNOTATIONS_SECTION_NAME ); 975 sectionNames.add( DOCUMENTATION_SECTION_NAME ); 976 977 final SourceFilesType sourceFilesType = new SourceFilesType(); 978 final SourceFileType sourceFileType = new SourceFileType(); 979 sourceFilesType.getSourceFile().add( sourceFileType ); 980 981 sourceFileType.setIdentifier( "Default" ); 982 sourceFileType.setLocation( this.getDefaultSourceFileLocation( context, modules, specification ) ); 983 984 sourceFileType.setTemplate( SPECIFICATION_TEMPLATE ); 985 sourceFileType.setHeadComment( contextHeadComment ); 986 sourceFileType.setTailComment( contextTailComment ); 987 sourceFileType.setSourceSections( new SourceSectionsType() ); 988 989 SourceSectionType s = new SourceSectionType(); 990 s.setName( LICENSE_SECTION_NAME ); 991 s.setHeadTemplate( SPECIFICATION_LICENSE_TEMPLATE ); 992 s.setOptional( true ); 993 sourceFileType.getSourceSections().getSourceSection().add( s ); 994 995 s = new SourceSectionType(); 996 s.setName( ANNOTATIONS_SECTION_NAME ); 997 s.setHeadTemplate( SPECIFICATION_ANNOTATIONS_TEMPLATE ); 998 sourceFileType.getSourceSections().getSourceSection().add( s ); 999 1000 s = new SourceSectionType(); 1001 s.setName( DOCUMENTATION_SECTION_NAME ); 1002 s.setHeadTemplate( SPECIFICATION_DOCUMENTATION_TEMPLATE ); 1003 s.setOptional( true ); 1004 sourceFileType.getSourceSections().getSourceSection().add( s ); 1005 1006 final String sectionName = this.getDefaultSourceSectionName( context, modules, specification ); 1007 1008 if ( sectionName != null ) 1009 { 1010 if ( sectionNames.add( sectionName ) ) 1011 { 1012 s = new SourceSectionType(); 1013 s.setName( sectionName ); 1014 s.setIndentationLevel( 1 ); 1015 s.setEditable( true ); 1016 sourceFileType.getSourceSections().getSourceSection().add( s ); 1017 } 1018 else if ( uniqueSectionNames.add( sectionName ) ) 1019 { 1020 final Module module = modules.getModuleOfSpecification( specification.getIdentifier() ); 1021 context.log( Level.WARNING, getMessage( "specificationSectionNameUniqueness", 1022 specification.getIdentifier(), 1023 module.getName(), 1024 sourceFileType.getIdentifier(), 1025 sectionName ), 1026 null ); 1027 1028 } 1029 } 1030 1031 return sourceFilesType; 1032 } 1033 1034 /** 1035 * Creates a new default source files model for a given implementation. 1036 * 1037 * @param context The context to create a new default source files model with. 1038 * @param modules The model to create a new default source files model with. 1039 * @param implementation The implementation to create a new default source files model for. 1040 * 1041 * @return A new default source files model for {@code implementation}. 1042 * 1043 * @throws NullPointerExeption if {@code context}, {@code modules} or {@code implementation} is {@code null}. 1044 * 1045 * @see #getDefaultSourceFileLocation(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation) 1046 * @see #getDefaultSourceSectionName(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation) 1047 * @since 1.6 1048 */ 1049 protected SourceFilesType getDefaultSourceFilesType( final ModelContext context, final Modules modules, 1050 final Implementation implementation ) 1051 { 1052 if ( context == null ) 1053 { 1054 throw new NullPointerException( "context" ); 1055 } 1056 if ( modules == null ) 1057 { 1058 throw new NullPointerException( "modules" ); 1059 } 1060 if ( implementation == null ) 1061 { 1062 throw new NullPointerException( "implementation" ); 1063 } 1064 1065 String contextHeadComment = this.getHeadComment(); 1066 if ( ( DEFAULT_HEAD_COMMENT != null 1067 ? DEFAULT_HEAD_COMMENT.equals( contextHeadComment ) 1068 : contextHeadComment == null ) 1069 && context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME ) instanceof String ) 1070 { 1071 contextHeadComment = (String) context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME ); 1072 } 1073 1074 if ( contextHeadComment != null && contextHeadComment.length() == 0 ) 1075 { 1076 contextHeadComment = null; 1077 } 1078 1079 String contextTailComment = this.getTailComment(); 1080 if ( ( DEFAULT_TAIL_COMMENT != null 1081 ? DEFAULT_TAIL_COMMENT.equals( contextTailComment ) 1082 : contextTailComment == null ) 1083 && context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME ) instanceof String ) 1084 { 1085 contextTailComment = (String) context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME ); 1086 } 1087 1088 if ( contextTailComment != null && contextTailComment.length() == 0 ) 1089 { 1090 contextTailComment = null; 1091 } 1092 1093 final Set<String> uniqueSectionNames = new HashSet<String>( 16 ); 1094 final ArrayList<String> sectionNames = new ArrayList<String>( 16 ); 1095 sectionNames.add( LICENSE_SECTION_NAME ); 1096 sectionNames.add( ANNOTATIONS_SECTION_NAME ); 1097 sectionNames.add( DOCUMENTATION_SECTION_NAME ); 1098 sectionNames.add( CONSTRUCTORS_SECTION_NAME ); 1099 sectionNames.add( DEFAULT_CONSTRUCTOR_SECTION_NAME ); 1100 sectionNames.add( DEPENDENCIES_SECTION_NAME ); 1101 sectionNames.add( PROPERTIES_SECTION_NAME ); 1102 sectionNames.add( MESSAGES_SECTION_NAME ); 1103 1104 final SourceFilesType sourceFilesType = new SourceFilesType(); 1105 final SourceFileType sourceFileType = new SourceFileType(); 1106 sourceFilesType.getSourceFile().add( sourceFileType ); 1107 1108 final Specifications specifications = modules.getSpecifications( implementation.getIdentifier() ); 1109 final Dependencies dependencies = modules.getDependencies( implementation.getIdentifier() ); 1110 final Messages messages = modules.getMessages( implementation.getIdentifier() ); 1111 final Properties properties = modules.getProperties( implementation.getIdentifier() ); 1112 1113 sourceFileType.setIdentifier( "Default" ); 1114 sourceFileType.setLocation( this.getDefaultSourceFileLocation( context, modules, implementation ) ); 1115 1116 sourceFileType.setTemplate( IMPLEMENTATION_TEMPLATE ); 1117 sourceFileType.setHeadComment( contextHeadComment ); 1118 sourceFileType.setTailComment( contextTailComment ); 1119 sourceFileType.setSourceSections( new SourceSectionsType() ); 1120 1121 SourceSectionType s = new SourceSectionType(); 1122 s.setName( LICENSE_SECTION_NAME ); 1123 s.setHeadTemplate( IMPLEMENTATION_LICENSE_TEMPLATE ); 1124 s.setOptional( true ); 1125 sourceFileType.getSourceSections().getSourceSection().add( s ); 1126 1127 s = new SourceSectionType(); 1128 s.setName( ANNOTATIONS_SECTION_NAME ); 1129 s.setHeadTemplate( IMPLEMENTATION_ANNOTATIONS_TEMPLATE ); 1130 sourceFileType.getSourceSections().getSourceSection().add( s ); 1131 1132 s = new SourceSectionType(); 1133 s.setName( DOCUMENTATION_SECTION_NAME ); 1134 s.setHeadTemplate( IMPLEMENTATION_DOCUMENTATION_TEMPLATE ); 1135 s.setOptional( true ); 1136 sourceFileType.getSourceSections().getSourceSection().add( s ); 1137 1138 if ( specifications != null ) 1139 { 1140 sectionNames.ensureCapacity( sectionNames.size() + specifications.getSpecification().size() ); 1141 1142 for ( final Specification specification : specifications.getSpecification() ) 1143 { 1144 final String sectionName = this.getDefaultSourceSectionName( context, modules, specification ); 1145 1146 if ( sectionName != null ) 1147 { 1148 if ( !sectionNames.contains( sectionName ) ) 1149 { 1150 sectionNames.add( sectionName ); 1151 1152 s = new SourceSectionType(); 1153 s.setName( sectionName ); 1154 s.setIndentationLevel( 1 ); 1155 s.setEditable( true ); 1156 sourceFileType.getSourceSections().getSourceSection().add( s ); 1157 } 1158 else if ( uniqueSectionNames.add( sectionName ) ) 1159 { 1160 final Module module = modules.getModuleOfImplementation( implementation.getIdentifier() ); 1161 context.log( Level.WARNING, getMessage( "implementationSectionNameUniqueness", 1162 implementation.getIdentifier(), 1163 module.getName(), 1164 sourceFileType.getIdentifier(), 1165 sectionName ), 1166 null ); 1167 1168 } 1169 } 1170 } 1171 } 1172 1173 final String sectionName = this.getDefaultSourceSectionName( context, modules, implementation ); 1174 1175 if ( sectionName != null ) 1176 { 1177 if ( !sectionNames.contains( sectionName ) ) 1178 { 1179 sectionNames.add( sectionName ); 1180 1181 s = new SourceSectionType(); 1182 s.setName( sectionName ); 1183 s.setIndentationLevel( 1 ); 1184 s.setEditable( true ); 1185 sourceFileType.getSourceSections().getSourceSection().add( s ); 1186 } 1187 else if ( uniqueSectionNames.add( sectionName ) ) 1188 { 1189 final Module module = modules.getModuleOfImplementation( implementation.getIdentifier() ); 1190 context.log( Level.WARNING, getMessage( "implementationSectionNameUniqueness", 1191 implementation.getIdentifier(), 1192 module.getName(), 1193 sourceFileType.getIdentifier(), 1194 sectionName ), 1195 null ); 1196 1197 } 1198 } 1199 1200 s = new SourceSectionType(); 1201 s.setName( CONSTRUCTORS_SECTION_NAME ); 1202 s.setIndentationLevel( 1 ); 1203 s.setHeadTemplate( CONSTRUCTORS_HEAD_TEMPLATE ); 1204 s.setTailTemplate( CONSTRUCTORS_TAIL_TEMPLATE ); 1205 s.setOptional( specifications == null || ( specifications.getSpecification().isEmpty() 1206 && specifications.getReference().isEmpty() ) ); 1207 1208 s.setSourceSections( new SourceSectionsType() ); 1209 sourceFileType.getSourceSections().getSourceSection().add( s ); 1210 1211 final SourceSectionType defaultCtor = new SourceSectionType(); 1212 defaultCtor.setName( DEFAULT_CONSTRUCTOR_SECTION_NAME ); 1213 defaultCtor.setIndentationLevel( 2 ); 1214 defaultCtor.setHeadTemplate( DEFAULT_CONSTRUCTOR_TEMPLATE ); 1215 defaultCtor.setEditable( true ); 1216 s.getSourceSections().getSourceSection().add( defaultCtor ); 1217 1218 s = new SourceSectionType(); 1219 s.setName( DEPENDENCIES_SECTION_NAME ); 1220 s.setIndentationLevel( 1 ); 1221 s.setHeadTemplate( DEPENDENCIES_TEMPLATE ); 1222 s.setOptional( dependencies == null || dependencies.getDependency().isEmpty() ); 1223 sourceFileType.getSourceSections().getSourceSection().add( s ); 1224 1225 s = new SourceSectionType(); 1226 s.setName( PROPERTIES_SECTION_NAME ); 1227 s.setIndentationLevel( 1 ); 1228 s.setHeadTemplate( PROPERTIES_TEMPLATE ); 1229 s.setOptional( properties == null || properties.getProperty().isEmpty() ); 1230 sourceFileType.getSourceSections().getSourceSection().add( s ); 1231 1232 s = new SourceSectionType(); 1233 s.setName( MESSAGES_SECTION_NAME ); 1234 s.setIndentationLevel( 1 ); 1235 s.setHeadTemplate( MESSAGES_TEMPLATE ); 1236 s.setOptional( messages == null || messages.getMessage().isEmpty() ); 1237 sourceFileType.getSourceSections().getSourceSection().add( s ); 1238 1239 return sourceFilesType; 1240 } 1241 1242 /** 1243 * Overwrites a list of source code files with another list of source code files. 1244 * 1245 * @param targetSourceFiles The list to overwrite. 1246 * @param sourceSourceFiles The list to overwrite with. 1247 * @param preserveExisting {@code true}, to preserve existing attributes of source code files and sections; 1248 * {@code false}, to overwrite existing attributes of source code files and sections. 1249 * 1250 * @throws NullPointerException if {@code targetSourceFiles} or {@code sourceSourceFiles} is {@code null}. 1251 */ 1252 private void overwriteSourceFiles( final SourceFilesType targetSourceFiles, final SourceFilesType sourceSourceFiles, 1253 final boolean preserveExisting ) 1254 { 1255 if ( targetSourceFiles == null ) 1256 { 1257 throw new NullPointerException( "targetSourceFiles" ); 1258 } 1259 if ( sourceSourceFiles == null ) 1260 { 1261 throw new NullPointerException( "sourceSourceFiles" ); 1262 } 1263 1264 try 1265 { 1266 for ( final SourceFileType s : sourceSourceFiles.getSourceFile() ) 1267 { 1268 final SourceFileType targetSourceFile = targetSourceFiles.getSourceFile( s.getIdentifier() ); 1269 1270 if ( targetSourceFile != null ) 1271 { 1272 this.overwriteSourceFile( targetSourceFile, s, preserveExisting ); 1273 } 1274 } 1275 } 1276 catch ( final NoSuchFieldException e ) 1277 { 1278 throw new AssertionError( e ); 1279 } 1280 } 1281 1282 /** 1283 * Overwrites a source code file with another source code file. 1284 * 1285 * @param targetSourceFile The source code file to overwrite. 1286 * @param sourceSourceFile The source code file to overwrite with. 1287 * @param preserveExisting {@code true}, to preserve existing attributes of the given source code file and sections; 1288 * {@code false}, to overwrite existing attributes of the given source code file and sections. 1289 * 1290 * @throws NullPointerException if {@code targetSourceFile} or {@code sourceSourceFile} is {@code null}. 1291 */ 1292 private void overwriteSourceFile( final SourceFileType targetSourceFile, final SourceFileType sourceSourceFile, 1293 final boolean preserveExisting ) 1294 throws NoSuchFieldException 1295 { 1296 if ( targetSourceFile == null ) 1297 { 1298 throw new NullPointerException( "targetSourceFile" ); 1299 } 1300 if ( sourceSourceFile == null ) 1301 { 1302 throw new NullPointerException( "sourceSourceFile" ); 1303 } 1304 1305 if ( !preserveExisting ) 1306 { 1307 targetSourceFile.setIdentifier( sourceSourceFile.getIdentifier() ); 1308 targetSourceFile.setLocation( sourceSourceFile.getLocation() ); 1309 targetSourceFile.setTemplate( sourceSourceFile.getTemplate() ); 1310 targetSourceFile.setHeadComment( sourceSourceFile.getHeadComment() ); 1311 targetSourceFile.setTailComment( sourceSourceFile.getTailComment() ); 1312 1313 if ( isFieldSet( sourceSourceFile, "_final" ) ) 1314 { 1315 targetSourceFile.setFinal( sourceSourceFile.isFinal() ); 1316 } 1317 if ( isFieldSet( sourceSourceFile, "modelVersion" ) ) 1318 { 1319 targetSourceFile.setModelVersion( sourceSourceFile.getModelVersion() ); 1320 } 1321 if ( isFieldSet( sourceSourceFile, "override" ) ) 1322 { 1323 targetSourceFile.setOverride( sourceSourceFile.isOverride() ); 1324 } 1325 } 1326 1327 if ( sourceSourceFile.getSourceSections() != null ) 1328 { 1329 if ( targetSourceFile.getSourceSections() == null ) 1330 { 1331 targetSourceFile.setSourceSections( new SourceSectionsType() ); 1332 } 1333 1334 this.overwriteSourceSections( targetSourceFile.getSourceSections(), sourceSourceFile.getSourceSections(), 1335 preserveExisting ); 1336 1337 } 1338 } 1339 1340 /** 1341 * Overwrites source code file sections with other source code file sections. 1342 * 1343 * @param targetSourceSections The source code file sections to overwrite. 1344 * @param sourceSourceSections The source code file sections to overwrite with. 1345 * @param preserveExisting {@code true}, to preserve existing attributes of the given source code file sections; 1346 * {@code false}, to overwrite existing attributes of the given source code file sections. 1347 * 1348 * @throws NullPointerException if {@code targetSourceSections} or {@code sourceSourceSections} is {@code null}. 1349 */ 1350 private void overwriteSourceSections( final SourceSectionsType targetSourceSections, 1351 final SourceSectionsType sourceSourceSections, 1352 final boolean preserveExisting ) throws NoSuchFieldException 1353 { 1354 if ( targetSourceSections == null ) 1355 { 1356 throw new NullPointerException( "targetSourceSections" ); 1357 } 1358 if ( sourceSourceSections == null ) 1359 { 1360 throw new NullPointerException( "sourceSourceSections" ); 1361 } 1362 1363 for ( final SourceSectionType sourceSection : sourceSourceSections.getSourceSection() ) 1364 { 1365 SourceSectionType targetSection = null; 1366 1367 for ( final SourceSectionType t : targetSourceSections.getSourceSection() ) 1368 { 1369 if ( sourceSection.getName().equals( t.getName() ) ) 1370 { 1371 targetSection = t; 1372 break; 1373 } 1374 } 1375 1376 if ( targetSection != null ) 1377 { 1378 if ( !preserveExisting ) 1379 { 1380 targetSection.setName( sourceSection.getName() ); 1381 targetSection.setHeadTemplate( sourceSection.getHeadTemplate() ); 1382 targetSection.setTailTemplate( sourceSection.getTailTemplate() ); 1383 1384 if ( isFieldSet( sourceSection, "editable" ) ) 1385 { 1386 targetSection.setEditable( sourceSection.isEditable() ); 1387 } 1388 if ( isFieldSet( sourceSection, "indentationLevel" ) ) 1389 { 1390 targetSection.setIndentationLevel( sourceSection.getIndentationLevel() ); 1391 } 1392 if ( isFieldSet( sourceSection, "modelVersion" ) ) 1393 { 1394 targetSection.setModelVersion( sourceSection.getModelVersion() ); 1395 } 1396 if ( isFieldSet( sourceSection, "optional" ) ) 1397 { 1398 targetSection.setOptional( sourceSection.isOptional() ); 1399 } 1400 } 1401 } 1402 else 1403 { 1404 targetSection = sourceSection.clone(); 1405 targetSourceSections.getSourceSection().add( targetSection ); 1406 } 1407 1408 if ( sourceSection.getSourceSections() != null ) 1409 { 1410 if ( targetSection.getSourceSections() == null ) 1411 { 1412 targetSection.setSourceSections( new SourceSectionsType() ); 1413 } 1414 1415 this.overwriteSourceSections( targetSection.getSourceSections(), sourceSection.getSourceSections(), 1416 preserveExisting ); 1417 } 1418 } 1419 } 1420 1421 private static boolean isFieldSet( final Object object, final String fieldName ) throws NoSuchFieldException 1422 { 1423 final Field field = getField( object.getClass(), fieldName ); 1424 1425 if ( field == null ) 1426 { 1427 throw new NoSuchFieldException( fieldName ); 1428 } 1429 1430 final boolean accessible = field.isAccessible(); 1431 1432 try 1433 { 1434 field.setAccessible( true ); 1435 return field.get( object ) != null; 1436 } 1437 catch ( final IllegalAccessException e ) 1438 { 1439 throw new AssertionError( e ); 1440 } 1441 finally 1442 { 1443 field.setAccessible( accessible ); 1444 } 1445 } 1446 1447 private static Field getField( final Class<?> clazz, final String name ) 1448 { 1449 if ( clazz != null ) 1450 { 1451 try 1452 { 1453 return clazz.getDeclaredField( name ); 1454 } 1455 catch ( final NoSuchFieldException e ) 1456 { 1457 return getField( clazz.getSuperclass(), name ); 1458 } 1459 } 1460 1461 return null; 1462 } 1463 1464 private static String getMessage( final Throwable t ) 1465 { 1466 return t != null 1467 ? t.getMessage() != null && t.getMessage().trim().length() > 0 1468 ? t.getMessage() 1469 : getMessage( t.getCause() ) 1470 : null; 1471 1472 } 1473 1474 private static String getMessage( final String key, final Object... args ) 1475 { 1476 return MessageFormat.format( ResourceBundle.getBundle( 1477 ToolsModelProvider.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args ); 1478 1479 } 1480 1481}