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 4317 2012-02-28 11:14:30Z schulte2005 $ 029 * 030 */ 031package org.jomc.tools.modlet; 032 033import java.lang.reflect.Field; 034import java.text.MessageFormat; 035import java.util.HashMap; 036import java.util.List; 037import java.util.Locale; 038import java.util.Map; 039import java.util.ResourceBundle; 040import java.util.Set; 041import java.util.logging.Level; 042import javax.xml.bind.JAXBElement; 043import javax.xml.namespace.QName; 044import org.jomc.model.Dependencies; 045import org.jomc.model.Implementation; 046import org.jomc.model.InheritanceModel; 047import org.jomc.model.Messages; 048import org.jomc.model.Module; 049import org.jomc.model.Modules; 050import org.jomc.model.Properties; 051import org.jomc.model.Specification; 052import org.jomc.model.Specifications; 053import org.jomc.model.modlet.ModelHelper; 054import org.jomc.modlet.Model; 055import org.jomc.modlet.ModelContext; 056import org.jomc.modlet.ModelException; 057import org.jomc.modlet.ModelProvider; 058import org.jomc.tools.JomcTool; 059import org.jomc.tools.model.ObjectFactory; 060import org.jomc.tools.model.SourceFileType; 061import org.jomc.tools.model.SourceFilesType; 062import org.jomc.tools.model.SourceSectionType; 063import org.jomc.tools.model.SourceSectionsType; 064import static org.jomc.tools.modlet.ToolsModletConstants.*; 065 066/** 067 * Object management and configuration tools {@code ModelProvider} implementation. 068 * 069 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a> 070 * @version $JOMC: ToolsModelProvider.java 4317 2012-02-28 11:14:30Z schulte2005 $ 071 * @see ModelContext#findModel(java.lang.String) 072 * @since 1.2 073 */ 074public class ToolsModelProvider implements ModelProvider 075{ 076 077 /** Constant for the qualified name of {@code source-files} elements. */ 078 private static final QName SOURCE_FILES_QNAME = new ObjectFactory().createSourceFiles( null ).getName(); 079 080 /** 081 * Constant for the name of the model context attribute backing property {@code enabled}. 082 * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 083 * @see ModelContext#getAttribute(java.lang.String) 084 */ 085 public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.tools.modlet.ToolsModelProvider.enabledAttribute"; 086 087 /** 088 * Constant for the name of the system property controlling property {@code defaultEnabled}. 089 * @see #isDefaultEnabled() 090 */ 091 private static final String DEFAULT_ENABLED_PROPERTY_NAME = 092 "org.jomc.tools.modlet.ToolsModelProvider.defaultEnabled"; 093 094 /** 095 * Default value of the flag indicating the provider is enabled by default. 096 * @see #isDefaultEnabled() 097 */ 098 private static final Boolean DEFAULT_ENABLED = Boolean.TRUE; 099 100 /** Flag indicating the provider is enabled by default. */ 101 private static volatile Boolean defaultEnabled; 102 103 /** Flag indicating the provider is enabled. */ 104 private Boolean enabled; 105 106 /** 107 * Constant for the name of the model context attribute backing property 108 * {@code modelObjectClasspathResolutionEnabled}. 109 * 110 * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model) 111 * @see ModelContext#getAttribute(java.lang.String) 112 */ 113 public static final String MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME = 114 "org.jomc.tools.modlet.ToolsModelProvider.modelObjectClasspathResolutionEnabledAttribute"; 115 116 /** 117 * Constant for the name of the system property controlling property 118 * {@code defaultModelObjectClasspathResolutionEnabled}. 119 * @see #isDefaultModelObjectClasspathResolutionEnabled() 120 */ 121 private static final String DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME = 122 "org.jomc.tools.modlet.ToolsModelProvider.defaultModelObjectClasspathResolutionEnabled"; 123 124 /** 125 * Default value of the flag indicating model object class path resolution is enabled by default. 126 * @see #isDefaultModelObjectClasspathResolutionEnabled() 127 */ 128 private static final Boolean DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED = Boolean.TRUE; 129 130 /** Flag indicating model object class path resolution is enabled by default. */ 131 private static volatile Boolean defaultModelObjectClasspathResolutionEnabled; 132 133 /** Flag indicating model object class path resolution is enabled. */ 134 private Boolean modelObjectClasspathResolutionEnabled; 135 136 /** Creates a new {@code ToolsModelProvider} instance. */ 137 public ToolsModelProvider() 138 { 139 super(); 140 } 141 142 /** 143 * Gets a flag indicating the provider is enabled by default. 144 * <p>The default enabled flag is controlled by system property 145 * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultEnabled} holding a value indicating the provider is 146 * enabled by default. If that property is not set, the {@code true} default is returned.</p> 147 * 148 * @return {@code true}, if the provider is enabled by default; {@code false}, if the provider is disabled by 149 * default. 150 * 151 * @see #setDefaultEnabled(java.lang.Boolean) 152 */ 153 public static boolean isDefaultEnabled() 154 { 155 if ( defaultEnabled == null ) 156 { 157 defaultEnabled = Boolean.valueOf( System.getProperty( DEFAULT_ENABLED_PROPERTY_NAME, 158 Boolean.toString( DEFAULT_ENABLED ) ) ); 159 160 } 161 162 return defaultEnabled; 163 } 164 165 /** 166 * Sets the flag indicating the provider is enabled by default. 167 * 168 * @param value The new value of the flag indicating the provider is enabled by default or {@code null}. 169 * 170 * @see #isDefaultEnabled() 171 */ 172 public static void setDefaultEnabled( final Boolean value ) 173 { 174 defaultEnabled = value; 175 } 176 177 /** 178 * Gets a flag indicating the provider is enabled. 179 * 180 * @return {@code true}, if the provider is enabled; {@code false}, if the provider is disabled. 181 * 182 * @see #isDefaultEnabled() 183 * @see #setEnabled(java.lang.Boolean) 184 */ 185 public final boolean isEnabled() 186 { 187 if ( this.enabled == null ) 188 { 189 this.enabled = isDefaultEnabled(); 190 } 191 192 return this.enabled; 193 } 194 195 /** 196 * Sets the flag indicating the provider is enabled. 197 * 198 * @param value The new value of the flag indicating the provider is enabled or {@code null}. 199 * 200 * @see #isEnabled() 201 */ 202 public final void setEnabled( final Boolean value ) 203 { 204 this.enabled = value; 205 } 206 207 /** 208 * Gets a flag indicating model object class path resolution is enabled by default. 209 * <p>The model object class path resolution default enabled flag is controlled by system property 210 * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultModelObjectClasspathResolutionEnabled} holding a value 211 * indicating model object class path resolution is enabled by default. If that property is not set, the 212 * {@code true} default is returned.</p> 213 * 214 * @return {@code true}, if model object class path resolution is enabled by default; {@code false}, if model object 215 * class path resolution is disabled by default. 216 * 217 * @see #setDefaultModelObjectClasspathResolutionEnabled(java.lang.Boolean) 218 */ 219 public static boolean isDefaultModelObjectClasspathResolutionEnabled() 220 { 221 if ( defaultModelObjectClasspathResolutionEnabled == null ) 222 { 223 defaultModelObjectClasspathResolutionEnabled = Boolean.valueOf( System.getProperty( 224 DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME, 225 Boolean.toString( DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED ) ) ); 226 227 } 228 229 return defaultModelObjectClasspathResolutionEnabled; 230 } 231 232 /** 233 * Sets the flag indicating model object class path resolution is enabled by default. 234 * 235 * @param value The new value of the flag indicating model object class path resolution is enabled by default or 236 * {@code null}. 237 * 238 * @see #isDefaultModelObjectClasspathResolutionEnabled() 239 */ 240 public static void setDefaultModelObjectClasspathResolutionEnabled( final Boolean value ) 241 { 242 defaultModelObjectClasspathResolutionEnabled = value; 243 } 244 245 /** 246 * Gets a flag indicating model object class path resolution is enabled. 247 * 248 * @return {@code true}, if model object class path resolution is enabled; {@code false}, if model object class path 249 * resolution is disabled. 250 * 251 * @see #isDefaultModelObjectClasspathResolutionEnabled() 252 * @see #setModelObjectClasspathResolutionEnabled(java.lang.Boolean) 253 */ 254 public final boolean isModelObjectClasspathResolutionEnabled() 255 { 256 if ( this.modelObjectClasspathResolutionEnabled == null ) 257 { 258 this.modelObjectClasspathResolutionEnabled = isDefaultModelObjectClasspathResolutionEnabled(); 259 } 260 261 return this.modelObjectClasspathResolutionEnabled; 262 } 263 264 /** 265 * Sets the flag indicating model object class path resolution is is enabled. 266 * 267 * @param value The new value of the flag indicating model object class path resolution is enabled or {@code null}. 268 * 269 * @see #isModelObjectClasspathResolutionEnabled() 270 */ 271 public final void setModelObjectClasspathResolutionEnabled( final Boolean value ) 272 { 273 this.modelObjectClasspathResolutionEnabled = value; 274 } 275 276 /** 277 * {@inheritDoc} 278 * 279 * @see #isEnabled() 280 * @see #isModelObjectClasspathResolutionEnabled() 281 * @see #ENABLED_ATTRIBUTE_NAME 282 * @see #MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME 283 */ 284 public Model findModel( final ModelContext context, final Model model ) throws ModelException 285 { 286 if ( context == null ) 287 { 288 throw new NullPointerException( "context" ); 289 } 290 if ( model == null ) 291 { 292 throw new NullPointerException( "model" ); 293 } 294 295 Model provided = null; 296 297 boolean contextEnabled = this.isEnabled(); 298 if ( DEFAULT_ENABLED == contextEnabled && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean ) 299 { 300 contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME ); 301 } 302 303 boolean contextModelObjectClasspathResolutionEnabled = this.isModelObjectClasspathResolutionEnabled(); 304 if ( contextModelObjectClasspathResolutionEnabled == DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED 305 && context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME ) instanceof Boolean ) 306 { 307 contextModelObjectClasspathResolutionEnabled = 308 (Boolean) context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME ); 309 310 } 311 312 if ( contextEnabled ) 313 { 314 provided = model.clone(); 315 final Modules modules = ModelHelper.getModules( provided ); 316 317 if ( modules != null ) 318 { 319 Module classpathModule = null; 320 if ( contextModelObjectClasspathResolutionEnabled ) 321 { 322 classpathModule = modules.getClasspathModule( Modules.getDefaultClasspathModuleName(), 323 context.getClassLoader() ); 324 325 if ( classpathModule != null 326 && modules.getModule( Modules.getDefaultClasspathModuleName() ) == null ) 327 { 328 modules.getModule().add( classpathModule ); 329 } 330 else 331 { 332 classpathModule = null; 333 } 334 } 335 336 final JomcTool tool = new JomcTool(); 337 tool.setModel( provided ); 338 339 if ( modules.getSpecifications() != null ) 340 { 341 for ( int i = 0, s0 = modules.getSpecifications().getSpecification().size(); i < s0; i++ ) 342 { 343 final Specification specification = modules.getSpecifications().getSpecification().get( i ); 344 final SourceFileType sourceFileType = specification.getAnyObject( SourceFileType.class ); 345 final SourceFilesType sourceFilesType = specification.getAnyObject( SourceFilesType.class ); 346 347 if ( sourceFileType == null && specification.isClassDeclaration() ) 348 { 349 final SourceFilesType defaultSourceFiles = 350 this.getDefaultSourceFilesType( tool, specification ); 351 352 if ( sourceFilesType != null ) 353 { 354 this.overwriteSourceFiles( sourceFilesType, defaultSourceFiles, true ); 355 } 356 else 357 { 358 specification.getAny().add( new ObjectFactory().createSourceFiles( 359 this.getDefaultSourceFilesType( tool, specification ) ) ); 360 361 } 362 } 363 } 364 } 365 366 if ( modules.getImplementations() != null ) 367 { 368 final Map<Implementation, SourceFilesType> userSourceFiles = 369 new HashMap<Implementation, SourceFilesType>(); 370 371 InheritanceModel imodel = new InheritanceModel( modules ); 372 373 for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ ) 374 { 375 final Implementation implementation = modules.getImplementations().getImplementation().get( i ); 376 final SourceFileType sourceFileType = implementation.getAnyObject( SourceFileType.class ); 377 final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class ); 378 379 if ( sourceFileType == null ) 380 { 381 if ( sourceFilesType != null ) 382 { 383 userSourceFiles.put( implementation, sourceFilesType ); 384 } 385 else if ( implementation.isClassDeclaration() ) 386 { 387 final SourceFilesType defaultSourceFiles = 388 this.getDefaultSourceFilesType( tool, implementation ); 389 390 boolean finalAncestor = false; 391 392 final Set<InheritanceModel.Node<JAXBElement<?>>> sourceFilesNodes = 393 imodel.getJaxbElementNodes( implementation.getIdentifier(), SOURCE_FILES_QNAME ); 394 395 for ( final InheritanceModel.Node<JAXBElement<?>> sourceFilesNode : sourceFilesNodes ) 396 { 397 if ( sourceFilesNode.getModelObject().getValue() instanceof SourceFilesType ) 398 { 399 final SourceFilesType ancestorSourceFiles = 400 (SourceFilesType) sourceFilesNode.getModelObject().getValue(); 401 402 this.overwriteSourceFiles( defaultSourceFiles, ancestorSourceFiles, false ); 403 404 if ( ancestorSourceFiles.isFinal() ) 405 { 406 finalAncestor = true; 407 } 408 } 409 } 410 411 if ( !finalAncestor ) 412 { 413 implementation.getAny().add( 414 new ObjectFactory().createSourceFiles( defaultSourceFiles ) ); 415 416 } 417 } 418 } 419 } 420 421 for ( final Map.Entry<Implementation, SourceFilesType> e : userSourceFiles.entrySet() ) 422 { 423 this.overwriteSourceFiles( e.getValue(), this.getDefaultSourceFilesType( tool, e.getKey() ), 424 true ); 425 426 } 427 428 imodel = new InheritanceModel( modules ); 429 430 for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ ) 431 { 432 final Implementation implementation = modules.getImplementations().getImplementation().get( i ); 433 final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class ); 434 435 if ( sourceFilesType != null && !userSourceFiles.containsKey( implementation ) ) 436 { 437 boolean override = false; 438 439 final Set<InheritanceModel.Node<JAXBElement<?>>> sourceFilesNodes = 440 imodel.getJaxbElementNodes( implementation.getIdentifier(), SOURCE_FILES_QNAME ); 441 442 for ( final InheritanceModel.Node<JAXBElement<?>> e : sourceFilesNodes ) 443 { 444 if ( !e.getOverriddenNodes().isEmpty() ) 445 { 446 override = true; 447 break; 448 } 449 } 450 451 if ( override ) 452 { 453 sourceFilesType.setOverride( override ); 454 } 455 } 456 } 457 } 458 459 if ( classpathModule != null ) 460 { 461 modules.getModule().remove( classpathModule ); 462 } 463 } 464 } 465 else if ( context.isLoggable( Level.FINER ) ) 466 { 467 context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName(), 468 model.getIdentifier() ), null ); 469 470 } 471 472 return provided; 473 } 474 475 /** 476 * Creates a new default source files model for a given specification. 477 * 478 * @param tool The tool to use for generating type names. 479 * @param specification The specification to create a new default source files model for. 480 * 481 * @return A new default source files model for {@code specification}. 482 * 483 * @throws NullPointerExeption if {@code tool} or {@code specification} is {@code null}. 484 */ 485 private SourceFilesType getDefaultSourceFilesType( final JomcTool tool, final Specification specification ) 486 { 487 if ( tool == null ) 488 { 489 throw new NullPointerException( "tool" ); 490 } 491 if ( specification == null ) 492 { 493 throw new NullPointerException( "specification" ); 494 } 495 496 final SourceFilesType sourceFilesType = new SourceFilesType(); 497 final SourceFileType sourceFileType = new SourceFileType(); 498 sourceFilesType.getSourceFile().add( sourceFileType ); 499 500 sourceFileType.setIdentifier( "Default" ); 501 502 if ( specification.getClazz() != null ) 503 { 504 sourceFileType.setLocation( new StringBuilder( specification.getClazz().length() + 5 ).append( 505 specification.getClazz().replace( '.', '/' ) ).append( ".java" ).toString() ); 506 507 } 508 509 sourceFileType.setTemplate( SPECIFICATION_TEMPLATE ); 510 sourceFileType.setHeadComment( "//" ); 511 sourceFileType.setSourceSections( new SourceSectionsType() ); 512 513 SourceSectionType s = new SourceSectionType(); 514 s.setName( LICENSE_SECTION_NAME ); 515 s.setHeadTemplate( SPECIFICATION_LICENSE_TEMPLATE ); 516 s.setOptional( true ); 517 sourceFileType.getSourceSections().getSourceSection().add( s ); 518 519 s = new SourceSectionType(); 520 s.setName( ANNOTATIONS_SECTION_NAME ); 521 s.setHeadTemplate( SPECIFICATION_ANNOTATIONS_TEMPLATE ); 522 sourceFileType.getSourceSections().getSourceSection().add( s ); 523 524 s = new SourceSectionType(); 525 s.setName( DOCUMENTATION_SECTION_NAME ); 526 s.setHeadTemplate( SPECIFICATION_DOCUMENTATION_TEMPLATE ); 527 s.setOptional( true ); 528 sourceFileType.getSourceSections().getSourceSection().add( s ); 529 530 final String javaTypeName = tool.getJavaTypeName( specification, false ); 531 if ( javaTypeName != null ) 532 { 533 s = new SourceSectionType(); 534 s.setName( javaTypeName ); 535 s.setIndentationLevel( 1 ); 536 s.setEditable( true ); 537 sourceFileType.getSourceSections().getSourceSection().add( s ); 538 } 539 540 return sourceFilesType; 541 } 542 543 /** 544 * Creates a new default source files model for a given implementation. 545 * 546 * @param tool The tool to use for generating type names. 547 * @param implementation The implementation to create a new default source files model for. 548 * 549 * @return A new default source files model for {@code implementation}. 550 * 551 * @throws NullPointerExeption if {@code tool} or {@code implementation} is {@code null}. 552 */ 553 private SourceFilesType getDefaultSourceFilesType( final JomcTool tool, final Implementation implementation ) 554 { 555 if ( tool == null ) 556 { 557 throw new NullPointerException( "tool" ); 558 } 559 if ( implementation == null ) 560 { 561 throw new NullPointerException( "implementation" ); 562 } 563 564 final SourceFilesType sourceFilesType = new SourceFilesType(); 565 final SourceFileType sourceFileType = new SourceFileType(); 566 sourceFilesType.getSourceFile().add( sourceFileType ); 567 568 final Modules modules = ModelHelper.getModules( tool.getModel() ); 569 Specifications specifications = null; 570 Dependencies dependencies = null; 571 Messages messages = null; 572 Properties properties = null; 573 574 if ( modules != null ) 575 { 576 specifications = modules.getSpecifications( implementation.getIdentifier() ); 577 dependencies = modules.getDependencies( implementation.getIdentifier() ); 578 messages = modules.getMessages( implementation.getIdentifier() ); 579 properties = modules.getProperties( implementation.getIdentifier() ); 580 } 581 582 sourceFileType.setIdentifier( "Default" ); 583 584 if ( implementation.getClazz() != null ) 585 { 586 sourceFileType.setLocation( new StringBuilder( implementation.getClazz().length() + 5 ).append( 587 implementation.getClazz().replace( '.', '/' ) ).append( ".java" ).toString() ); 588 589 } 590 591 sourceFileType.setTemplate( IMPLEMENTATION_TEMPLATE ); 592 sourceFileType.setHeadComment( "//" ); 593 sourceFileType.setSourceSections( new SourceSectionsType() ); 594 595 SourceSectionType s = new SourceSectionType(); 596 s.setName( LICENSE_SECTION_NAME ); 597 s.setHeadTemplate( IMPLEMENTATION_LICENSE_TEMPLATE ); 598 s.setOptional( true ); 599 sourceFileType.getSourceSections().getSourceSection().add( s ); 600 601 s = new SourceSectionType(); 602 s.setName( ANNOTATIONS_SECTION_NAME ); 603 s.setHeadTemplate( IMPLEMENTATION_ANNOTATIONS_TEMPLATE ); 604 sourceFileType.getSourceSections().getSourceSection().add( s ); 605 606 s = new SourceSectionType(); 607 s.setName( DOCUMENTATION_SECTION_NAME ); 608 s.setHeadTemplate( IMPLEMENTATION_DOCUMENTATION_TEMPLATE ); 609 s.setOptional( true ); 610 sourceFileType.getSourceSections().getSourceSection().add( s ); 611 612 final List<String> implementedJavaTypeNames = tool.getImplementedJavaTypeNames( implementation, false ); 613 for ( int i = 0, s0 = implementedJavaTypeNames.size(); i < s0; i++ ) 614 { 615 s = new SourceSectionType(); 616 s.setName( implementedJavaTypeNames.get( i ) ); 617 s.setIndentationLevel( 1 ); 618 s.setEditable( true ); 619 sourceFileType.getSourceSections().getSourceSection().add( s ); 620 } 621 622 final String javaTypeName = tool.getJavaTypeName( implementation, false ); 623 if ( javaTypeName != null && !implementedJavaTypeNames.contains( javaTypeName ) ) 624 { 625 s = new SourceSectionType(); 626 s.setName( javaTypeName ); 627 s.setIndentationLevel( 1 ); 628 s.setEditable( true ); 629 sourceFileType.getSourceSections().getSourceSection().add( s ); 630 } 631 632 s = new SourceSectionType(); 633 s.setName( CONSTRUCTORS_SECTION_NAME ); 634 s.setIndentationLevel( 1 ); 635 s.setHeadTemplate( CONSTRUCTORS_HEAD_TEMPLATE ); 636 s.setTailTemplate( CONSTRUCTORS_TAIL_TEMPLATE ); 637 s.setOptional( specifications == null || ( specifications.getSpecification().isEmpty() 638 && specifications.getReference().isEmpty() ) ); 639 640 s.setSourceSections( new SourceSectionsType() ); 641 sourceFileType.getSourceSections().getSourceSection().add( s ); 642 643 final SourceSectionType defaultCtor = new SourceSectionType(); 644 defaultCtor.setName( DEFAULT_CONSTRUCTOR_SECTION_NAME ); 645 defaultCtor.setIndentationLevel( 2 ); 646 defaultCtor.setHeadTemplate( DEFAULT_CONSTRUCTOR_TEMPLATE ); 647 defaultCtor.setEditable( true ); 648 s.getSourceSections().getSourceSection().add( defaultCtor ); 649 650 s = new SourceSectionType(); 651 s.setName( DEPENDENCIES_SECTION_NAME ); 652 s.setIndentationLevel( 1 ); 653 s.setHeadTemplate( DEPENDENCIES_TEMPLATE ); 654 s.setOptional( dependencies == null || dependencies.getDependency().isEmpty() ); 655 sourceFileType.getSourceSections().getSourceSection().add( s ); 656 657 s = new SourceSectionType(); 658 s.setName( PROPERTIES_SECTION_NAME ); 659 s.setIndentationLevel( 1 ); 660 s.setHeadTemplate( PROPERTIES_TEMPLATE ); 661 s.setOptional( properties == null || properties.getProperty().isEmpty() ); 662 sourceFileType.getSourceSections().getSourceSection().add( s ); 663 664 s = new SourceSectionType(); 665 s.setName( MESSAGES_SECTION_NAME ); 666 s.setIndentationLevel( 1 ); 667 s.setHeadTemplate( MESSAGES_TEMPLATE ); 668 s.setOptional( messages == null || messages.getMessage().isEmpty() ); 669 sourceFileType.getSourceSections().getSourceSection().add( s ); 670 671 return sourceFilesType; 672 } 673 674 /** 675 * Overwrites a list of source code files with another list of source code files. 676 * 677 * @param targetSourceFiles The list to overwrite. 678 * @param sourceSourceFiles The list to overwrite with. 679 * @param preserveExisting {@code true}, to preserve existing attributes of source code files and sections; 680 * {@code false}, to overwrite existing attributes of source code files and sections. 681 * 682 * @throws NullPointerException if {@code targetSourceFiles} or {@code sourceSourceFiles} is {@code null}. 683 */ 684 private void overwriteSourceFiles( final SourceFilesType targetSourceFiles, final SourceFilesType sourceSourceFiles, 685 final boolean preserveExisting ) 686 { 687 if ( targetSourceFiles == null ) 688 { 689 throw new NullPointerException( "targetSourceFiles" ); 690 } 691 if ( sourceSourceFiles == null ) 692 { 693 throw new NullPointerException( "sourceSourceFiles" ); 694 } 695 696 try 697 { 698 for ( final SourceFileType s : sourceSourceFiles.getSourceFile() ) 699 { 700 final SourceFileType targetSourceFile = targetSourceFiles.getSourceFile( s.getIdentifier() ); 701 702 if ( targetSourceFile != null ) 703 { 704 this.overwriteSourceFile( targetSourceFile, s, preserveExisting ); 705 } 706 } 707 } 708 catch ( final NoSuchFieldException e ) 709 { 710 throw new AssertionError( e ); 711 } 712 } 713 714 /** 715 * Overwrites a source code file with another source code file. 716 * 717 * @param targetSourceFile The source code file to overwrite. 718 * @param sourceSourceFile The source code file to overwrite with. 719 * @param preserveExisting {@code true}, to preserve existing attributes of the given source code file and sections; 720 * {@code false}, to overwrite existing attributes of the given source code file and sections. 721 * 722 * @throws NullPointerException if {@code targetSourceFile} or {@code sourceSourceFile} is {@code null}. 723 */ 724 private void overwriteSourceFile( final SourceFileType targetSourceFile, final SourceFileType sourceSourceFile, 725 final boolean preserveExisting ) 726 throws NoSuchFieldException 727 { 728 if ( targetSourceFile == null ) 729 { 730 throw new NullPointerException( "targetSourceFile" ); 731 } 732 if ( sourceSourceFile == null ) 733 { 734 throw new NullPointerException( "sourceSourceFile" ); 735 } 736 737 if ( !preserveExisting ) 738 { 739 targetSourceFile.setIdentifier( sourceSourceFile.getIdentifier() ); 740 targetSourceFile.setLocation( sourceSourceFile.getLocation() ); 741 targetSourceFile.setTemplate( sourceSourceFile.getTemplate() ); 742 targetSourceFile.setHeadComment( sourceSourceFile.getHeadComment() ); 743 targetSourceFile.setTailComment( sourceSourceFile.getTailComment() ); 744 745 if ( isFieldSet( sourceSourceFile, "_final" ) ) 746 { 747 targetSourceFile.setFinal( sourceSourceFile.isFinal() ); 748 } 749 if ( isFieldSet( sourceSourceFile, "modelVersion" ) ) 750 { 751 targetSourceFile.setModelVersion( sourceSourceFile.getModelVersion() ); 752 } 753 if ( isFieldSet( sourceSourceFile, "override" ) ) 754 { 755 targetSourceFile.setOverride( sourceSourceFile.isOverride() ); 756 } 757 } 758 759 if ( sourceSourceFile.getSourceSections() != null ) 760 { 761 if ( targetSourceFile.getSourceSections() == null ) 762 { 763 targetSourceFile.setSourceSections( new SourceSectionsType() ); 764 } 765 766 this.overwriteSourceSections( targetSourceFile.getSourceSections(), sourceSourceFile.getSourceSections(), 767 preserveExisting ); 768 769 } 770 } 771 772 /** 773 * Overwrites source code file sections with other source code file sections. 774 * 775 * @param targetSourceSections The source code file sections to overwrite. 776 * @param sourceSourceSections The source code file sections to overwrite with. 777 * @param preserveExisting {@code true}, to preserve existing attributes of the given source code file sections; 778 * {@code false}, to overwrite existing attributes of the given source code file sections. 779 * 780 * @throws NullPointerException if {@code targetSourceSections} or {@code sourceSourceSections} is {@code null}. 781 */ 782 private void overwriteSourceSections( final SourceSectionsType targetSourceSections, 783 final SourceSectionsType sourceSourceSections, 784 final boolean preserveExisting ) throws NoSuchFieldException 785 { 786 if ( targetSourceSections == null ) 787 { 788 throw new NullPointerException( "targetSourceSections" ); 789 } 790 if ( sourceSourceSections == null ) 791 { 792 throw new NullPointerException( "sourceSourceSections" ); 793 } 794 795 for ( final SourceSectionType sourceSection : sourceSourceSections.getSourceSection() ) 796 { 797 SourceSectionType targetSection = null; 798 799 for ( final SourceSectionType t : targetSourceSections.getSourceSection() ) 800 { 801 if ( sourceSection.getName().equals( t.getName() ) ) 802 { 803 targetSection = t; 804 break; 805 } 806 } 807 808 if ( targetSection != null ) 809 { 810 if ( !preserveExisting ) 811 { 812 targetSection.setName( sourceSection.getName() ); 813 targetSection.setHeadTemplate( sourceSection.getHeadTemplate() ); 814 targetSection.setTailTemplate( sourceSection.getTailTemplate() ); 815 816 if ( isFieldSet( sourceSection, "editable" ) ) 817 { 818 targetSection.setEditable( sourceSection.isEditable() ); 819 } 820 if ( isFieldSet( sourceSection, "indentationLevel" ) ) 821 { 822 targetSection.setIndentationLevel( sourceSection.getIndentationLevel() ); 823 } 824 if ( isFieldSet( sourceSection, "modelVersion" ) ) 825 { 826 targetSection.setModelVersion( sourceSection.getModelVersion() ); 827 } 828 if ( isFieldSet( sourceSection, "optional" ) ) 829 { 830 targetSection.setOptional( sourceSection.isOptional() ); 831 } 832 } 833 } 834 else 835 { 836 targetSection = sourceSection.clone(); 837 targetSourceSections.getSourceSection().add( targetSection ); 838 } 839 840 if ( sourceSection.getSourceSections() != null ) 841 { 842 if ( targetSection.getSourceSections() == null ) 843 { 844 targetSection.setSourceSections( new SourceSectionsType() ); 845 } 846 847 this.overwriteSourceSections( targetSection.getSourceSections(), sourceSection.getSourceSections(), 848 preserveExisting ); 849 } 850 } 851 } 852 853 private static boolean isFieldSet( final Object object, final String fieldName ) throws NoSuchFieldException 854 { 855 final Field field = getField( object.getClass(), fieldName ); 856 857 if ( field == null ) 858 { 859 throw new NoSuchFieldException( fieldName ); 860 } 861 862 final boolean accessible = field.isAccessible(); 863 864 try 865 { 866 field.setAccessible( true ); 867 return field.get( object ) != null; 868 } 869 catch ( final IllegalAccessException e ) 870 { 871 throw new AssertionError( e ); 872 } 873 finally 874 { 875 field.setAccessible( accessible ); 876 } 877 } 878 879 private static Field getField( final Class<?> clazz, final String name ) 880 { 881 if ( clazz != null ) 882 { 883 try 884 { 885 return clazz.getDeclaredField( name ); 886 } 887 catch ( final NoSuchFieldException e ) 888 { 889 return getField( clazz.getSuperclass(), name ); 890 } 891 } 892 893 return null; 894 } 895 896 private static String getMessage( final String key, final Object... args ) 897 { 898 return MessageFormat.format( ResourceBundle.getBundle( 899 ToolsModelProvider.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args ); 900 901 } 902 903}