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 }