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 744 2009-10-06 04:43:21Z 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 744 2009-10-06 04:43:21Z 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() )
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() )
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 FileUtils.writeStringToFile( f, edited, this.getOutputEncoding() );
312 this.log( Level.INFO, this.getMessage( "editing", new Object[]
313 {
314 f.getCanonicalPath()
315 } ), null );
316
317 }
318 }
319 }
320
321 /**
322 * Manages the source code of a given implementation of the modules of the instance.
323 *
324 * @param implementation The implementation to process.
325 * @param sourcesDirectory The directory holding the sources to manage.
326 *
327 * @throws NullPointerException if {@code implementation} or {@code sourcesDirectory} is {@code null}.
328 * @throws IOException if managing sources fails.
329 *
330 * @see #getImplementationEditor(org.jomc.model.Implementation)
331 */
332 public void manageSources( final Implementation implementation, final File sourcesDirectory ) throws IOException
333 {
334 if ( implementation == null )
335 {
336 throw new NullPointerException( "implementation" );
337 }
338 if ( sourcesDirectory == null )
339 {
340 throw new NullPointerException( "sourcesDirectory" );
341 }
342
343 if ( this.isJavaClassDeclaration( implementation ) )
344 {
345 final File f = new File( sourcesDirectory, implementation.getClazz().replace( '.', '/' ) + ".java" );
346 final String content = f.exists()
347 ? FileUtils.readFileToString( f, this.getInputEncoding() )
348 : this.getImplementationTemplate( implementation );
349
350 final JavaImplementationEditor editor = this.getImplementationEditor( implementation );
351 final String edited;
352 try
353 {
354 edited = editor.edit( content );
355 }
356 catch ( final IOException e )
357 {
358 throw (IOException) new IOException( this.getMessage( "failedEditing", new Object[]
359 {
360 f.getCanonicalPath(), e.getMessage()
361 } ) ).initCause( e );
362
363 }
364
365 if ( !editor.isLicenseSectionPresent() )
366 {
367 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[]
368 {
369 LICENSE_SECTION_NAME,
370 f.getCanonicalPath()
371 } ), null );
372
373 }
374
375 if ( !editor.isAnnotationsSectionPresent() )
376 {
377 throw new IOException( this.getMessage( "missingSection", new Object[]
378 {
379 ANNOTATIONS_SECTION_NAME,
380 f.getCanonicalPath()
381 } ) );
382
383 }
384
385 if ( !editor.isDocumentationSectionPresent() )
386 {
387 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[]
388 {
389 DOCUMENTATION_SECTION_NAME,
390 f.getCanonicalPath()
391 } ), null );
392
393 }
394
395 if ( !editor.isConstructorsSectionPresent() )
396 {
397 final Specifications specifications =
398 this.getModules().getSpecifications( implementation.getIdentifier() );
399
400 if ( specifications != null &&
401 !( specifications.getSpecification().isEmpty() && specifications.getReference().isEmpty() ) )
402 {
403 throw new IOException( this.getMessage( "missingSection", new Object[]
404 {
405 CONSTRUCTORS_SECTION_NAME,
406 f.getCanonicalPath()
407 } ) );
408
409 }
410 else
411 {
412 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[]
413 {
414 CONSTRUCTORS_SECTION_NAME,
415 f.getCanonicalPath()
416 } ), null );
417
418 }
419 }
420 else if ( !editor.isDefaultConstructorSectionPresent() )
421 {
422 throw new IOException( this.getMessage( "missingSection", new Object[]
423 {
424 DEFAULT_CONSTRUCTOR_SECTION_NAME,
425 f.getCanonicalPath()
426 } ) );
427
428 }
429
430 if ( !editor.isPropertiesSectionPresent() )
431 {
432 final Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
433
434 if ( properties != null && !properties.getProperty().isEmpty() )
435 {
436 throw new IOException( this.getMessage( "missingSection", new Object[]
437 {
438 PROPERTIES_SECTION_NAME,
439 f.getCanonicalPath()
440 } ) );
441
442 }
443 else
444 {
445 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[]
446 {
447 PROPERTIES_SECTION_NAME,
448 f.getCanonicalPath()
449 } ), null );
450
451 }
452 }
453
454 if ( !editor.isDependenciesSectionPresent() )
455 {
456 final Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
457
458 if ( dependencies != null && !dependencies.getDependency().isEmpty() )
459 {
460 throw new IOException( this.getMessage( "missingSection", new Object[]
461 {
462 DEPENDENCIES_SECTION_NAME,
463 f.getCanonicalPath()
464 } ) );
465
466 }
467 else
468 {
469 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[]
470 {
471 DEPENDENCIES_SECTION_NAME,
472 f.getCanonicalPath()
473 } ), null );
474
475 }
476 }
477
478 if ( !editor.isMessagesSectionPresent() )
479 {
480 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
481
482 if ( messages != null && !messages.getMessage().isEmpty() )
483 {
484 throw new IOException( this.getMessage( "missingSection", new Object[]
485 {
486 MESSAGES_SECTION_NAME,
487 f.getCanonicalPath()
488 } ) );
489
490 }
491 else
492 {
493 this.log( Level.INFO, this.getMessage( "missingOptionalSection", new Object[]
494 {
495 MESSAGES_SECTION_NAME,
496 f.getCanonicalPath()
497 } ), null );
498
499 }
500 }
501
502 if ( !edited.equals( content ) )
503 {
504 if ( !f.getParentFile().exists() && !f.getParentFile().mkdirs() )
505 {
506 throw new IOException( this.getMessage( "failedCreatingDirectory", new Object[]
507 {
508 f.getParentFile().getAbsolutePath()
509 } ) );
510
511 }
512
513 FileUtils.writeStringToFile( f, edited, this.getOutputEncoding() );
514 this.log( Level.INFO, this.getMessage( "editing", new Object[]
515 {
516 f.getCanonicalPath()
517 } ), null );
518
519 }
520 }
521 }
522
523 /**
524 * Gets a new editor for editing Java specification source code.
525 *
526 * @param specification The specification to create a new editor for.
527 *
528 * @return A new editor for editing the source code of {@code specification}.
529 *
530 * @throws NullPointerException if {@code specification} is {@code null}.
531 */
532 public JavaSpecificationEditor getSpecificationEditor( final Specification specification )
533 {
534 if ( specification == null )
535 {
536 throw new NullPointerException( "specification" );
537 }
538
539 return new JavaSpecificationEditor( new TrailingWhitespaceEditor(), specification );
540 }
541
542 /**
543 * Gets a new editor for editing Java implementation source code.
544 *
545 * @param implementation The implementation to create a new editor for.
546 *
547 * @return A new editor for editing the source code of {@code implementation}.
548 *
549 * @throws NullPointerException if {@code implementation} is {@code null}.
550 */
551 public JavaImplementationEditor getImplementationEditor( final Implementation implementation )
552 {
553 if ( implementation == null )
554 {
555 throw new NullPointerException( "implementation" );
556 }
557
558 return new JavaImplementationEditor( new TrailingWhitespaceEditor(), implementation );
559 }
560
561 /**
562 * Gets the velocity context used for merging templates.
563 *
564 * @return The velocity context used for merging templates.
565 */
566 @Override
567 public VelocityContext getVelocityContext()
568 {
569 final VelocityContext ctx = super.getVelocityContext();
570 ctx.put( "generatorName", GENERATOR_NAME );
571 ctx.put( "generatorVersion", GENERATOR_VERSION );
572 return ctx;
573 }
574
575 /**
576 * Gets the Java source code template of specification.
577 *
578 * @param specification The specification to get the source code template of.
579 *
580 * @throws IOException if getting the source code section fails.
581 */
582 private String getSpecificationTemplate( final Specification specification ) throws IOException
583 {
584 final StringWriter writer = new StringWriter();
585 final VelocityContext ctx = this.getVelocityContext();
586 final Template template = this.getVelocityTemplate( SPECIFICATION_TEMPLATE );
587 ctx.put( "specification", specification );
588 ctx.put( "template", template );
589 template.merge( ctx, writer );
590 writer.close();
591 return writer.toString();
592 }
593
594 /**
595 * Gets the Java source code template of an implementation.
596 *
597 * @param implementation The implementation to get the source code template of.
598 *
599 * @throws IOException if getting the source code section fails.
600 */
601 private String getImplementationTemplate( final Implementation implementation ) throws IOException
602 {
603 final StringWriter writer = new StringWriter();
604 final VelocityContext ctx = this.getVelocityContext();
605 final Template template = this.getVelocityTemplate( IMPLEMENTATION_TEMPLATE );
606 ctx.put( "implementation", implementation );
607 ctx.put( "template", template );
608 template.merge( ctx, writer );
609 writer.close();
610 return writer.toString();
611 }
612
613 /**
614 * Gets the Java source code of the license section of a specification.
615 *
616 * @param specification The specification to get the source code of the license section of.
617 *
618 * @throws IOException if getting the source code section fails.
619 */
620 private String getLicenseSection( final Specification specification ) throws IOException
621 {
622 final StringWriter writer = new StringWriter();
623 final VelocityContext ctx = this.getVelocityContext();
624 final Template template = this.getVelocityTemplate( SPECIFICATION_LICENSE_TEMPLATE );
625 ctx.put( "specification", specification );
626 ctx.put( "template", template );
627 template.merge( ctx, writer );
628 writer.close();
629 return writer.toString();
630 }
631
632 /**
633 * Gets the Java source code of the license section of an implementation..
634 *
635 * @param implementation The implementation to get the source code of the license section of.
636 *
637 * @throws IOException if getting the source code section fails.
638 */
639 private String getLicenseSection( final Implementation implementation ) throws IOException
640 {
641 final StringWriter writer = new StringWriter();
642 final VelocityContext ctx = this.getVelocityContext();
643 final Template template = this.getVelocityTemplate( IMPLEMENTATION_LICENSE_TEMPLATE );
644 ctx.put( "implementation", implementation );
645 ctx.put( "template", template );
646 template.merge( ctx, writer );
647 writer.close();
648 return writer.toString();
649 }
650
651 /**
652 * Gets the Java source code of the specification annotations section.
653 *
654 * @param specification The specification to get the source code of the annotations section of.
655 *
656 * @throws IOException if getting the source code section fails.
657 */
658 private String getAnnotationsSection( final Specification specification ) throws IOException
659 {
660 final StringWriter writer = new StringWriter();
661 final VelocityContext ctx = this.getVelocityContext();
662 final Template template = this.getVelocityTemplate( SPECIFICATION_ANNOTATIONS_TEMPLATE );
663 ctx.put( "specification", specification );
664 ctx.put( "template", template );
665 template.merge( ctx, writer );
666 writer.close();
667 return writer.toString();
668 }
669
670 /**
671 * Gets the Java source code of the implementation annotations section.
672 *
673 * @param implementation The implementation to get the source code of the annotations section of.
674 *
675 * @throws IOException if getting the source code section fails.
676 */
677 private String getAnnotationsSection( final Implementation implementation ) throws IOException
678 {
679 final StringWriter writer = new StringWriter();
680 final VelocityContext ctx = this.getVelocityContext();
681 final Template template = this.getVelocityTemplate( IMPLEMENTATION_ANNOTATIONS_TEMPLATE );
682 ctx.put( "implementation", implementation );
683 ctx.put( "template", template );
684 template.merge( ctx, writer );
685 writer.close();
686 return writer.toString();
687 }
688
689 /**
690 * Gets the Java source code of the documentation section of a specification.
691 *
692 * @param specification The specification to get the source code section of.
693 *
694 * @throws IOException if getting the source code section fails.
695 */
696 private String getDocumentationSection( final Specification specification ) throws IOException
697 {
698 final StringWriter writer = new StringWriter();
699 final VelocityContext ctx = this.getVelocityContext();
700 final Template template = this.getVelocityTemplate( SPECIFICATION_DOCUMENTATION_TEMPLATE );
701 ctx.put( "specification", specification );
702 ctx.put( "template", template );
703 template.merge( ctx, writer );
704 writer.close();
705 return writer.toString();
706 }
707
708 /**
709 * Gets the Java source code of the documentation section of an implementation.
710 *
711 * @param implementation The implementation to get the source code section of.
712 *
713 * @throws IOException if getting the source code section fails.
714 */
715 private String getDocumentationSection( final Implementation implementation ) throws IOException
716 {
717 final StringWriter writer = new StringWriter();
718 final VelocityContext ctx = this.getVelocityContext();
719 final Template template = this.getVelocityTemplate( IMPLEMENTATION_DOCUMENTATION_TEMPLATE );
720 ctx.put( "implementation", implementation );
721 ctx.put( "template", template );
722 template.merge( ctx, writer );
723 writer.close();
724 return writer.toString();
725 }
726
727 /**
728 * Gets the Java source code of the constructors section head content of an implementation.
729 *
730 * @param implementation The implementation to get the constructors section head content of.
731 *
732 * @throws IOException if getting the source code section fails.
733 */
734 private String getConstructorsSectionHeadContent( final Implementation implementation ) throws IOException
735 {
736 final StringWriter writer = new StringWriter();
737 final VelocityContext ctx = this.getVelocityContext();
738 final Template template = this.getVelocityTemplate( CONSTRUCTORS_HEAD_TEMPLATE );
739 ctx.put( "implementation", implementation );
740 ctx.put( "template", template );
741 template.merge( ctx, writer );
742 writer.close();
743 return writer.toString();
744 }
745
746 /**
747 * Gets the Java source code of the constructors section tail content of an implementation.
748 *
749 * @param implementation The implementation to get the constructors section tail content of.
750 *
751 * @throws IOException if getting the source code section fails.
752 */
753 private String getConstructorsSectionTailContent( final Implementation implementation ) throws IOException
754 {
755 final StringWriter writer = new StringWriter();
756 final VelocityContext ctx = this.getVelocityContext();
757 final Template template = this.getVelocityTemplate( CONSTRUCTORS_TAIL_TEMPLATE );
758 ctx.put( "implementation", implementation );
759 ctx.put( "template", template );
760 template.merge( ctx, writer );
761 writer.close();
762 return writer.toString();
763 }
764
765 /**
766 * Gets the Java source code of the dependencies section of an implementation.
767 *
768 * @param implementation The implementation to get the source code of the dependencies section of.
769 *
770 * @throws IOException if getting the source code section fails.
771 */
772 private String getDependenciesSection( final Implementation implementation ) throws IOException
773 {
774 final StringWriter writer = new StringWriter();
775 final VelocityContext ctx = this.getVelocityContext();
776 final Template template = this.getVelocityTemplate( DEPENDENCIES_TEMPLATE );
777 ctx.put( "implementation", implementation );
778 ctx.put( "template", template );
779 template.merge( ctx, writer );
780 writer.close();
781 return writer.toString();
782 }
783
784 /**
785 * Gets the Java source code of the properties section of an implementation.
786 *
787 * @param implementation The implementation to get the source code of the properties section of.
788 *
789 * @throws IOException if getting the source code section fails.
790 */
791 private String getPropertiesSection( final Implementation implementation ) throws IOException
792 {
793 final StringWriter writer = new StringWriter();
794 final VelocityContext ctx = this.getVelocityContext();
795 final Template template = this.getVelocityTemplate( PROPERTIES_TEMPLATE );
796 ctx.put( "implementation", implementation );
797 ctx.put( "template", template );
798 template.merge( ctx, writer );
799 writer.close();
800 return writer.toString();
801 }
802
803 /**
804 * Gets the Java source code of the messages section of an implementation.
805 *
806 * @param implementation The implementation to get the source code of the messages section of.
807 *
808 * @throws IOException if getting the source code section fails.
809 */
810 private String getMessagesSection( final Implementation implementation ) throws IOException
811 {
812 final StringWriter writer = new StringWriter();
813 final VelocityContext ctx = this.getVelocityContext();
814 final Template template = this.getVelocityTemplate( MESSAGES_TEMPLATE );
815 ctx.put( "implementation", implementation );
816 ctx.put( "template", template );
817 template.merge( ctx, writer );
818 writer.close();
819 return writer.toString();
820 }
821
822 private String getMessage( final String key, final Object args )
823 {
824 final ResourceBundle b = ResourceBundle.getBundle( JavaSources.class.getName().replace( '.', '/' ) );
825 final MessageFormat f = new MessageFormat( b.getString( key ) );
826 return f.format( args );
827 }
828
829 /**
830 * Extension to {@code SectionEditor} for editing Java source code.
831 *
832 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
833 * @version $Id: JavaSources.java 744 2009-10-06 04:43:21Z schulte2005 $
834 */
835 public abstract class JavaEditor extends SectionEditor
836 {
837
838 /** Flag indicating that the source code of the editor contains a license section. */
839 private boolean licenseSectionPresent;
840
841 /** Flag indicating that the source code of the editor contains an annotations section. */
842 private boolean annotationsSectionPresent;
843
844 /** Flag indicating that the source code of the editor contains a documentation section. */
845 private boolean documentationSectionPresent;
846
847 /** Creates a new {@code JavaEditor} instance. */
848 public JavaEditor()
849 {
850 super();
851 }
852
853 /**
854 * Creates a new {@code JavaEditor} instance taking a {@code LineEditor} to chain.
855 *
856 * @param lineEditor The editor to chain.
857 */
858 public JavaEditor( final LineEditor lineEditor )
859 {
860 super( lineEditor );
861 }
862
863 @Override
864 public String getOutput( final Section section ) throws IOException
865 {
866 if ( section == null )
867 {
868 throw new NullPointerException( "section" );
869 }
870
871 this.licenseSectionPresent = false;
872 this.annotationsSectionPresent = false;
873 this.documentationSectionPresent = false;
874 return super.getOutput( section );
875 }
876
877 @Override
878 public void editSection( final Section section ) throws IOException
879 {
880 if ( section == null )
881 {
882 throw new NullPointerException( "section" );
883 }
884
885 if ( section.getName() != null )
886 {
887 if ( LICENSE_SECTION_NAME.equals( section.getName() ) )
888 {
889 this.editLicenseSection( section );
890 this.licenseSectionPresent = true;
891 }
892 if ( ANNOTATIONS_SECTION_NAME.equals( section.getName() ) )
893 {
894 this.editAnnotationsSection( section );
895 this.annotationsSectionPresent = true;
896 }
897 if ( DOCUMENTATION_SECTION_NAME.equals( section.getName() ) )
898 {
899 this.editDocumentationSection( section );
900 this.documentationSectionPresent = true;
901 }
902 }
903 }
904
905 /**
906 * Edits the license section of the source code of the editor.
907 *
908 * @param s The section to edit.
909 *
910 * @throws NullPointerException if {@code s} is {@code null}.
911 * @throws IOException if editing {@code s} fails.
912 */
913 public abstract void editLicenseSection( final Section s ) throws IOException;
914
915 /**
916 * Edits the annotations section of the source code of the editor.
917 *
918 * @param s The section to edit.
919 *
920 * @throws NullPointerException if {@code s} is {@code null}.
921 * @throws IOException if editing {@code s} fails.
922 */
923 public abstract void editAnnotationsSection( final Section s ) throws IOException;
924
925 /**
926 * Edits the documentation section of the source code of the editor.
927 *
928 * @param s The section to edit.
929 *
930 * @throws NullPointerException if {@code s} is {@code null}.
931 * @throws IOException if editing {@code s} fails.
932 */
933 public abstract void editDocumentationSection( final Section s ) throws IOException;
934
935 /**
936 * Gets a flag indicating that the source code of the editor contains a license section.
937 *
938 * @return {@code true} if the source code of the editor contains a license section; {@code false} if the
939 * source code of the editor does not contain a license section.
940 */
941 public boolean isLicenseSectionPresent()
942 {
943 return this.licenseSectionPresent;
944 }
945
946 /**
947 * Gets a flag indicating that the source code of the editor contains an annotations section.
948 *
949 * @return {@code true} if the source code of the editor contains an annotations section; {@code false} if the
950 * source code of the editor does not contain an annotations section.
951 */
952 public boolean isAnnotationsSectionPresent()
953 {
954 return this.annotationsSectionPresent;
955 }
956
957 /**
958 * Gets a flag indicating that the source code of the editor contains a documentation section.
959 *
960 * @return {@code true} if the source code of the editor contains a documentation section; {@code false} if the
961 * source code of the editor does not contain a documentation section.
962 */
963 public boolean isDocumentationSectionPresent()
964 {
965 return this.documentationSectionPresent;
966 }
967
968 }
969
970 /**
971 * Extension to {@code JavaEditor} for editing specification source code.
972 *
973 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
974 * @version $Id: JavaSources.java 744 2009-10-06 04:43:21Z schulte2005 $
975 */
976 public class JavaSpecificationEditor extends JavaEditor
977 {
978
979 /** The specification to edit. */
980 private Specification specification;
981
982 /**
983 * Creates a new {@code JavaSpecificationEditor} instance for editing the source code of a given specification.
984 *
985 * @param specification The specification to edit.
986 */
987 public JavaSpecificationEditor( final Specification specification )
988 {
989 super();
990 this.specification = specification;
991 }
992
993 /**
994 * Creates a new {@code JavaSpecificationEditor} instance for editing the source code of a given specification
995 * taking a {@code LineEditor} to chain.
996 *
997 * @param lineEditor The editor to chain.
998 * @param specification The specification to edit.
999 */
1000 public JavaSpecificationEditor( final LineEditor lineEditor, final Specification specification )
1001 {
1002 super( lineEditor );
1003 this.specification = specification;
1004 }
1005
1006 /**
1007 * Edits the license section of the source code of the editor.
1008 *
1009 * @param s The section to edit.
1010 *
1011 * @throws NullPointerException if {@code s} is {@code null}.
1012 * @throws IOException if editing {@code s} fails.
1013 */
1014 public void editLicenseSection( final Section s ) throws IOException
1015 {
1016 if ( s == null )
1017 {
1018 throw new NullPointerException( "s" );
1019 }
1020
1021 s.getHeadContent().setLength( 0 );
1022 if ( this.specification != null )
1023 {
1024 s.getHeadContent().append( getLicenseSection( this.specification ) );
1025 }
1026 }
1027
1028 /**
1029 * Edits the annotations section of the source code of the editor.
1030 *
1031 * @param s The section to edit.
1032 *
1033 * @throws NullPointerException if {@code s} is {@code null}.
1034 * @throws IOException if editing {@code s} fails.
1035 */
1036 public void editAnnotationsSection( final Section s ) throws IOException
1037 {
1038 if ( s == null )
1039 {
1040 throw new NullPointerException( "s" );
1041 }
1042
1043 s.getHeadContent().setLength( 0 );
1044 if ( this.specification != null )
1045 {
1046 s.getHeadContent().append( getAnnotationsSection( this.specification ) );
1047 }
1048 }
1049
1050 /**
1051 * Edits the documentation section of the source code of the editor.
1052 *
1053 * @param s The section to edit.
1054 *
1055 * @throws NullPointerException if {@code s} is {@code null}.
1056 * @throws IOException if editing {@code s} fails.
1057 */
1058 public void editDocumentationSection( final Section s ) throws IOException
1059 {
1060 if ( s == null )
1061 {
1062 throw new NullPointerException( "s" );
1063 }
1064
1065 s.getHeadContent().setLength( 0 );
1066 if ( this.specification != null )
1067 {
1068 s.getHeadContent().append( getDocumentationSection( this.specification ) );
1069 }
1070 }
1071
1072 }
1073
1074 /**
1075 * Extension to {@code JavaEditor} for editing implementation source code.
1076 *
1077 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
1078 * @version $Id: JavaSources.java 744 2009-10-06 04:43:21Z schulte2005 $
1079 */
1080 public class JavaImplementationEditor extends JavaEditor
1081 {
1082
1083 /** The implementation to edit. */
1084 private Implementation implementation;
1085
1086 /** Flag indicating that the source code of the editor contains a constructors section. */
1087 private boolean constructorsSectionPresent;
1088
1089 /** Flag indicating that the source code of the editor contains a default constructor section. */
1090 private boolean defaultConstructorSectionPresent;
1091
1092 /** Flag indicating that the source code of the editor contains a messages section. */
1093 private boolean messagesSectionPresent;
1094
1095 /** Flag indicating that the source code of the editor contains a dependencies section. */
1096 private boolean dependenciesSectionPresent;
1097
1098 /** Flag indicating that the source code of the editor contains a properties section. */
1099 private boolean propertiesSectionPresent;
1100
1101 /**
1102 * Creates a new {@code JavaImplementationEditor} instance for editing the source code of a given implementation.
1103 *
1104 * @param implementation The implementation to edit.
1105 */
1106 public JavaImplementationEditor( final Implementation implementation )
1107 {
1108 super();
1109 this.implementation = implementation;
1110 }
1111
1112 /**
1113 * Creates a new {@code JavaImplementationEditor} instance for editing the source code of a given implementation
1114 * taking a {@code LineEditor} to chain.
1115 *
1116 * @param lineEditor The editor to chain.
1117 * @param implementation The implementation to edit.
1118 */
1119 public JavaImplementationEditor( final LineEditor lineEditor, final Implementation implementation )
1120 {
1121 super( lineEditor );
1122 this.implementation = implementation;
1123 }
1124
1125 @Override
1126 public String getOutput( final Section section ) throws IOException
1127 {
1128 if ( section == null )
1129 {
1130 throw new NullPointerException( "section" );
1131 }
1132
1133 this.constructorsSectionPresent = false;
1134 this.defaultConstructorSectionPresent = false;
1135 this.messagesSectionPresent = false;
1136 this.dependenciesSectionPresent = false;
1137 this.propertiesSectionPresent = false;
1138 return super.getOutput( section );
1139 }
1140
1141 @Override
1142 public void editSection( final Section section ) throws IOException
1143 {
1144 if ( section == null )
1145 {
1146 throw new NullPointerException( "section" );
1147 }
1148
1149 super.editSection( section );
1150
1151 if ( section.getName() != null )
1152 {
1153 if ( CONSTRUCTORS_SECTION_NAME.equals( section.getName() ) )
1154 {
1155 this.editConstructorsSection( section );
1156 this.constructorsSectionPresent = true;
1157 }
1158 else if ( DEFAULT_CONSTRUCTOR_SECTION_NAME.equals( section.getName() ) )
1159 {
1160 this.editDefaultConstructorSection( section );
1161 this.defaultConstructorSectionPresent = true;
1162 }
1163 else if ( DEPENDENCIES_SECTION_NAME.equals( section.getName() ) )
1164 {
1165 this.editDependenciesSection( section );
1166 this.dependenciesSectionPresent = true;
1167 }
1168 else if ( MESSAGES_SECTION_NAME.equals( section.getName() ) )
1169 {
1170 this.editMessagesSection( section );
1171 this.messagesSectionPresent = true;
1172 }
1173 else if ( PROPERTIES_SECTION_NAME.equals( section.getName() ) )
1174 {
1175 this.editPropertiesSection( section );
1176 this.propertiesSectionPresent = true;
1177 }
1178 }
1179 }
1180
1181 /**
1182 * Edits the license section of the source code of the editor.
1183 *
1184 * @param s The section to edit.
1185 *
1186 * @throws IOException if editing {@code s} fails.
1187 */
1188 public void editLicenseSection( final Section s ) throws IOException
1189 {
1190 if ( s == null )
1191 {
1192 throw new NullPointerException( "s" );
1193 }
1194
1195 s.getHeadContent().setLength( 0 );
1196 if ( this.implementation != null )
1197 {
1198 s.getHeadContent().append( getLicenseSection( this.implementation ) );
1199 }
1200 }
1201
1202 /**
1203 * Edits the annotations section of the source code of the editor.
1204 *
1205 * @param s The section to edit.
1206 *
1207 * @throws NullPointerException if {@code s} is {@code null}.
1208 * @throws IOException if editing {@code s} fails.
1209 */
1210 public void editAnnotationsSection( final Section s ) throws IOException
1211 {
1212 if ( s == null )
1213 {
1214 throw new NullPointerException( "s" );
1215 }
1216
1217 s.getHeadContent().setLength( 0 );
1218 if ( this.implementation != null )
1219 {
1220 s.getHeadContent().append( getAnnotationsSection( this.implementation ) );
1221 }
1222 }
1223
1224 /**
1225 * Edits the documentation section of the source code of the editor.
1226 *
1227 * @param s The section to edit.
1228 *
1229 * @throws NullPointerException if {@code s} is {@code null}.
1230 * @throws IOException if editing {@code s} fails.
1231 */
1232 public void editDocumentationSection( final Section s ) throws IOException
1233 {
1234 if ( s == null )
1235 {
1236 throw new NullPointerException( "s" );
1237 }
1238
1239 s.getHeadContent().setLength( 0 );
1240 if ( this.implementation != null )
1241 {
1242 s.getHeadContent().append( getDocumentationSection( this.implementation ) );
1243 }
1244 }
1245
1246 /**
1247 * Edits the constructors section of the source code of the editor.
1248 *
1249 * @param s The section to edit.
1250 *
1251 * @throws NullPointerException if {@code s} is {@code null}.
1252 * @throws IOException if editing {@code s} fails.
1253 */
1254 public void editConstructorsSection( final Section s ) throws IOException
1255 {
1256 if ( s == null )
1257 {
1258 throw new NullPointerException( "s" );
1259 }
1260
1261 s.getHeadContent().setLength( 0 );
1262 s.getTailContent().setLength( 0 );
1263
1264 if ( this.implementation != null )
1265 {
1266 s.getHeadContent().append( getConstructorsSectionHeadContent( this.implementation ) );
1267 s.getTailContent().append( getConstructorsSectionTailContent( this.implementation ) );
1268 }
1269
1270 for ( Section child : s.getSections() )
1271 {
1272 if ( child.getName() != null && DEFAULT_CONSTRUCTOR_SECTION_NAME.equals( child.getName() ) )
1273 {
1274 this.defaultConstructorSectionPresent = true;
1275 break;
1276 }
1277 }
1278
1279 if ( !this.defaultConstructorSectionPresent )
1280 {
1281 final Section defaultCtor = new Section();
1282 defaultCtor.setName( DEFAULT_CONSTRUCTOR_SECTION_NAME );
1283 defaultCtor.setStartingLine( " // SECTION-START[" + DEFAULT_CONSTRUCTOR_SECTION_NAME + "]" );
1284 defaultCtor.setEndingLine( " // SECTION-END" );
1285 defaultCtor.getHeadContent().append( " super();" ).append( this.getLineSeparator() );
1286 s.getSections().add( defaultCtor );
1287 this.defaultConstructorSectionPresent = true;
1288 }
1289 }
1290
1291 /**
1292 * Edits the default constructor section of the source code of the editor.
1293 *
1294 * @param s The section to edit.
1295 *
1296 * @throws NullPointerException if {@code s} is {@code null}.
1297 * @throws IOException if editing {@code s} fails.
1298 */
1299 public void editDefaultConstructorSection( final Section s ) throws IOException
1300 {
1301 if ( s == null )
1302 {
1303 throw new NullPointerException( "s" );
1304 }
1305
1306 if ( s.getHeadContent().toString().trim().length() == 0 )
1307 {
1308 s.getHeadContent().setLength( 0 );
1309
1310 if ( this.implementation != null )
1311 {
1312 s.getHeadContent().append( " super();" ).append( this.getLineSeparator() );
1313 }
1314 }
1315 }
1316
1317 /**
1318 * Edits the dependencies section of the source code of the editor.
1319 *
1320 * @param s The section to edit.
1321 *
1322 * @throws NullPointerException if {@code s} is {@code null}.
1323 * @throws IOException if editing {@code s} fails.
1324 */
1325 public void editDependenciesSection( final Section s ) throws IOException
1326 {
1327 if ( s == null )
1328 {
1329 throw new NullPointerException( "s" );
1330 }
1331
1332 s.getHeadContent().setLength( 0 );
1333 if ( this.implementation != null )
1334 {
1335 s.getHeadContent().append( getDependenciesSection( this.implementation ) );
1336 }
1337 }
1338
1339 /**
1340 * Edits the messages section of the source code of the editor.
1341 *
1342 * @param s The section to edit.
1343 *
1344 * @throws NullPointerException if {@code s} is {@code null}.
1345 * @throws IOException if editing {@code s} fails.
1346 */
1347 public void editMessagesSection( final Section s ) throws IOException
1348 {
1349 if ( s == null )
1350 {
1351 throw new NullPointerException( "s" );
1352 }
1353
1354 s.getHeadContent().setLength( 0 );
1355 if ( this.implementation != null )
1356 {
1357 s.getHeadContent().append( getMessagesSection( this.implementation ) );
1358 }
1359 }
1360
1361 /**
1362 * Edits the properties section of the source code of the editor.
1363 *
1364 * @param s The section to edit.
1365 *
1366 * @throws NullPointerException if {@code s} is {@code null}.
1367 * @throws IOException if editing {@code s} fails.
1368 */
1369 public void editPropertiesSection( final Section s ) throws IOException
1370 {
1371 if ( s == null )
1372 {
1373 throw new NullPointerException( "s" );
1374 }
1375
1376 s.getHeadContent().setLength( 0 );
1377 if ( this.implementation != null )
1378 {
1379 s.getHeadContent().append( getPropertiesSection( this.implementation ) );
1380 }
1381 }
1382
1383 /**
1384 * Gets a flag indicating that the source code of the editor contains a constructors section.
1385 *
1386 * @return {@code true} if the source code of the editor contains a constructors section; {@code false} if the
1387 * source code of the editor does not contain a constructors section.
1388 */
1389 public boolean isConstructorsSectionPresent()
1390 {
1391 return this.constructorsSectionPresent;
1392 }
1393
1394 /**
1395 * Gets a flag indicating that the source code of the editor contains a default constructor section.
1396 *
1397 * @return {@code true} if the source code of the editor contains a default constructor section; {@code false}
1398 * if the source code of the editor does not contain a default constructor section.
1399 */
1400 public boolean isDefaultConstructorSectionPresent()
1401 {
1402 return this.defaultConstructorSectionPresent;
1403 }
1404
1405 /**
1406 * Gets a flag indicating that the source code of the editor contains a messages section.
1407 *
1408 * @return {@code true} if the source code of the editor contains a messages section; {@code false}
1409 * if the source code of the editor does not contain a messages section.
1410 */
1411 public boolean isMessagesSectionPresent()
1412 {
1413 return this.messagesSectionPresent;
1414 }
1415
1416 /**
1417 * Gets a flag indicating that the source code of the editor contains a dependencies section.
1418 *
1419 * @return {@code true} if the source code of the editor contains a dependencies section; {@code false}
1420 * if the source code of the editor does not contain a dependencies section.
1421 */
1422 public boolean isDependenciesSectionPresent()
1423 {
1424 return this.dependenciesSectionPresent;
1425 }
1426
1427 /**
1428 * Gets a flag indicating that the source code of the editor contains a properties section.
1429 *
1430 * @return {@code true} if the source code of the editor contains a properties section; {@code false}
1431 * if the source code of the editor does not contain a properties section.
1432 */
1433 public boolean isPropertiesSectionPresent()
1434 {
1435 return this.propertiesSectionPresent;
1436 }
1437
1438 }
1439
1440 }