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