View Javadoc

1   /*
2    *   Copyright (C) Christian Schulte, 2005-206
3    *   All rights reserved.
4    *
5    *   Redistribution and use in source and binary forms, with or without
6    *   modification, are permitted provided that the following conditions
7    *   are met:
8    *
9    *     o Redistributions of source code must retain the above copyright
10   *       notice, this list of conditions and the following disclaimer.
11   *
12   *     o Redistributions in binary form must reproduce the above copyright
13   *       notice, this list of conditions and the following disclaimer in
14   *       the documentation and/or other materials provided with the
15   *       distribution.
16   *
17   *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18   *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20   *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21   *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27   *
28   *   $JOMC: ToolsModelProcessor.java 4201 2012-01-25 09:47:12Z schulte2005 $
29   *
30   */
31  package org.jomc.tools.modlet;
32  
33  import java.lang.reflect.Field;
34  import java.text.MessageFormat;
35  import java.util.List;
36  import java.util.Locale;
37  import java.util.ResourceBundle;
38  import java.util.logging.Level;
39  import org.jomc.model.Dependencies;
40  import org.jomc.model.Implementation;
41  import org.jomc.model.Messages;
42  import org.jomc.model.Module;
43  import org.jomc.model.Modules;
44  import org.jomc.model.Properties;
45  import org.jomc.model.Specification;
46  import org.jomc.model.Specifications;
47  import org.jomc.model.modlet.ModelHelper;
48  import org.jomc.modlet.Model;
49  import org.jomc.modlet.ModelContext;
50  import org.jomc.modlet.ModelException;
51  import org.jomc.modlet.ModelProcessor;
52  import org.jomc.tools.JomcTool;
53  import org.jomc.tools.model.SourceFileType;
54  import org.jomc.tools.model.SourceFilesType;
55  import org.jomc.tools.model.SourceSectionType;
56  import org.jomc.tools.model.SourceSectionsType;
57  import static org.jomc.tools.modlet.ToolsModletConstants.*;
58  
59  /**
60   * Object management and configuration tools {@code ModelProcessor} implementation.
61   *
62   * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
63   * @version $JOMC: ToolsModelProcessor.java 4201 2012-01-25 09:47:12Z schulte2005 $
64   * @see ModelContext#processModel(org.jomc.modlet.Model)
65   * @since 1.2
66   */
67  public class ToolsModelProcessor implements ModelProcessor
68  {
69  
70      /**
71       * Constant for the name of the model context attribute backing property {@code enabled}.
72       * @see #processModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
73       * @see ModelContext#getAttribute(java.lang.String)
74       */
75      public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.tools.modlet.ToolsModelProcessor.enabledAttribute";
76  
77      /**
78       * Constant for the name of the system property controlling property {@code defaultEnabled}.
79       * @see #isDefaultEnabled()
80       */
81      private static final String DEFAULT_ENABLED_PROPERTY_NAME =
82          "org.jomc.tools.modlet.ToolsModelProcessor.defaultEnabled";
83  
84      /**
85       * Default value of the flag indicating the processor is enabled by default.
86       * @see #isDefaultEnabled()
87       */
88      private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;
89  
90      /** Flag indicating the processor is enabled by default. */
91      private static volatile Boolean defaultEnabled;
92  
93      /** Flag indicating the processor is enabled. */
94      private Boolean enabled;
95  
96      /**
97       * Constant for the name of the model context attribute backing property
98       * {@code modelObjectClasspathResolutionEnabled}.
99       *
100      * @see #processModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
101      * @see ModelContext#getAttribute(java.lang.String)
102      */
103     public static final String MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME =
104         "org.jomc.tools.modlet.ToolsModelProcessor.modelObjectClasspathResolutionEnabledAttribute";
105 
106     /**
107      * Constant for the name of the system property controlling property
108      * {@code defaultModelObjectClasspathResolutionEnabled}.
109      * @see #isDefaultModelObjectClasspathResolutionEnabled()
110      */
111     private static final String DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME =
112         "org.jomc.tools.modlet.ToolsModelProcessor.defaultModelObjectClasspathResolutionEnabled";
113 
114     /**
115      * Default value of the flag indicating model object class path resolution is enabled by default.
116      * @see #isDefaultModelObjectClasspathResolutionEnabled()
117      */
118     private static final Boolean DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED = Boolean.TRUE;
119 
120     /** Flag indicating model object class path resolution is enabled by default. */
121     private static volatile Boolean defaultModelObjectClasspathResolutionEnabled;
122 
123     /** Flag indicating model object class path resolution is enabled. */
124     private Boolean modelObjectClasspathResolutionEnabled;
125 
126     /** Creates a new {@code ToolsModelProcessor} instance. */
127     public ToolsModelProcessor()
128     {
129         super();
130     }
131 
132     /**
133      * Gets a flag indicating the processor is enabled by default.
134      * <p>The default enabled flag is controlled by system property
135      * {@code org.jomc.tools.modlet.ToolsModelProcessor.defaultEnabled} holding a value indicating the processor is
136      * enabled by default. If that property is not set, the {@code true} default is returned.</p>
137      *
138      * @return {@code true}, if the processor is enabled by default; {@code false}, if the processor is disabled by
139      * default.
140      *
141      * @see #setDefaultEnabled(java.lang.Boolean)
142      */
143     public static boolean isDefaultEnabled()
144     {
145         if ( defaultEnabled == null )
146         {
147             defaultEnabled = Boolean.valueOf( System.getProperty( DEFAULT_ENABLED_PROPERTY_NAME,
148                                                                   Boolean.toString( DEFAULT_ENABLED ) ) );
149 
150         }
151 
152         return defaultEnabled;
153     }
154 
155     /**
156      * Sets the flag indicating the processor is enabled by default.
157      *
158      * @param value The new value of the flag indicating the processor is enabled by default or {@code null}.
159      *
160      * @see #isDefaultEnabled()
161      */
162     public static void setDefaultEnabled( final Boolean value )
163     {
164         defaultEnabled = value;
165     }
166 
167     /**
168      * Gets a flag indicating the processor is enabled.
169      *
170      * @return {@code true}, if the processor is enabled; {@code false}, if the processor is disabled.
171      *
172      * @see #isDefaultEnabled()
173      * @see #setEnabled(java.lang.Boolean)
174      */
175     public final boolean isEnabled()
176     {
177         if ( this.enabled == null )
178         {
179             this.enabled = isDefaultEnabled();
180         }
181 
182         return this.enabled;
183     }
184 
185     /**
186      * Sets the flag indicating the processor is enabled.
187      *
188      * @param value The new value of the flag indicating the processor is enabled or {@code null}.
189      *
190      * @see #isEnabled()
191      */
192     public final void setEnabled( final Boolean value )
193     {
194         this.enabled = value;
195     }
196 
197     /**
198      * Gets a flag indicating model object class path resolution is enabled by default.
199      * <p>The model object class path resolution default enabled flag is controlled by system property
200      * {@code org.jomc.tools.modlet.ToolsModelProcessor.defaultModelObjectClasspathResolutionEnabled} holding a value
201      * indicating model object class path resolution is enabled by default. If that property is not set, the
202      * {@code true} default is returned.</p>
203      *
204      * @return {@code true}, if model object class path resolution is enabled by default; {@code false}, if model object
205      * class path resolution is disabled by default.
206      *
207      * @see #setDefaultModelObjectClasspathResolutionEnabled(java.lang.Boolean)
208      */
209     public static boolean isDefaultModelObjectClasspathResolutionEnabled()
210     {
211         if ( defaultModelObjectClasspathResolutionEnabled == null )
212         {
213             defaultModelObjectClasspathResolutionEnabled = Boolean.valueOf( System.getProperty(
214                 DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME,
215                 Boolean.toString( DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED ) ) );
216 
217         }
218 
219         return defaultModelObjectClasspathResolutionEnabled;
220     }
221 
222     /**
223      * Sets the flag indicating model object class path resolution is enabled by default.
224      *
225      * @param value The new value of the flag indicating model object class path resolution is enabled by default or
226      * {@code null}.
227      *
228      * @see #isDefaultModelObjectClasspathResolutionEnabled()
229      */
230     public static void setDefaultModelObjectClasspathResolutionEnabled( final Boolean value )
231     {
232         defaultModelObjectClasspathResolutionEnabled = value;
233     }
234 
235     /**
236      * Gets a flag indicating model object class path resolution is enabled.
237      *
238      * @return {@code true}, if model object class path resolution is enabled; {@code false}, if model object class path
239      * resolution is disabled.
240      *
241      * @see #isDefaultModelObjectClasspathResolutionEnabled()
242      * @see #setModelObjectClasspathResolutionEnabled(java.lang.Boolean)
243      */
244     public final boolean isModelObjectClasspathResolutionEnabled()
245     {
246         if ( this.modelObjectClasspathResolutionEnabled == null )
247         {
248             this.modelObjectClasspathResolutionEnabled = isDefaultModelObjectClasspathResolutionEnabled();
249         }
250 
251         return this.modelObjectClasspathResolutionEnabled;
252     }
253 
254     /**
255      * Sets the flag indicating model object class path resolution is is enabled.
256      *
257      * @param value The new value of the flag indicating model object class path resolution is enabled or {@code null}.
258      *
259      * @see #isModelObjectClasspathResolutionEnabled()
260      */
261     public final void setModelObjectClasspathResolutionEnabled( final Boolean value )
262     {
263         this.modelObjectClasspathResolutionEnabled = value;
264     }
265 
266     /**
267      * {@inheritDoc}
268      *
269      * @see #isEnabled()
270      * @see #isModelObjectClasspathResolutionEnabled()
271      * @see #ENABLED_ATTRIBUTE_NAME
272      * @see #MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME
273      */
274     public Model processModel( final ModelContext context, final Model model ) throws ModelException
275     {
276         if ( context == null )
277         {
278             throw new NullPointerException( "context" );
279         }
280         if ( model == null )
281         {
282             throw new NullPointerException( "model" );
283         }
284 
285         Model processed = model;
286 
287         boolean contextEnabled = this.isEnabled();
288         if ( DEFAULT_ENABLED == contextEnabled && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
289         {
290             contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME );
291         }
292 
293         boolean contextModelObjectClasspathResolutionEnabled = this.isModelObjectClasspathResolutionEnabled();
294         if ( contextModelObjectClasspathResolutionEnabled == DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED
295              && context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
296         {
297             contextModelObjectClasspathResolutionEnabled =
298                 (Boolean) context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME );
299 
300         }
301 
302         if ( contextEnabled )
303         {
304             processed = model.clone();
305             final Modules modules = ModelHelper.getModules( processed );
306 
307             if ( modules != null )
308             {
309                 Module classpathModule = null;
310                 if ( contextModelObjectClasspathResolutionEnabled )
311                 {
312                     classpathModule = modules.getClasspathModule( Modules.getDefaultClasspathModuleName(),
313                                                                   context.getClassLoader() );
314 
315                     if ( classpathModule != null
316                          && modules.getModule( Modules.getDefaultClasspathModuleName() ) == null )
317                     {
318                         modules.getModule().add( classpathModule );
319                     }
320                     else
321                     {
322                         classpathModule = null;
323                     }
324                 }
325 
326                 final JomcTool tool = new JomcTool();
327                 tool.setModel( processed );
328 
329                 if ( modules.getSpecifications() != null )
330                 {
331                     for ( int i = 0, s0 = modules.getSpecifications().getSpecification().size(); i < s0; i++ )
332                     {
333                         final Specification specification = modules.getSpecifications().getSpecification().get( i );
334                         final SourceFileType sourceFileType = specification.getAnyObject( SourceFileType.class );
335                         final SourceFilesType sourceFilesType = specification.getAnyObject( SourceFilesType.class );
336 
337                         if ( sourceFileType != null )
338                         {
339                             if ( sourceFileType.getLocation() == null && specification.getClazz() != null )
340                             {
341                                 // As of 1.2, the 'location' attribute got updated from 'required' to 'optional'.
342                                 sourceFileType.setLocation( new StringBuilder( specification.getClazz().length() + 5 ).
343                                     append( specification.getClazz().replace( '.', '/' ) ).append( ".java" ).
344                                     toString() );
345 
346                             }
347 
348                             if ( sourceFileType.getHeadComment() == null )
349                             {
350                                 // As of 1.2, the 'head-comment' and 'tail-comment' attributes got introduced.
351                                 sourceFileType.setHeadComment( "//" );
352                             }
353                         }
354 
355                         if ( sourceFilesType != null )
356                         {
357                             this.applyDefaults( tool, specification, sourceFilesType );
358                         }
359                     }
360                 }
361 
362                 if ( modules.getImplementations() != null )
363                 {
364                     for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ )
365                     {
366                         final Implementation implementation = modules.getImplementations().getImplementation().get( i );
367                         final SourceFileType sourceFileType = implementation.getAnyObject( SourceFileType.class );
368                         final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class );
369 
370                         if ( sourceFileType != null )
371                         {
372                             if ( sourceFileType.getLocation() == null && implementation.getClazz() != null )
373                             {
374                                 // As of 1.2, the 'location' attribute got updated from 'required' to 'optional'.
375                                 sourceFileType.setLocation( new StringBuilder( implementation.getClazz().length() + 5 ).
376                                     append( implementation.getClazz().replace( '.', '/' ) ).append( ".java" ).
377                                     toString() );
378 
379                             }
380 
381                             if ( sourceFileType.getHeadComment() == null )
382                             {
383                                 // As of 1.2, the 'head-comment' and 'tail-comment' attributes got introduced.
384                                 sourceFileType.setHeadComment( "//" );
385                             }
386                         }
387 
388                         if ( sourceFilesType != null )
389                         {
390                             this.applyDefaults( tool, implementation, sourceFilesType );
391                         }
392                     }
393                 }
394 
395                 if ( classpathModule != null )
396                 {
397                     modules.getModule().remove( classpathModule );
398                 }
399             }
400         }
401         else if ( context.isLoggable( Level.FINER ) )
402         {
403             context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName(),
404                                                   model.getIdentifier() ), null );
405 
406         }
407 
408         return processed;
409     }
410 
411     /**
412      * Updates any optional attributes to default values.
413      *
414      * @param tool The tool to use for creating type names.
415      * @param specification The specification corresponding to {@code sourceFilesType}.
416      * @param sourceFilesType The model to update.
417      *
418      * @throws NullPointerException if {@code tool}, {@code specification} or {@code sourceFilesType} is {@code null}.
419      */
420     private void applyDefaults( final JomcTool tool, final Specification specification,
421                                 final SourceFilesType sourceFilesType )
422     {
423         if ( tool == null )
424         {
425             throw new NullPointerException( "tool" );
426         }
427         if ( specification == null )
428         {
429             throw new NullPointerException( "specification" );
430         }
431         if ( sourceFilesType == null )
432         {
433             throw new NullPointerException( "sourceFilesType" );
434         }
435 
436         for ( int i = 0, s0 = sourceFilesType.getSourceFile().size(); i < s0; i++ )
437         {
438             final SourceFileType s = sourceFilesType.getSourceFile().get( i );
439 
440             if ( s.getTemplate() == null )
441             {
442                 s.setTemplate( SPECIFICATION_TEMPLATE );
443             }
444             if ( s.getLocation() == null && specification.getClazz() != null )
445             {
446                 s.setLocation( new StringBuilder( specification.getClazz().length() + 5 ).append(
447                     specification.getClazz().replace( '.', '/' ) ).append( ".java" ).toString() );
448 
449             }
450             if ( s.getHeadComment() == null )
451             {
452                 s.setHeadComment( "//" );
453             }
454 
455             this.applyDefaults( tool, specification, s.getSourceSections() );
456         }
457     }
458 
459     /**
460      * Updates any optional attributes to default values.
461      *
462      * @param tool The tool to use for creating type names.
463      * @param specification The specification corresponding to {@code sourceSectionsType}.
464      * @param sourceSectionsType The model to update or {@code null}.
465      *
466      * @throws NullPointerException if {@code tool} or {@code specification} is {@code null}.
467      */
468     private void applyDefaults( final JomcTool tool, final Specification specification,
469                                 final SourceSectionsType sourceSectionsType )
470     {
471         if ( tool == null )
472         {
473             throw new NullPointerException( "tool" );
474         }
475         if ( specification == null )
476         {
477             throw new NullPointerException( "specification" );
478         }
479 
480         try
481         {
482             if ( sourceSectionsType != null )
483             {
484                 for ( int i = 0, s0 = sourceSectionsType.getSourceSection().size(); i < s0; i++ )
485                 {
486                     final SourceSectionType s = sourceSectionsType.getSourceSection().get( i );
487 
488                     if ( LICENSE_SECTION_NAME.equals( s.getName() ) )
489                     {
490                         if ( !isFieldSet( s, "optional" ) )
491                         {
492                             s.setOptional( true );
493                         }
494                         if ( s.getHeadTemplate() == null )
495                         {
496                             s.setHeadTemplate( SPECIFICATION_LICENSE_TEMPLATE );
497                         }
498                     }
499 
500                     if ( ANNOTATIONS_SECTION_NAME.equals( s.getName() ) )
501                     {
502                         if ( s.getHeadTemplate() == null )
503                         {
504                             s.setHeadTemplate( SPECIFICATION_ANNOTATIONS_TEMPLATE );
505                         }
506                     }
507 
508                     if ( DOCUMENTATION_SECTION_NAME.equals( s.getName() ) )
509                     {
510                         if ( !isFieldSet( s, "optional" ) )
511                         {
512                             s.setOptional( true );
513                         }
514                         if ( s.getHeadTemplate() == null )
515                         {
516                             s.setHeadTemplate( SPECIFICATION_DOCUMENTATION_TEMPLATE );
517                         }
518                     }
519 
520                     final String javaTypeName = tool.getJavaTypeName( specification, false );
521                     if ( javaTypeName != null )
522                     {
523                         if ( javaTypeName.equals( s.getName() ) )
524                         {
525                             if ( !isFieldSet( s, "editable" ) )
526                             {
527                                 s.setEditable( true );
528                             }
529                             if ( !isFieldSet( s, "indentationLevel" ) )
530                             {
531                                 s.setIndentationLevel( 1 );
532                             }
533                         }
534                     }
535 
536                     this.applyDefaults( tool, specification, s.getSourceSections() );
537                 }
538             }
539         }
540         catch ( final NoSuchFieldException e )
541         {
542             throw new AssertionError( e );
543         }
544     }
545 
546     /**
547      * Updates any optional attributes to default values.
548      *
549      * @param tool The tool to use for creating type names.
550      * @param implementation The implementation corresponding to {@code sourceFilesType}.
551      * @param sourceFilesType The model to update.
552      *
553      * @throws NullPointerException if {@code tool}, {@code implementation} or {@code sourceFilesType} is {@code null}.
554      */
555     private void applyDefaults( final JomcTool tool, final Implementation implementation,
556                                 final SourceFilesType sourceFilesType )
557     {
558         if ( tool == null )
559         {
560             throw new NullPointerException( "tool" );
561         }
562         if ( implementation == null )
563         {
564             throw new NullPointerException( "implementation" );
565         }
566         if ( sourceFilesType == null )
567         {
568             throw new NullPointerException( "sourceFilesType" );
569         }
570 
571         for ( int i = 0, s0 = sourceFilesType.getSourceFile().size(); i < s0; i++ )
572         {
573             final SourceFileType s = sourceFilesType.getSourceFile().get( i );
574 
575             if ( s.getTemplate() == null )
576             {
577                 s.setTemplate( IMPLEMENTATION_TEMPLATE );
578             }
579             if ( s.getLocation() == null && implementation.getClazz() != null )
580             {
581                 s.setLocation( new StringBuilder( implementation.getClazz().length() + 5 ).append(
582                     implementation.getClazz().replace( '.', '/' ) ).append( ".java" ).toString() );
583 
584             }
585             if ( s.getHeadComment() == null )
586             {
587                 s.setHeadComment( "//" );
588             }
589 
590             this.applyDefaults( tool, implementation, s.getSourceSections() );
591         }
592     }
593 
594     /**
595      * Updates any optional attributes to default values.
596      *
597      * @param tool The tool to use for creating type names.
598      * @param implementation The implementation corresponding to {@code sourceSectionsType}.
599      * @param sourceSectionsType The model to update or {@code null}.
600      *
601      * @throws NullPointerException if {@code tool} or {@code implementation} is {@code null}.
602      */
603     private void applyDefaults( final JomcTool tool, final Implementation implementation,
604                                 final SourceSectionsType sourceSectionsType )
605     {
606         if ( tool == null )
607         {
608             throw new NullPointerException( "tool" );
609         }
610         if ( implementation == null )
611         {
612             throw new NullPointerException( "implementation" );
613         }
614 
615         try
616         {
617             if ( sourceSectionsType != null )
618             {
619                 final Modules modules = ModelHelper.getModules( tool.getModel() );
620 
621                 for ( int i = 0, s0 = sourceSectionsType.getSourceSection().size(); i < s0; i++ )
622                 {
623                     final SourceSectionType s = sourceSectionsType.getSourceSection().get( i );
624 
625                     if ( LICENSE_SECTION_NAME.equals( s.getName() ) )
626                     {
627                         if ( !isFieldSet( s, "optional" ) )
628                         {
629                             s.setOptional( true );
630                         }
631                         if ( s.getHeadTemplate() == null )
632                         {
633                             s.setHeadTemplate( IMPLEMENTATION_LICENSE_TEMPLATE );
634                         }
635                     }
636 
637                     if ( ANNOTATIONS_SECTION_NAME.equals( s.getName() ) )
638                     {
639                         if ( s.getHeadTemplate() == null )
640                         {
641                             s.setHeadTemplate( IMPLEMENTATION_ANNOTATIONS_TEMPLATE );
642                         }
643                     }
644 
645                     if ( DOCUMENTATION_SECTION_NAME.equals( s.getName() ) )
646                     {
647                         if ( !isFieldSet( s, "optional" ) )
648                         {
649                             s.setOptional( true );
650                         }
651                         if ( s.getHeadTemplate() == null )
652                         {
653                             s.setHeadTemplate( IMPLEMENTATION_DOCUMENTATION_TEMPLATE );
654                         }
655                     }
656 
657                     if ( CONSTRUCTORS_SECTION_NAME.equals( s.getName() ) )
658                     {
659                         if ( !isFieldSet( s, "indentationLevel" ) )
660                         {
661                             s.setIndentationLevel( 1 );
662                         }
663                         if ( s.getHeadTemplate() == null )
664                         {
665                             s.setHeadTemplate( CONSTRUCTORS_HEAD_TEMPLATE );
666                         }
667                         if ( s.getTailTemplate() == null )
668                         {
669                             s.setTailTemplate( CONSTRUCTORS_TAIL_TEMPLATE );
670                         }
671                         if ( !isFieldSet( s, "optional" ) )
672                         {
673                             final Specifications specifications =
674                                 modules != null ? modules.getSpecifications( implementation.getIdentifier() ) : null;
675 
676                             s.setOptional( specifications == null || ( specifications.getSpecification().isEmpty()
677                                                                        && specifications.getReference().isEmpty() ) );
678 
679                         }
680                     }
681 
682                     if ( DEFAULT_CONSTRUCTOR_SECTION_NAME.equals( s.getName() ) )
683                     {
684                         if ( !isFieldSet( s, "editable" ) )
685                         {
686                             s.setEditable( true );
687                         }
688                         if ( !isFieldSet( s, "indentationLevel" ) )
689                         {
690                             s.setIndentationLevel( 2 );
691                         }
692                         if ( s.getHeadTemplate() == null )
693                         {
694                             s.setHeadTemplate( DEFAULT_CONSTRUCTOR_TEMPLATE );
695                         }
696                     }
697 
698                     if ( DEPENDENCIES_SECTION_NAME.equals( s.getName() ) )
699                     {
700                         if ( !isFieldSet( s, "optional" ) )
701                         {
702                             final Dependencies dependencies =
703                                 modules != null ? modules.getDependencies( implementation.getIdentifier() ) : null;
704 
705                             s.setOptional( dependencies == null || dependencies.getDependency().isEmpty() );
706                         }
707                         if ( !isFieldSet( s, "indentationLevel" ) )
708                         {
709                             s.setIndentationLevel( 1 );
710                         }
711                         if ( s.getHeadTemplate() == null )
712                         {
713                             s.setHeadTemplate( DEPENDENCIES_TEMPLATE );
714                         }
715                     }
716 
717                     if ( PROPERTIES_SECTION_NAME.equals( s.getName() ) )
718                     {
719                         if ( !isFieldSet( s, "optional" ) )
720                         {
721                             final Properties properties =
722                                 modules != null ? modules.getProperties( implementation.getIdentifier() ) : null;
723 
724                             s.setOptional( properties == null || properties.getProperty().isEmpty() );
725                         }
726                         if ( !isFieldSet( s, "indentationLevel" ) )
727                         {
728                             s.setIndentationLevel( 1 );
729                         }
730                         if ( s.getHeadTemplate() == null )
731                         {
732                             s.setHeadTemplate( PROPERTIES_TEMPLATE );
733                         }
734                     }
735 
736                     if ( MESSAGES_SECTION_NAME.equals( s.getName() ) )
737                     {
738                         if ( !isFieldSet( s, "optional" ) )
739                         {
740                             final Messages messages =
741                                 modules != null ? modules.getMessages( implementation.getIdentifier() ) : null;
742 
743                             s.setOptional( messages == null || messages.getMessage().isEmpty() );
744                         }
745                         if ( !isFieldSet( s, "indentationLevel" ) )
746                         {
747                             s.setIndentationLevel( 1 );
748                         }
749                         if ( s.getHeadTemplate() == null )
750                         {
751                             s.setHeadTemplate( MESSAGES_TEMPLATE );
752                         }
753                     }
754 
755                     final List<String> implementedJavaTypeNames =
756                         tool.getImplementedJavaTypeNames( implementation, false );
757 
758                     for ( int j = 0, s1 = implementedJavaTypeNames.size(); j < s1; j++ )
759                     {
760                         final String interfaceName = implementedJavaTypeNames.get( j );
761 
762                         if ( interfaceName.equals( s.getName() ) )
763                         {
764                             if ( !isFieldSet( s, "editable" ) )
765                             {
766                                 s.setEditable( true );
767                             }
768                             if ( !isFieldSet( s, "indentationLevel" ) )
769                             {
770                                 s.setIndentationLevel( 1 );
771                             }
772                         }
773                     }
774 
775                     final String javaTypeName = tool.getJavaTypeName( implementation, false );
776                     if ( javaTypeName != null )
777                     {
778                         if ( javaTypeName.equals( s.getName() ) )
779                         {
780                             if ( !isFieldSet( s, "editable" ) )
781                             {
782                                 s.setEditable( true );
783                             }
784                             if ( !isFieldSet( s, "indentationLevel" ) )
785                             {
786                                 s.setIndentationLevel( 1 );
787                             }
788                         }
789                     }
790 
791                     this.applyDefaults( tool, implementation, s.getSourceSections() );
792                 }
793             }
794         }
795         catch ( final NoSuchFieldException e )
796         {
797             throw new AssertionError( e );
798         }
799     }
800 
801     private static boolean isFieldSet( final Object object, final String fieldName ) throws NoSuchFieldException
802     {
803         final Field field = object.getClass().getDeclaredField( fieldName );
804         final boolean accessible = field.isAccessible();
805 
806         try
807         {
808             field.setAccessible( true );
809             return field.get( object ) != null;
810         }
811         catch ( final IllegalAccessException e )
812         {
813             throw new AssertionError( e );
814         }
815         finally
816         {
817             field.setAccessible( accessible );
818         }
819     }
820 
821     private static String getMessage( final String key, final Object... args )
822     {
823         return MessageFormat.format( ResourceBundle.getBundle(
824             ToolsModelProcessor.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args );
825 
826     }
827 
828 }