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