001 /* 002 * Copyright (c) 2009 The JOMC Project 003 * Copyright (c) 2005 Christian Schulte <cs@jomc.org> 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or without 007 * modification, are permitted provided that the following conditions 008 * are met: 009 * 010 * o Redistributions of source code must retain the above copyright 011 * notice, this list of conditions and the following disclaimer. 012 * 013 * o Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in 015 * the documentation and/or other materials provided with the 016 * distribution. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR 022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 027 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 028 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 * 030 * $Id: JavaSources.java 891 2009-11-02 03:40:00Z schulte2005 $ 031 * 032 */ 033 package org.jomc.tools; 034 035 import java.io.File; 036 import java.io.IOException; 037 import java.io.StringWriter; 038 import java.text.MessageFormat; 039 import java.util.ResourceBundle; 040 import java.util.logging.Level; 041 import org.apache.commons.io.FileUtils; 042 import org.apache.velocity.Template; 043 import org.apache.velocity.VelocityContext; 044 import org.jomc.model.Dependencies; 045 import org.jomc.model.Implementation; 046 import org.jomc.model.Messages; 047 import org.jomc.model.Module; 048 import org.jomc.model.Properties; 049 import org.jomc.model.Specification; 050 import org.jomc.model.Specifications; 051 import org.jomc.util.LineEditor; 052 import org.jomc.util.Section; 053 import org.jomc.util.SectionEditor; 054 import org.jomc.util.TrailingWhitespaceEditor; 055 056 /** 057 * Manages Java source code. 058 * 059 * <p><b>Use cases</b><br/><ul> 060 * <li>{@link #manageSources(java.io.File) }</li> 061 * <li>{@link #manageSources(org.jomc.model.Module, java.io.File) }</li> 062 * <li>{@link #manageSources(org.jomc.model.Specification, java.io.File) }</li> 063 * <li>{@link #manageSources(org.jomc.model.Implementation, java.io.File) }</li> 064 * </ul></p> 065 * 066 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a> 067 * @version $Id: JavaSources.java 891 2009-11-02 03:40:00Z schulte2005 $ 068 * 069 * @see #getModules() 070 */ 071 public class JavaSources extends JomcTool 072 { 073 074 /** Constant for the name of the constructors source code section. */ 075 private static final String CONSTRUCTORS_SECTION_NAME = "Constructors"; 076 077 /** Constant for the name of the default constructor source code section. */ 078 private static final String DEFAULT_CONSTRUCTOR_SECTION_NAME = "Default Constructor"; 079 080 /** Constant for the name of the dependencies source code section. */ 081 private static final String DEPENDENCIES_SECTION_NAME = "Dependencies"; 082 083 /** Constant for the name of the properties source code section. */ 084 private static final String PROPERTIES_SECTION_NAME = "Properties"; 085 086 /** Constant for the name of the messages source code section. */ 087 private static final String MESSAGES_SECTION_NAME = "Messages"; 088 089 /** Constant for the name of the license source code section. */ 090 private static final String LICENSE_SECTION_NAME = "License Header"; 091 092 /** Constant for the name of the documentation source code section. */ 093 private static final String DOCUMENTATION_SECTION_NAME = "Documentation"; 094 095 /** Constant for the name of the implementation annotations source code section. */ 096 private static final String ANNOTATIONS_SECTION_NAME = "Annotations"; 097 098 /** Name of the generator. */ 099 private static final String GENERATOR_NAME = JavaSources.class.getName(); 100 101 /** Constant for the version of the generator. */ 102 private static final String GENERATOR_VERSION = "1.0"; 103 104 /** Name of the {@code implementation-constructors-head.vm} template. */ 105 private static final String CONSTRUCTORS_HEAD_TEMPLATE = "implementation-constructors-head.vm"; 106 107 /** Name of the {@code implementation-constructors-tail.vm} template. */ 108 private static final String CONSTRUCTORS_TAIL_TEMPLATE = "implementation-constructors-tail.vm"; 109 110 /** Name of the {@code implementation-dependencies.vm} template. */ 111 private static final String DEPENDENCIES_TEMPLATE = "implementation-dependencies.vm"; 112 113 /** Name of the {@code implementation-properties.vm} template. */ 114 private static final String PROPERTIES_TEMPLATE = "implementation-properties.vm"; 115 116 /** Name of the {@code implementation-messages.vm} template. */ 117 private static final String MESSAGES_TEMPLATE = "implementation-messages.vm"; 118 119 /** Name of the {@code specification-license.vm} template. */ 120 private static final String SPECIFICATION_LICENSE_TEMPLATE = "specification-license.vm"; 121 122 /** Name of the {@code implementation-license.vm} template. */ 123 private static final String IMPLEMENTATION_LICENSE_TEMPLATE = "implementation-license.vm"; 124 125 /** Name of the {@code specification-documentation.vm} template. */ 126 private static final String SPECIFICATION_DOCUMENTATION_TEMPLATE = "specification-documentation.vm"; 127 128 /** Name of the {@code implementation-documentation.vm} template. */ 129 private static final String IMPLEMENTATION_DOCUMENTATION_TEMPLATE = "implementation-documentation.vm"; 130 131 /** Name of the {@code Implementation.java.vm} template. */ 132 private static final String IMPLEMENTATION_TEMPLATE = "Implementation.java.vm"; 133 134 /** Name of the {@code Specification.java.vm} template. */ 135 private static final String SPECIFICATION_TEMPLATE = "Specification.java.vm"; 136 137 /** Name of the {@code specification-annotations.vm} template. */ 138 private static final String SPECIFICATION_ANNOTATIONS_TEMPLATE = "specification-annotations.vm"; 139 140 /** Name of the {@code implementation-annotations.vm} template. */ 141 private static final String IMPLEMENTATION_ANNOTATIONS_TEMPLATE = "implementation-annotations.vm"; 142 143 /** Creates a new {@code JavaSources} instance. */ 144 public JavaSources() 145 { 146 super(); 147 } 148 149 /** 150 * Creates a new {@code JavaSources} instance taking a {@code JavaSources} instance to initialize the instance with. 151 * 152 * @param tool The instance to initialize the new instance with, 153 */ 154 public JavaSources( final JavaSources tool ) 155 { 156 super( tool ); 157 } 158 159 /** 160 * Manages the source code of the modules of the instance. 161 * 162 * @param sourcesDirectory The directory holding the sources to manage. 163 * 164 * @throws NullPointerException if {@code sourcesDirectory} is {@code null}. 165 * @throws IOException if managing sources fails. 166 * 167 * @see #manageSources(org.jomc.model.Module, java.io.File) 168 */ 169 public void manageSources( final File sourcesDirectory ) throws IOException 170 { 171 if ( sourcesDirectory == null ) 172 { 173 throw new NullPointerException( "sourcesDirectory" ); 174 } 175 176 for ( Module m : this.getModules().getModule() ) 177 { 178 this.manageSources( m, sourcesDirectory ); 179 } 180 } 181 182 /** 183 * Manages the source code of a given module of the modules of the instance. 184 * 185 * @param module The module to process. 186 * @param sourcesDirectory The directory holding the sources to manage. 187 * 188 * @throws NullPointerException if {@code module} or {@code sourcesDirectory} is {@code null}. 189 * @throws IOException if managing sources fails. 190 * 191 * @see #manageSources(org.jomc.model.Specification, java.io.File) 192 * @see #manageSources(org.jomc.model.Implementation, java.io.File) 193 */ 194 public void manageSources( final Module module, final File sourcesDirectory ) throws IOException 195 { 196 if ( module == null ) 197 { 198 throw new NullPointerException( "module" ); 199 } 200 if ( sourcesDirectory == null ) 201 { 202 throw new NullPointerException( "sourcesDirectory" ); 203 } 204 205 if ( module.getSpecifications() != null ) 206 { 207 for ( Specification s : module.getSpecifications().getSpecification() ) 208 { 209 this.manageSources( s, sourcesDirectory ); 210 } 211 } 212 if ( module.getImplementations() != null ) 213 { 214 for ( Implementation i : module.getImplementations().getImplementation() ) 215 { 216 this.manageSources( i, sourcesDirectory ); 217 } 218 } 219 } 220 221 /** 222 * Manages the source code of a given specification of the modules of the instance. 223 * 224 * @param specification The specification to process. 225 * @param sourcesDirectory The directory holding the sources to manage. 226 * 227 * @throws NullPointerException if {@code specification} or {@code sourcesDirectory} is {@code null}. 228 * @throws IOException if managing sources fails. 229 * 230 * @see #getSpecificationEditor(org.jomc.model.Specification) 231 */ 232 public void manageSources( final Specification specification, final File sourcesDirectory ) throws IOException 233 { 234 if ( specification == null ) 235 { 236 throw new NullPointerException( "specification" ); 237 } 238 if ( sourcesDirectory == null ) 239 { 240 throw new NullPointerException( "sourcesDirectory" ); 241 } 242 243 final Implementation i = this.getModules().getImplementation( specification.getIdentifier() ); 244 if ( i != null && this.isJavaClassDeclaration( i ) ) 245 { 246 this.manageSources( i, sourcesDirectory ); 247 } 248 else if ( this.isJavaClassDeclaration( specification ) ) 249 { 250 final File f = new File( sourcesDirectory, specification.getIdentifier().replace( '.', '/' ) + ".java" ); 251 final String content = f.exists() 252 ? FileUtils.readFileToString( f, this.getInputEncoding() ) 253 : this.getSpecificationTemplate( specification ); 254 255 final JavaSpecificationEditor editor = this.getSpecificationEditor( specification ); 256 final String edited; 257 try 258 { 259 edited = editor.edit( content ); 260 } 261 catch ( final IOException e ) 262 { 263 throw (IOException) new IOException( this.getMessage( "failedEditing", new Object[] 264 { 265 f.getCanonicalPath(), e.getMessage() 266 } ) ).initCause( e ); 267 268 } 269 270 if ( !editor.isLicenseSectionPresent() && this.isLoggable( Level.INFO ) ) 271 { 272 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 273 { 274 LICENSE_SECTION_NAME, 275 f.getCanonicalPath() 276 } ), null ); 277 278 } 279 280 if ( !editor.isAnnotationsSectionPresent() ) 281 { 282 throw new IOException( this.getMessage( "missingSection", new Object[] 283 { 284 ANNOTATIONS_SECTION_NAME, 285 f.getCanonicalPath() 286 } ) ); 287 288 } 289 290 if ( !editor.isDocumentationSectionPresent() && this.isLoggable( Level.INFO ) ) 291 { 292 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 293 { 294 DOCUMENTATION_SECTION_NAME, 295 f.getCanonicalPath() 296 } ), null ); 297 298 } 299 300 if ( !edited.equals( content ) ) 301 { 302 if ( !f.getParentFile().exists() && !f.getParentFile().mkdirs() ) 303 { 304 throw new IOException( this.getMessage( "failedCreatingDirectory", new Object[] 305 { 306 f.getParentFile().getAbsolutePath() 307 } ) ); 308 309 } 310 311 if ( this.isLoggable( Level.INFO ) ) 312 { 313 this.log( Level.INFO, this.getMessage( "editing", new Object[] 314 { 315 f.getCanonicalPath() 316 } ), null ); 317 318 } 319 320 FileUtils.writeStringToFile( f, edited, this.getOutputEncoding() ); 321 } 322 } 323 } 324 325 /** 326 * Manages the source code of a given implementation of the modules of the instance. 327 * 328 * @param implementation The implementation to process. 329 * @param sourcesDirectory The directory holding the sources to manage. 330 * 331 * @throws NullPointerException if {@code implementation} or {@code sourcesDirectory} is {@code null}. 332 * @throws IOException if managing sources fails. 333 * 334 * @see #getImplementationEditor(org.jomc.model.Implementation) 335 */ 336 public void manageSources( final Implementation implementation, final File sourcesDirectory ) throws IOException 337 { 338 if ( implementation == null ) 339 { 340 throw new NullPointerException( "implementation" ); 341 } 342 if ( sourcesDirectory == null ) 343 { 344 throw new NullPointerException( "sourcesDirectory" ); 345 } 346 347 if ( this.isJavaClassDeclaration( implementation ) ) 348 { 349 final File f = new File( sourcesDirectory, implementation.getClazz().replace( '.', '/' ) + ".java" ); 350 final String content = f.exists() 351 ? FileUtils.readFileToString( f, this.getInputEncoding() ) 352 : this.getImplementationTemplate( implementation ); 353 354 final JavaImplementationEditor editor = this.getImplementationEditor( implementation ); 355 final String edited; 356 try 357 { 358 edited = editor.edit( content ); 359 } 360 catch ( final IOException e ) 361 { 362 throw (IOException) new IOException( this.getMessage( "failedEditing", new Object[] 363 { 364 f.getCanonicalPath(), e.getMessage() 365 } ) ).initCause( e ); 366 367 } 368 369 if ( !editor.isLicenseSectionPresent() && this.isLoggable( Level.INFO ) ) 370 { 371 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 372 { 373 LICENSE_SECTION_NAME, 374 f.getCanonicalPath() 375 } ), null ); 376 377 } 378 379 if ( !editor.isAnnotationsSectionPresent() ) 380 { 381 throw new IOException( this.getMessage( "missingSection", new Object[] 382 { 383 ANNOTATIONS_SECTION_NAME, 384 f.getCanonicalPath() 385 } ) ); 386 387 } 388 389 if ( !editor.isDocumentationSectionPresent() && this.isLoggable( Level.INFO ) ) 390 { 391 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 392 { 393 DOCUMENTATION_SECTION_NAME, 394 f.getCanonicalPath() 395 } ), null ); 396 397 } 398 399 if ( !editor.isConstructorsSectionPresent() ) 400 { 401 final Specifications specifications = 402 this.getModules().getSpecifications( implementation.getIdentifier() ); 403 404 if ( specifications != null && 405 !( specifications.getSpecification().isEmpty() && specifications.getReference().isEmpty() ) ) 406 { 407 throw new IOException( this.getMessage( "missingSection", new Object[] 408 { 409 CONSTRUCTORS_SECTION_NAME, 410 f.getCanonicalPath() 411 } ) ); 412 413 } 414 else if ( this.isLoggable( Level.INFO ) ) 415 { 416 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 417 { 418 CONSTRUCTORS_SECTION_NAME, 419 f.getCanonicalPath() 420 } ), null ); 421 422 } 423 } 424 else if ( !editor.isDefaultConstructorSectionPresent() ) 425 { 426 throw new IOException( this.getMessage( "missingSection", new Object[] 427 { 428 DEFAULT_CONSTRUCTOR_SECTION_NAME, 429 f.getCanonicalPath() 430 } ) ); 431 432 } 433 434 if ( !editor.isPropertiesSectionPresent() ) 435 { 436 final Properties properties = this.getModules().getProperties( implementation.getIdentifier() ); 437 438 if ( properties != null && !properties.getProperty().isEmpty() ) 439 { 440 throw new IOException( this.getMessage( "missingSection", new Object[] 441 { 442 PROPERTIES_SECTION_NAME, 443 f.getCanonicalPath() 444 } ) ); 445 446 } 447 else if ( this.isLoggable( Level.INFO ) ) 448 { 449 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 450 { 451 PROPERTIES_SECTION_NAME, 452 f.getCanonicalPath() 453 } ), null ); 454 455 } 456 } 457 458 if ( !editor.isDependenciesSectionPresent() ) 459 { 460 final Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() ); 461 462 if ( dependencies != null && !dependencies.getDependency().isEmpty() ) 463 { 464 throw new IOException( this.getMessage( "missingSection", new Object[] 465 { 466 DEPENDENCIES_SECTION_NAME, 467 f.getCanonicalPath() 468 } ) ); 469 470 } 471 else if ( this.isLoggable( Level.INFO ) ) 472 { 473 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 474 { 475 DEPENDENCIES_SECTION_NAME, 476 f.getCanonicalPath() 477 } ), null ); 478 479 } 480 } 481 482 if ( !editor.isMessagesSectionPresent() ) 483 { 484 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() ); 485 486 if ( messages != null && !messages.getMessage().isEmpty() ) 487 { 488 throw new IOException( this.getMessage( "missingSection", new Object[] 489 { 490 MESSAGES_SECTION_NAME, 491 f.getCanonicalPath() 492 } ) ); 493 494 } 495 else if ( this.isLoggable( Level.INFO ) ) 496 { 497 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[] 498 { 499 MESSAGES_SECTION_NAME, 500 f.getCanonicalPath() 501 } ), null ); 502 503 } 504 } 505 506 if ( !edited.equals( content ) ) 507 { 508 if ( !f.getParentFile().exists() && !f.getParentFile().mkdirs() ) 509 { 510 throw new IOException( this.getMessage( "failedCreatingDirectory", new Object[] 511 { 512 f.getParentFile().getAbsolutePath() 513 } ) ); 514 515 } 516 517 if ( this.isLoggable( Level.INFO ) ) 518 { 519 this.log( Level.INFO, this.getMessage( "editing", new Object[] 520 { 521 f.getCanonicalPath() 522 } ), null ); 523 524 } 525 526 FileUtils.writeStringToFile( f, edited, this.getOutputEncoding() ); 527 } 528 } 529 } 530 531 /** 532 * Gets a new editor for editing Java specification source code. 533 * 534 * @param specification The specification to create a new editor for. 535 * 536 * @return A new editor for editing the source code of {@code specification}. 537 * 538 * @throws NullPointerException if {@code specification} is {@code null}. 539 */ 540 public JavaSpecificationEditor getSpecificationEditor( final Specification specification ) 541 { 542 if ( specification == null ) 543 { 544 throw new NullPointerException( "specification" ); 545 } 546 547 return new JavaSpecificationEditor( new TrailingWhitespaceEditor(), specification ); 548 } 549 550 /** 551 * Gets a new editor for editing Java implementation source code. 552 * 553 * @param implementation The implementation to create a new editor for. 554 * 555 * @return A new editor for editing the source code of {@code implementation}. 556 * 557 * @throws NullPointerException if {@code implementation} is {@code null}. 558 */ 559 public JavaImplementationEditor getImplementationEditor( final Implementation implementation ) 560 { 561 if ( implementation == null ) 562 { 563 throw new NullPointerException( "implementation" ); 564 } 565 566 return new JavaImplementationEditor( new TrailingWhitespaceEditor(), implementation ); 567 } 568 569 /** 570 * Gets the velocity context used for merging templates. 571 * 572 * @return The velocity context used for merging templates. 573 */ 574 @Override 575 public VelocityContext getVelocityContext() 576 { 577 final VelocityContext ctx = super.getVelocityContext(); 578 ctx.put( "generatorName", GENERATOR_NAME ); 579 ctx.put( "generatorVersion", GENERATOR_VERSION ); 580 return ctx; 581 } 582 583 /** 584 * Gets the Java source code template of specification. 585 * 586 * @param specification The specification to get the source code template of. 587 * 588 * @throws IOException if getting the source code section fails. 589 */ 590 private String getSpecificationTemplate( final Specification specification ) throws IOException 591 { 592 final StringWriter writer = new StringWriter(); 593 final VelocityContext ctx = this.getVelocityContext(); 594 final Template template = this.getVelocityTemplate( SPECIFICATION_TEMPLATE ); 595 ctx.put( "specification", specification ); 596 ctx.put( "template", template ); 597 template.merge( ctx, writer ); 598 writer.close(); 599 return writer.toString(); 600 } 601 602 /** 603 * Gets the Java source code template of an implementation. 604 * 605 * @param implementation The implementation to get the source code template of. 606 * 607 * @throws IOException if getting the source code section fails. 608 */ 609 private String getImplementationTemplate( final Implementation implementation ) throws IOException 610 { 611 final StringWriter writer = new StringWriter(); 612 final VelocityContext ctx = this.getVelocityContext(); 613 final Template template = this.getVelocityTemplate( IMPLEMENTATION_TEMPLATE ); 614 ctx.put( "implementation", implementation ); 615 ctx.put( "template", template ); 616 template.merge( ctx, writer ); 617 writer.close(); 618 return writer.toString(); 619 } 620 621 /** 622 * Gets the Java source code of the license section of a specification. 623 * 624 * @param specification The specification to get the source code of the license section of. 625 * 626 * @throws IOException if getting the source code section fails. 627 */ 628 private String getLicenseSection( final Specification specification ) throws IOException 629 { 630 final StringWriter writer = new StringWriter(); 631 final VelocityContext ctx = this.getVelocityContext(); 632 final Template template = this.getVelocityTemplate( SPECIFICATION_LICENSE_TEMPLATE ); 633 ctx.put( "specification", specification ); 634 ctx.put( "template", template ); 635 template.merge( ctx, writer ); 636 writer.close(); 637 return writer.toString(); 638 } 639 640 /** 641 * Gets the Java source code of the license section of an implementation.. 642 * 643 * @param implementation The implementation to get the source code of the license section of. 644 * 645 * @throws IOException if getting the source code section fails. 646 */ 647 private String getLicenseSection( final Implementation implementation ) throws IOException 648 { 649 final StringWriter writer = new StringWriter(); 650 final VelocityContext ctx = this.getVelocityContext(); 651 final Template template = this.getVelocityTemplate( IMPLEMENTATION_LICENSE_TEMPLATE ); 652 ctx.put( "implementation", implementation ); 653 ctx.put( "template", template ); 654 template.merge( ctx, writer ); 655 writer.close(); 656 return writer.toString(); 657 } 658 659 /** 660 * Gets the Java source code of the specification annotations section. 661 * 662 * @param specification The specification to get the source code of the annotations section of. 663 * 664 * @throws IOException if getting the source code section fails. 665 */ 666 private String getAnnotationsSection( final Specification specification ) throws IOException 667 { 668 final StringWriter writer = new StringWriter(); 669 final VelocityContext ctx = this.getVelocityContext(); 670 final Template template = this.getVelocityTemplate( SPECIFICATION_ANNOTATIONS_TEMPLATE ); 671 ctx.put( "specification", specification ); 672 ctx.put( "template", template ); 673 template.merge( ctx, writer ); 674 writer.close(); 675 return writer.toString(); 676 } 677 678 /** 679 * Gets the Java source code of the implementation annotations section. 680 * 681 * @param implementation The implementation to get the source code of the annotations section of. 682 * 683 * @throws IOException if getting the source code section fails. 684 */ 685 private String getAnnotationsSection( final Implementation implementation ) throws IOException 686 { 687 final StringWriter writer = new StringWriter(); 688 final VelocityContext ctx = this.getVelocityContext(); 689 final Template template = this.getVelocityTemplate( IMPLEMENTATION_ANNOTATIONS_TEMPLATE ); 690 ctx.put( "implementation", implementation ); 691 ctx.put( "template", template ); 692 template.merge( ctx, writer ); 693 writer.close(); 694 return writer.toString(); 695 } 696 697 /** 698 * Gets the Java source code of the documentation section of a specification. 699 * 700 * @param specification The specification to get the source code section of. 701 * 702 * @throws IOException if getting the source code section fails. 703 */ 704 private String getDocumentationSection( final Specification specification ) throws IOException 705 { 706 final StringWriter writer = new StringWriter(); 707 final VelocityContext ctx = this.getVelocityContext(); 708 final Template template = this.getVelocityTemplate( SPECIFICATION_DOCUMENTATION_TEMPLATE ); 709 ctx.put( "specification", specification ); 710 ctx.put( "template", template ); 711 template.merge( ctx, writer ); 712 writer.close(); 713 return writer.toString(); 714 } 715 716 /** 717 * Gets the Java source code of the documentation section of an implementation. 718 * 719 * @param implementation The implementation to get the source code section of. 720 * 721 * @throws IOException if getting the source code section fails. 722 */ 723 private String getDocumentationSection( final Implementation implementation ) throws IOException 724 { 725 final StringWriter writer = new StringWriter(); 726 final VelocityContext ctx = this.getVelocityContext(); 727 final Template template = this.getVelocityTemplate( IMPLEMENTATION_DOCUMENTATION_TEMPLATE ); 728 ctx.put( "implementation", implementation ); 729 ctx.put( "template", template ); 730 template.merge( ctx, writer ); 731 writer.close(); 732 return writer.toString(); 733 } 734 735 /** 736 * Gets the Java source code of the constructors section head content of an implementation. 737 * 738 * @param implementation The implementation to get the constructors section head content of. 739 * 740 * @throws IOException if getting the source code section fails. 741 */ 742 private String getConstructorsSectionHeadContent( final Implementation implementation ) throws IOException 743 { 744 final StringWriter writer = new StringWriter(); 745 final VelocityContext ctx = this.getVelocityContext(); 746 final Template template = this.getVelocityTemplate( CONSTRUCTORS_HEAD_TEMPLATE ); 747 ctx.put( "implementation", implementation ); 748 ctx.put( "template", template ); 749 template.merge( ctx, writer ); 750 writer.close(); 751 return writer.toString(); 752 } 753 754 /** 755 * Gets the Java source code of the constructors section tail content of an implementation. 756 * 757 * @param implementation The implementation to get the constructors section tail content of. 758 * 759 * @throws IOException if getting the source code section fails. 760 */ 761 private String getConstructorsSectionTailContent( final Implementation implementation ) throws IOException 762 { 763 final StringWriter writer = new StringWriter(); 764 final VelocityContext ctx = this.getVelocityContext(); 765 final Template template = this.getVelocityTemplate( CONSTRUCTORS_TAIL_TEMPLATE ); 766 ctx.put( "implementation", implementation ); 767 ctx.put( "template", template ); 768 template.merge( ctx, writer ); 769 writer.close(); 770 return writer.toString(); 771 } 772 773 /** 774 * Gets the Java source code of the dependencies section of an implementation. 775 * 776 * @param implementation The implementation to get the source code of the dependencies section of. 777 * 778 * @throws IOException if getting the source code section fails. 779 */ 780 private String getDependenciesSection( final Implementation implementation ) throws IOException 781 { 782 final StringWriter writer = new StringWriter(); 783 final VelocityContext ctx = this.getVelocityContext(); 784 final Template template = this.getVelocityTemplate( DEPENDENCIES_TEMPLATE ); 785 ctx.put( "implementation", implementation ); 786 ctx.put( "template", template ); 787 template.merge( ctx, writer ); 788 writer.close(); 789 return writer.toString(); 790 } 791 792 /** 793 * Gets the Java source code of the properties section of an implementation. 794 * 795 * @param implementation The implementation to get the source code of the properties section of. 796 * 797 * @throws IOException if getting the source code section fails. 798 */ 799 private String getPropertiesSection( final Implementation implementation ) throws IOException 800 { 801 final StringWriter writer = new StringWriter(); 802 final VelocityContext ctx = this.getVelocityContext(); 803 final Template template = this.getVelocityTemplate( PROPERTIES_TEMPLATE ); 804 ctx.put( "implementation", implementation ); 805 ctx.put( "template", template ); 806 template.merge( ctx, writer ); 807 writer.close(); 808 return writer.toString(); 809 } 810 811 /** 812 * Gets the Java source code of the messages section of an implementation. 813 * 814 * @param implementation The implementation to get the source code of the messages section of. 815 * 816 * @throws IOException if getting the source code section fails. 817 */ 818 private String getMessagesSection( final Implementation implementation ) throws IOException 819 { 820 final StringWriter writer = new StringWriter(); 821 final VelocityContext ctx = this.getVelocityContext(); 822 final Template template = this.getVelocityTemplate( MESSAGES_TEMPLATE ); 823 ctx.put( "implementation", implementation ); 824 ctx.put( "template", template ); 825 template.merge( ctx, writer ); 826 writer.close(); 827 return writer.toString(); 828 } 829 830 private String getMessage( final String key, final Object args ) 831 { 832 final ResourceBundle b = ResourceBundle.getBundle( JavaSources.class.getName().replace( '.', '/' ) ); 833 final MessageFormat f = new MessageFormat( b.getString( key ) ); 834 return f.format( args ); 835 } 836 837 /** 838 * Extension to {@code SectionEditor} for editing Java source code. 839 * 840 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a> 841 * @version $Id: JavaSources.java 891 2009-11-02 03:40:00Z schulte2005 $ 842 */ 843 public abstract class JavaEditor extends SectionEditor 844 { 845 846 /** Flag indicating that the source code of the editor contains a license section. */ 847 private boolean licenseSectionPresent; 848 849 /** Flag indicating that the source code of the editor contains an annotations section. */ 850 private boolean annotationsSectionPresent; 851 852 /** Flag indicating that the source code of the editor contains a documentation section. */ 853 private boolean documentationSectionPresent; 854 855 /** Creates a new {@code JavaEditor} instance. */ 856 public JavaEditor() 857 { 858 super(); 859 } 860 861 /** 862 * Creates a new {@code JavaEditor} instance taking a {@code LineEditor} to chain. 863 * 864 * @param lineEditor The editor to chain. 865 */ 866 public JavaEditor( final LineEditor lineEditor ) 867 { 868 super( lineEditor ); 869 } 870 871 @Override 872 public String getOutput( final Section section ) throws IOException 873 { 874 if ( section == null ) 875 { 876 throw new NullPointerException( "section" ); 877 } 878 879 this.licenseSectionPresent = false; 880 this.annotationsSectionPresent = false; 881 this.documentationSectionPresent = false; 882 return super.getOutput( section ); 883 } 884 885 @Override 886 public void editSection( final Section section ) throws IOException 887 { 888 if ( section == null ) 889 { 890 throw new NullPointerException( "section" ); 891 } 892 893 if ( section.getName() != null ) 894 { 895 if ( LICENSE_SECTION_NAME.equals( section.getName() ) ) 896 { 897 this.editLicenseSection( section ); 898 this.licenseSectionPresent = true; 899 } 900 if ( ANNOTATIONS_SECTION_NAME.equals( section.getName() ) ) 901 { 902 this.editAnnotationsSection( section ); 903 this.annotationsSectionPresent = true; 904 } 905 if ( DOCUMENTATION_SECTION_NAME.equals( section.getName() ) ) 906 { 907 this.editDocumentationSection( section ); 908 this.documentationSectionPresent = true; 909 } 910 } 911 } 912 913 /** 914 * Edits the license section of the source code of the editor. 915 * 916 * @param s The section to edit. 917 * 918 * @throws NullPointerException if {@code s} is {@code null}. 919 * @throws IOException if editing {@code s} fails. 920 */ 921 public abstract void editLicenseSection( final Section s ) throws IOException; 922 923 /** 924 * Edits the annotations section of the source code of the editor. 925 * 926 * @param s The section to edit. 927 * 928 * @throws NullPointerException if {@code s} is {@code null}. 929 * @throws IOException if editing {@code s} fails. 930 */ 931 public abstract void editAnnotationsSection( final Section s ) throws IOException; 932 933 /** 934 * Edits the documentation section of the source code of the editor. 935 * 936 * @param s The section to edit. 937 * 938 * @throws NullPointerException if {@code s} is {@code null}. 939 * @throws IOException if editing {@code s} fails. 940 */ 941 public abstract void editDocumentationSection( final Section s ) throws IOException; 942 943 /** 944 * Gets a flag indicating that the source code of the editor contains a license section. 945 * 946 * @return {@code true} if the source code of the editor contains a license section; {@code false} if the 947 * source code of the editor does not contain a license section. 948 */ 949 public boolean isLicenseSectionPresent() 950 { 951 return this.licenseSectionPresent; 952 } 953 954 /** 955 * Gets a flag indicating that the source code of the editor contains an annotations section. 956 * 957 * @return {@code true} if the source code of the editor contains an annotations section; {@code false} if the 958 * source code of the editor does not contain an annotations section. 959 */ 960 public boolean isAnnotationsSectionPresent() 961 { 962 return this.annotationsSectionPresent; 963 } 964 965 /** 966 * Gets a flag indicating that the source code of the editor contains a documentation section. 967 * 968 * @return {@code true} if the source code of the editor contains a documentation section; {@code false} if the 969 * source code of the editor does not contain a documentation section. 970 */ 971 public boolean isDocumentationSectionPresent() 972 { 973 return this.documentationSectionPresent; 974 } 975 976 } 977 978 /** 979 * Extension to {@code JavaEditor} for editing specification source code. 980 * 981 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a> 982 * @version $Id: JavaSources.java 891 2009-11-02 03:40:00Z schulte2005 $ 983 */ 984 public class JavaSpecificationEditor extends JavaEditor 985 { 986 987 /** The specification to edit. */ 988 private Specification specification; 989 990 /** 991 * Creates a new {@code JavaSpecificationEditor} instance for editing the source code of a given specification. 992 * 993 * @param specification The specification to edit. 994 */ 995 public JavaSpecificationEditor( final Specification specification ) 996 { 997 super(); 998 this.specification = specification; 999 } 1000 1001 /** 1002 * Creates a new {@code JavaSpecificationEditor} instance for editing the source code of a given specification 1003 * taking a {@code LineEditor} to chain. 1004 * 1005 * @param lineEditor The editor to chain. 1006 * @param specification The specification to edit. 1007 */ 1008 public JavaSpecificationEditor( final LineEditor lineEditor, final Specification specification ) 1009 { 1010 super( lineEditor ); 1011 this.specification = specification; 1012 } 1013 1014 /** 1015 * Edits the license section of the source code of the editor. 1016 * 1017 * @param s The section to edit. 1018 * 1019 * @throws NullPointerException if {@code s} is {@code null}. 1020 * @throws IOException if editing {@code s} fails. 1021 */ 1022 public void editLicenseSection( final Section s ) throws IOException 1023 { 1024 if ( s == null ) 1025 { 1026 throw new NullPointerException( "s" ); 1027 } 1028 1029 s.getHeadContent().setLength( 0 ); 1030 if ( this.specification != null ) 1031 { 1032 s.getHeadContent().append( getLicenseSection( this.specification ) ); 1033 } 1034 } 1035 1036 /** 1037 * Edits the annotations section of the source code of the editor. 1038 * 1039 * @param s The section to edit. 1040 * 1041 * @throws NullPointerException if {@code s} is {@code null}. 1042 * @throws IOException if editing {@code s} fails. 1043 */ 1044 public void editAnnotationsSection( final Section s ) throws IOException 1045 { 1046 if ( s == null ) 1047 { 1048 throw new NullPointerException( "s" ); 1049 } 1050 1051 s.getHeadContent().setLength( 0 ); 1052 if ( this.specification != null ) 1053 { 1054 s.getHeadContent().append( getAnnotationsSection( this.specification ) ); 1055 } 1056 } 1057 1058 /** 1059 * Edits the documentation section of the source code of the editor. 1060 * 1061 * @param s The section to edit. 1062 * 1063 * @throws NullPointerException if {@code s} is {@code null}. 1064 * @throws IOException if editing {@code s} fails. 1065 */ 1066 public void editDocumentationSection( final Section s ) throws IOException 1067 { 1068 if ( s == null ) 1069 { 1070 throw new NullPointerException( "s" ); 1071 } 1072 1073 s.getHeadContent().setLength( 0 ); 1074 if ( this.specification != null ) 1075 { 1076 s.getHeadContent().append( getDocumentationSection( this.specification ) ); 1077 } 1078 } 1079 1080 } 1081 1082 /** 1083 * Extension to {@code JavaEditor} for editing implementation source code. 1084 * 1085 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a> 1086 * @version $Id: JavaSources.java 891 2009-11-02 03:40:00Z schulte2005 $ 1087 */ 1088 public class JavaImplementationEditor extends JavaEditor 1089 { 1090 1091 /** The implementation to edit. */ 1092 private Implementation implementation; 1093 1094 /** Flag indicating that the source code of the editor contains a constructors section. */ 1095 private boolean constructorsSectionPresent; 1096 1097 /** Flag indicating that the source code of the editor contains a default constructor section. */ 1098 private boolean defaultConstructorSectionPresent; 1099 1100 /** Flag indicating that the source code of the editor contains a messages section. */ 1101 private boolean messagesSectionPresent; 1102 1103 /** Flag indicating that the source code of the editor contains a dependencies section. */ 1104 private boolean dependenciesSectionPresent; 1105 1106 /** Flag indicating that the source code of the editor contains a properties section. */ 1107 private boolean propertiesSectionPresent; 1108 1109 /** 1110 * Creates a new {@code JavaImplementationEditor} instance for editing the source code of a given implementation. 1111 * 1112 * @param implementation The implementation to edit. 1113 */ 1114 public JavaImplementationEditor( final Implementation implementation ) 1115 { 1116 super(); 1117 this.implementation = implementation; 1118 } 1119 1120 /** 1121 * Creates a new {@code JavaImplementationEditor} instance for editing the source code of a given implementation 1122 * taking a {@code LineEditor} to chain. 1123 * 1124 * @param lineEditor The editor to chain. 1125 * @param implementation The implementation to edit. 1126 */ 1127 public JavaImplementationEditor( final LineEditor lineEditor, final Implementation implementation ) 1128 { 1129 super( lineEditor ); 1130 this.implementation = implementation; 1131 } 1132 1133 @Override 1134 public String getOutput( final Section section ) throws IOException 1135 { 1136 if ( section == null ) 1137 { 1138 throw new NullPointerException( "section" ); 1139 } 1140 1141 this.constructorsSectionPresent = false; 1142 this.defaultConstructorSectionPresent = false; 1143 this.messagesSectionPresent = false; 1144 this.dependenciesSectionPresent = false; 1145 this.propertiesSectionPresent = false; 1146 return super.getOutput( section ); 1147 } 1148 1149 @Override 1150 public void editSection( final Section section ) throws IOException 1151 { 1152 if ( section == null ) 1153 { 1154 throw new NullPointerException( "section" ); 1155 } 1156 1157 super.editSection( section ); 1158 1159 if ( section.getName() != null ) 1160 { 1161 if ( CONSTRUCTORS_SECTION_NAME.equals( section.getName() ) ) 1162 { 1163 this.editConstructorsSection( section ); 1164 this.constructorsSectionPresent = true; 1165 } 1166 else if ( DEFAULT_CONSTRUCTOR_SECTION_NAME.equals( section.getName() ) ) 1167 { 1168 this.editDefaultConstructorSection( section ); 1169 this.defaultConstructorSectionPresent = true; 1170 } 1171 else if ( DEPENDENCIES_SECTION_NAME.equals( section.getName() ) ) 1172 { 1173 this.editDependenciesSection( section ); 1174 this.dependenciesSectionPresent = true; 1175 } 1176 else if ( MESSAGES_SECTION_NAME.equals( section.getName() ) ) 1177 { 1178 this.editMessagesSection( section ); 1179 this.messagesSectionPresent = true; 1180 } 1181 else if ( PROPERTIES_SECTION_NAME.equals( section.getName() ) ) 1182 { 1183 this.editPropertiesSection( section ); 1184 this.propertiesSectionPresent = true; 1185 } 1186 } 1187 } 1188 1189 /** 1190 * Edits the license section of the source code of the editor. 1191 * 1192 * @param s The section to edit. 1193 * 1194 * @throws IOException if editing {@code s} fails. 1195 */ 1196 public void editLicenseSection( final Section s ) throws IOException 1197 { 1198 if ( s == null ) 1199 { 1200 throw new NullPointerException( "s" ); 1201 } 1202 1203 s.getHeadContent().setLength( 0 ); 1204 if ( this.implementation != null ) 1205 { 1206 s.getHeadContent().append( getLicenseSection( this.implementation ) ); 1207 } 1208 } 1209 1210 /** 1211 * Edits the annotations section of the source code of the editor. 1212 * 1213 * @param s The section to edit. 1214 * 1215 * @throws NullPointerException if {@code s} is {@code null}. 1216 * @throws IOException if editing {@code s} fails. 1217 */ 1218 public void editAnnotationsSection( final Section s ) throws IOException 1219 { 1220 if ( s == null ) 1221 { 1222 throw new NullPointerException( "s" ); 1223 } 1224 1225 s.getHeadContent().setLength( 0 ); 1226 if ( this.implementation != null ) 1227 { 1228 s.getHeadContent().append( getAnnotationsSection( this.implementation ) ); 1229 } 1230 } 1231 1232 /** 1233 * Edits the documentation section of the source code of the editor. 1234 * 1235 * @param s The section to edit. 1236 * 1237 * @throws NullPointerException if {@code s} is {@code null}. 1238 * @throws IOException if editing {@code s} fails. 1239 */ 1240 public void editDocumentationSection( final Section s ) throws IOException 1241 { 1242 if ( s == null ) 1243 { 1244 throw new NullPointerException( "s" ); 1245 } 1246 1247 s.getHeadContent().setLength( 0 ); 1248 if ( this.implementation != null ) 1249 { 1250 s.getHeadContent().append( getDocumentationSection( this.implementation ) ); 1251 } 1252 } 1253 1254 /** 1255 * Edits the constructors section of the source code of the editor. 1256 * 1257 * @param s The section to edit. 1258 * 1259 * @throws NullPointerException if {@code s} is {@code null}. 1260 * @throws IOException if editing {@code s} fails. 1261 */ 1262 public void editConstructorsSection( final Section s ) throws IOException 1263 { 1264 if ( s == null ) 1265 { 1266 throw new NullPointerException( "s" ); 1267 } 1268 1269 s.getHeadContent().setLength( 0 ); 1270 s.getTailContent().setLength( 0 ); 1271 1272 if ( this.implementation != null ) 1273 { 1274 s.getHeadContent().append( getConstructorsSectionHeadContent( this.implementation ) ); 1275 s.getTailContent().append( getConstructorsSectionTailContent( this.implementation ) ); 1276 } 1277 1278 for ( Section child : s.getSections() ) 1279 { 1280 if ( child.getName() != null && DEFAULT_CONSTRUCTOR_SECTION_NAME.equals( child.getName() ) ) 1281 { 1282 this.defaultConstructorSectionPresent = true; 1283 break; 1284 } 1285 } 1286 1287 if ( !this.defaultConstructorSectionPresent ) 1288 { 1289 final Section defaultCtor = new Section(); 1290 defaultCtor.setName( DEFAULT_CONSTRUCTOR_SECTION_NAME ); 1291 defaultCtor.setStartingLine( " // SECTION-START[" + DEFAULT_CONSTRUCTOR_SECTION_NAME + "]" ); 1292 defaultCtor.setEndingLine( " // SECTION-END" ); 1293 defaultCtor.getHeadContent().append( " super();" ).append( this.getLineSeparator() ); 1294 s.getSections().add( defaultCtor ); 1295 this.defaultConstructorSectionPresent = true; 1296 } 1297 } 1298 1299 /** 1300 * Edits the default constructor section of the source code of the editor. 1301 * 1302 * @param s The section to edit. 1303 * 1304 * @throws NullPointerException if {@code s} is {@code null}. 1305 * @throws IOException if editing {@code s} fails. 1306 */ 1307 public void editDefaultConstructorSection( final Section s ) throws IOException 1308 { 1309 if ( s == null ) 1310 { 1311 throw new NullPointerException( "s" ); 1312 } 1313 1314 if ( s.getHeadContent().toString().trim().length() == 0 ) 1315 { 1316 s.getHeadContent().setLength( 0 ); 1317 1318 if ( this.implementation != null ) 1319 { 1320 s.getHeadContent().append( " super();" ).append( this.getLineSeparator() ); 1321 } 1322 } 1323 } 1324 1325 /** 1326 * Edits the dependencies section of the source code of the editor. 1327 * 1328 * @param s The section to edit. 1329 * 1330 * @throws NullPointerException if {@code s} is {@code null}. 1331 * @throws IOException if editing {@code s} fails. 1332 */ 1333 public void editDependenciesSection( final Section s ) throws IOException 1334 { 1335 if ( s == null ) 1336 { 1337 throw new NullPointerException( "s" ); 1338 } 1339 1340 s.getHeadContent().setLength( 0 ); 1341 if ( this.implementation != null ) 1342 { 1343 s.getHeadContent().append( getDependenciesSection( this.implementation ) ); 1344 } 1345 } 1346 1347 /** 1348 * Edits the messages section of the source code of the editor. 1349 * 1350 * @param s The section to edit. 1351 * 1352 * @throws NullPointerException if {@code s} is {@code null}. 1353 * @throws IOException if editing {@code s} fails. 1354 */ 1355 public void editMessagesSection( final Section s ) throws IOException 1356 { 1357 if ( s == null ) 1358 { 1359 throw new NullPointerException( "s" ); 1360 } 1361 1362 s.getHeadContent().setLength( 0 ); 1363 if ( this.implementation != null ) 1364 { 1365 s.getHeadContent().append( getMessagesSection( this.implementation ) ); 1366 } 1367 } 1368 1369 /** 1370 * Edits the properties section of the source code of the editor. 1371 * 1372 * @param s The section to edit. 1373 * 1374 * @throws NullPointerException if {@code s} is {@code null}. 1375 * @throws IOException if editing {@code s} fails. 1376 */ 1377 public void editPropertiesSection( final Section s ) throws IOException 1378 { 1379 if ( s == null ) 1380 { 1381 throw new NullPointerException( "s" ); 1382 } 1383 1384 s.getHeadContent().setLength( 0 ); 1385 if ( this.implementation != null ) 1386 { 1387 s.getHeadContent().append( getPropertiesSection( this.implementation ) ); 1388 } 1389 } 1390 1391 /** 1392 * Gets a flag indicating that the source code of the editor contains a constructors section. 1393 * 1394 * @return {@code true} if the source code of the editor contains a constructors section; {@code false} if the 1395 * source code of the editor does not contain a constructors section. 1396 */ 1397 public boolean isConstructorsSectionPresent() 1398 { 1399 return this.constructorsSectionPresent; 1400 } 1401 1402 /** 1403 * Gets a flag indicating that the source code of the editor contains a default constructor section. 1404 * 1405 * @return {@code true} if the source code of the editor contains a default constructor section; {@code false} 1406 * if the source code of the editor does not contain a default constructor section. 1407 */ 1408 public boolean isDefaultConstructorSectionPresent() 1409 { 1410 return this.defaultConstructorSectionPresent; 1411 } 1412 1413 /** 1414 * Gets a flag indicating that the source code of the editor contains a messages section. 1415 * 1416 * @return {@code true} if the source code of the editor contains a messages section; {@code false} 1417 * if the source code of the editor does not contain a messages section. 1418 */ 1419 public boolean isMessagesSectionPresent() 1420 { 1421 return this.messagesSectionPresent; 1422 } 1423 1424 /** 1425 * Gets a flag indicating that the source code of the editor contains a dependencies section. 1426 * 1427 * @return {@code true} if the source code of the editor contains a dependencies section; {@code false} 1428 * if the source code of the editor does not contain a dependencies section. 1429 */ 1430 public boolean isDependenciesSectionPresent() 1431 { 1432 return this.dependenciesSectionPresent; 1433 } 1434 1435 /** 1436 * Gets a flag indicating that the source code of the editor contains a properties section. 1437 * 1438 * @return {@code true} if the source code of the editor contains a properties section; {@code false} 1439 * if the source code of the editor does not contain a properties section. 1440 */ 1441 public boolean isPropertiesSectionPresent() 1442 { 1443 return this.propertiesSectionPresent; 1444 } 1445 1446 } 1447 1448 }