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 4760 2013-04-08 17:56:26Z schulte $
29   *
30   */
31  package org.jomc.tools.modlet;
32  
33  import java.lang.reflect.Field;
34  import java.text.MessageFormat;
35  import java.util.Locale;
36  import java.util.ResourceBundle;
37  import java.util.logging.Level;
38  import org.jomc.model.Dependencies;
39  import org.jomc.model.Implementation;
40  import org.jomc.model.JavaTypeName;
41  import org.jomc.model.Messages;
42  import org.jomc.model.ModelObjectException;
43  import org.jomc.model.Module;
44  import org.jomc.model.Modules;
45  import org.jomc.model.Properties;
46  import org.jomc.model.Specification;
47  import org.jomc.model.Specifications;
48  import org.jomc.model.modlet.ModelHelper;
49  import org.jomc.modlet.Model;
50  import org.jomc.modlet.ModelContext;
51  import org.jomc.modlet.ModelException;
52  import org.jomc.modlet.ModelProcessor;
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:cs@schulte.it">Christian Schulte</a>
63   * @version $JOMC: ToolsModelProcessor.java 4760 2013-04-08 17:56:26Z schulte $
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                 if ( modules.getSpecifications() != null )
327                 {
328                     for ( int i = 0, s0 = modules.getSpecifications().getSpecification().size(); i < s0; i++ )
329                     {
330                         final Specification specification = modules.getSpecifications().getSpecification().get( i );
331                         final SourceFileType sourceFileType = specification.getAnyObject( SourceFileType.class );
332                         final SourceFilesType sourceFilesType = specification.getAnyObject( SourceFilesType.class );
333 
334                         if ( sourceFileType != null )
335                         {
336                             if ( sourceFileType.getLocation() == null && specification.getClazz() != null )
337                             {
338                                 // As of 1.2, the 'location' attribute got updated from 'required' to 'optional'.
339                                 sourceFileType.setLocation( new StringBuilder( specification.getClazz().length() + 5 ).
340                                     append( specification.getClazz().replace( '.', '/' ) ).append( ".java" ).
341                                     toString() );
342 
343                             }
344 
345                             if ( sourceFileType.getHeadComment() == null )
346                             {
347                                 // As of 1.2, the 'head-comment' and 'tail-comment' attributes got introduced.
348                                 sourceFileType.setHeadComment( "//" );
349                             }
350                         }
351 
352                         if ( sourceFilesType != null )
353                         {
354                             this.applyDefaults( context, modules, specification, sourceFilesType );
355                         }
356                     }
357                 }
358 
359                 if ( modules.getImplementations() != null )
360                 {
361                     for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ )
362                     {
363                         final Implementation implementation = modules.getImplementations().getImplementation().get( i );
364                         final SourceFileType sourceFileType = implementation.getAnyObject( SourceFileType.class );
365                         final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class );
366 
367                         if ( sourceFileType != null )
368                         {
369                             if ( sourceFileType.getLocation() == null && implementation.getClazz() != null )
370                             {
371                                 // As of 1.2, the 'location' attribute got updated from 'required' to 'optional'.
372                                 sourceFileType.setLocation( new StringBuilder( implementation.getClazz().length() + 5 ).
373                                     append( implementation.getClazz().replace( '.', '/' ) ).append( ".java" ).
374                                     toString() );
375 
376                             }
377 
378                             if ( sourceFileType.getHeadComment() == null )
379                             {
380                                 // As of 1.2, the 'head-comment' and 'tail-comment' attributes got introduced.
381                                 sourceFileType.setHeadComment( "//" );
382                             }
383                         }
384 
385                         if ( sourceFilesType != null )
386                         {
387                             this.applyDefaults( context, modules, implementation, sourceFilesType );
388                         }
389                     }
390                 }
391 
392                 if ( classpathModule != null )
393                 {
394                     modules.getModule().remove( classpathModule );
395                 }
396             }
397         }
398         else if ( context.isLoggable( Level.FINER ) )
399         {
400             context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName(),
401                                                   model.getIdentifier() ), null );
402 
403         }
404 
405         return processed;
406     }
407 
408     /**
409      * Updates any optional attributes to default values.
410      *
411      * @param context The context to apply defaults with.
412      * @param modules The model to to apply defaults with.
413      * @param specification The specification corresponding to {@code sourceFilesType}.
414      * @param sourceFilesType The model to update.
415      *
416      * @throws NullPointerException if {@code context}, {@code modules}, {@code specification} or
417      * {@code sourceFilesType} is {@code null}.
418      */
419     private void applyDefaults( final ModelContext context, final Modules modules, final Specification specification,
420                                 final SourceFilesType sourceFilesType )
421     {
422         if ( context == null )
423         {
424             throw new NullPointerException( "context" );
425         }
426         if ( modules == null )
427         {
428             throw new NullPointerException( "modules" );
429         }
430         if ( specification == null )
431         {
432             throw new NullPointerException( "specification" );
433         }
434         if ( sourceFilesType == null )
435         {
436             throw new NullPointerException( "sourceFilesType" );
437         }
438 
439         for ( int i = 0, s0 = sourceFilesType.getSourceFile().size(); i < s0; i++ )
440         {
441             final SourceFileType s = sourceFilesType.getSourceFile().get( i );
442 
443             if ( s.getTemplate() == null )
444             {
445                 s.setTemplate( SPECIFICATION_TEMPLATE );
446             }
447             if ( s.getLocation() == null )
448             {
449                 try
450                 {
451                     final JavaTypeName javaTypeName = specification.getJavaTypeName();
452 
453                     if ( javaTypeName != null )
454                     {
455                         s.setLocation( javaTypeName.getQualifiedName().replace( '.', '/' ) + ".java" );
456                     }
457                 }
458                 catch ( final ModelObjectException e )
459                 {
460                     context.log( Level.WARNING, getMessage( e ), null );
461                 }
462             }
463             if ( s.getHeadComment() == null )
464             {
465                 s.setHeadComment( "//" );
466             }
467 
468             this.applyDefaults( context, modules, specification, s.getSourceSections() );
469         }
470     }
471 
472     /**
473      * Updates any optional attributes to default values.
474      *
475      * @param context The context to apply defaults with.
476      * @param modules The model to to apply defaults with.
477      * @param specification The specification corresponding to {@code sourceSectionsType}.
478      * @param sourceSectionsType The model to update or {@code null}.
479      *
480      * @throws NullPointerException if {@code context}, {@code modules} or {@code specification} is {@code null}.
481      */
482     private void applyDefaults( final ModelContext context, final Modules modules, final Specification specification,
483                                 final SourceSectionsType sourceSectionsType )
484     {
485         if ( context == null )
486         {
487             throw new NullPointerException( "context" );
488         }
489         if ( modules == null )
490         {
491             throw new NullPointerException( "modules" );
492         }
493         if ( specification == null )
494         {
495             throw new NullPointerException( "specification" );
496         }
497 
498         try
499         {
500             if ( sourceSectionsType != null )
501             {
502                 for ( int i = 0, s0 = sourceSectionsType.getSourceSection().size(); i < s0; i++ )
503                 {
504                     final SourceSectionType s = sourceSectionsType.getSourceSection().get( i );
505 
506                     if ( LICENSE_SECTION_NAME.equals( s.getName() ) )
507                     {
508                         if ( !isFieldSet( s, "optional" ) )
509                         {
510                             s.setOptional( true );
511                         }
512                         if ( s.getHeadTemplate() == null )
513                         {
514                             s.setHeadTemplate( SPECIFICATION_LICENSE_TEMPLATE );
515                         }
516                     }
517 
518                     if ( ANNOTATIONS_SECTION_NAME.equals( s.getName() ) )
519                     {
520                         if ( s.getHeadTemplate() == null )
521                         {
522                             s.setHeadTemplate( SPECIFICATION_ANNOTATIONS_TEMPLATE );
523                         }
524                     }
525 
526                     if ( DOCUMENTATION_SECTION_NAME.equals( s.getName() ) )
527                     {
528                         if ( !isFieldSet( s, "optional" ) )
529                         {
530                             s.setOptional( true );
531                         }
532                         if ( s.getHeadTemplate() == null )
533                         {
534                             s.setHeadTemplate( SPECIFICATION_DOCUMENTATION_TEMPLATE );
535                         }
536                     }
537 
538                     try
539                     {
540                         final JavaTypeName javaTypeName = specification.getJavaTypeName();
541 
542                         if ( javaTypeName != null )
543                         {
544                             if ( javaTypeName.getName( false ).equals( s.getName() ) )
545                             {
546                                 if ( !isFieldSet( s, "editable" ) )
547                                 {
548                                     s.setEditable( true );
549                                 }
550                                 if ( !isFieldSet( s, "indentationLevel" ) )
551                                 {
552                                     s.setIndentationLevel( 1 );
553                                 }
554                             }
555                         }
556                     }
557                     catch ( final ModelObjectException e )
558                     {
559                         context.log( Level.WARNING, getMessage( e ), null );
560                     }
561 
562                     this.applyDefaults( context, modules, specification, s.getSourceSections() );
563                 }
564             }
565         }
566         catch ( final NoSuchFieldException e )
567         {
568             throw new AssertionError( e );
569         }
570     }
571 
572     /**
573      * Updates any optional attributes to default values.
574      *
575      * @param context The context to apply defaults with.
576      * @param modules The model to to apply defaults with.
577      * @param implementation The implementation corresponding to {@code sourceFilesType}.
578      * @param sourceFilesType The model to update.
579      *
580      * @throws NullPointerException if {@code context}, {@code modules}, {@code implementation} or
581      * {@code sourceFilesType} is {@code null}.
582      */
583     private void applyDefaults( final ModelContext context, final Modules modules, final Implementation implementation,
584                                 final SourceFilesType sourceFilesType )
585     {
586         if ( context == null )
587         {
588             throw new NullPointerException( "context" );
589         }
590         if ( modules == null )
591         {
592             throw new NullPointerException( "modules" );
593         }
594         if ( implementation == null )
595         {
596             throw new NullPointerException( "implementation" );
597         }
598         if ( sourceFilesType == null )
599         {
600             throw new NullPointerException( "sourceFilesType" );
601         }
602 
603         for ( int i = 0, s0 = sourceFilesType.getSourceFile().size(); i < s0; i++ )
604         {
605             final SourceFileType s = sourceFilesType.getSourceFile().get( i );
606 
607             if ( s.getTemplate() == null )
608             {
609                 s.setTemplate( IMPLEMENTATION_TEMPLATE );
610             }
611             if ( s.getLocation() == null )
612             {
613                 try
614                 {
615                     final JavaTypeName javaTypeName = implementation.getJavaTypeName();
616 
617                     if ( javaTypeName != null )
618                     {
619                         s.setLocation( javaTypeName.getQualifiedName().replace( '.', '/' ) + ".java" );
620                     }
621                 }
622                 catch ( final ModelObjectException e )
623                 {
624                     context.log( Level.WARNING, getMessage( e ), null );
625                 }
626             }
627             if ( s.getHeadComment() == null )
628             {
629                 s.setHeadComment( "//" );
630             }
631 
632             this.applyDefaults( context, modules, implementation, s.getSourceSections() );
633         }
634     }
635 
636     /**
637      * Updates any optional attributes to default values.
638      *
639      * @param context The context to apply defaults with.
640      * @param modules The model to to apply defaults with.
641      * @param implementation The implementation corresponding to {@code sourceSectionsType}.
642      * @param sourceSectionsType The model to update or {@code null}.
643      *
644      * @throws NullPointerException if {@code context}, {@code modules} or {@code implementation} is {@code null}.
645      */
646     private void applyDefaults( final ModelContext context, final Modules modules, final Implementation implementation,
647                                 final SourceSectionsType sourceSectionsType )
648     {
649         if ( context == null )
650         {
651             throw new NullPointerException( "context" );
652         }
653         if ( modules == null )
654         {
655             throw new NullPointerException( "modules" );
656         }
657         if ( implementation == null )
658         {
659             throw new NullPointerException( "implementation" );
660         }
661 
662         final Specifications specifications = modules.getSpecifications( implementation.getIdentifier() );
663         final Dependencies dependencies = modules.getDependencies( implementation.getIdentifier() );
664         final Messages messages = modules.getMessages( implementation.getIdentifier() );
665         final Properties properties = modules.getProperties( implementation.getIdentifier() );
666 
667         try
668         {
669             if ( sourceSectionsType != null )
670             {
671                 for ( int i = 0, s0 = sourceSectionsType.getSourceSection().size(); i < s0; i++ )
672                 {
673                     final SourceSectionType s = sourceSectionsType.getSourceSection().get( i );
674 
675                     if ( LICENSE_SECTION_NAME.equals( s.getName() ) )
676                     {
677                         if ( !isFieldSet( s, "optional" ) )
678                         {
679                             s.setOptional( true );
680                         }
681                         if ( s.getHeadTemplate() == null )
682                         {
683                             s.setHeadTemplate( IMPLEMENTATION_LICENSE_TEMPLATE );
684                         }
685                     }
686 
687                     if ( ANNOTATIONS_SECTION_NAME.equals( s.getName() ) )
688                     {
689                         if ( s.getHeadTemplate() == null )
690                         {
691                             s.setHeadTemplate( IMPLEMENTATION_ANNOTATIONS_TEMPLATE );
692                         }
693                     }
694 
695                     if ( DOCUMENTATION_SECTION_NAME.equals( s.getName() ) )
696                     {
697                         if ( !isFieldSet( s, "optional" ) )
698                         {
699                             s.setOptional( true );
700                         }
701                         if ( s.getHeadTemplate() == null )
702                         {
703                             s.setHeadTemplate( IMPLEMENTATION_DOCUMENTATION_TEMPLATE );
704                         }
705                     }
706 
707                     if ( CONSTRUCTORS_SECTION_NAME.equals( s.getName() ) )
708                     {
709                         if ( !isFieldSet( s, "indentationLevel" ) )
710                         {
711                             s.setIndentationLevel( 1 );
712                         }
713                         if ( s.getHeadTemplate() == null )
714                         {
715                             s.setHeadTemplate( CONSTRUCTORS_HEAD_TEMPLATE );
716                         }
717                         if ( s.getTailTemplate() == null )
718                         {
719                             s.setTailTemplate( CONSTRUCTORS_TAIL_TEMPLATE );
720                         }
721                         if ( !isFieldSet( s, "optional" ) )
722                         {
723                             s.setOptional( specifications == null || ( specifications.getSpecification().isEmpty()
724                                                                        && specifications.getReference().isEmpty() ) );
725 
726                         }
727                     }
728 
729                     if ( DEFAULT_CONSTRUCTOR_SECTION_NAME.equals( s.getName() ) )
730                     {
731                         if ( !isFieldSet( s, "editable" ) )
732                         {
733                             s.setEditable( true );
734                         }
735                         if ( !isFieldSet( s, "indentationLevel" ) )
736                         {
737                             s.setIndentationLevel( 2 );
738                         }
739                         if ( s.getHeadTemplate() == null )
740                         {
741                             s.setHeadTemplate( DEFAULT_CONSTRUCTOR_TEMPLATE );
742                         }
743                     }
744 
745                     if ( DEPENDENCIES_SECTION_NAME.equals( s.getName() ) )
746                     {
747                         if ( !isFieldSet( s, "optional" ) )
748                         {
749                             s.setOptional( dependencies == null || dependencies.getDependency().isEmpty() );
750                         }
751                         if ( !isFieldSet( s, "indentationLevel" ) )
752                         {
753                             s.setIndentationLevel( 1 );
754                         }
755                         if ( s.getHeadTemplate() == null )
756                         {
757                             s.setHeadTemplate( DEPENDENCIES_TEMPLATE );
758                         }
759                     }
760 
761                     if ( PROPERTIES_SECTION_NAME.equals( s.getName() ) )
762                     {
763                         if ( !isFieldSet( s, "optional" ) )
764                         {
765                             s.setOptional( properties == null || properties.getProperty().isEmpty() );
766                         }
767                         if ( !isFieldSet( s, "indentationLevel" ) )
768                         {
769                             s.setIndentationLevel( 1 );
770                         }
771                         if ( s.getHeadTemplate() == null )
772                         {
773                             s.setHeadTemplate( PROPERTIES_TEMPLATE );
774                         }
775                     }
776 
777                     if ( MESSAGES_SECTION_NAME.equals( s.getName() ) )
778                     {
779                         if ( !isFieldSet( s, "optional" ) )
780                         {
781                             s.setOptional( messages == null || messages.getMessage().isEmpty() );
782                         }
783                         if ( !isFieldSet( s, "indentationLevel" ) )
784                         {
785                             s.setIndentationLevel( 1 );
786                         }
787                         if ( s.getHeadTemplate() == null )
788                         {
789                             s.setHeadTemplate( MESSAGES_TEMPLATE );
790                         }
791                     }
792 
793                     if ( specifications != null )
794                     {
795                         for ( final Specification specification : specifications.getSpecification() )
796                         {
797                             try
798                             {
799                                 final JavaTypeName javaTypeName = specification.getJavaTypeName();
800 
801                                 if ( javaTypeName != null )
802                                 {
803                                     if ( javaTypeName.getName( false ).equals( s.getName() ) )
804                                     {
805                                         if ( !isFieldSet( s, "editable" ) )
806                                         {
807                                             s.setEditable( true );
808                                         }
809                                         if ( !isFieldSet( s, "indentationLevel" ) )
810                                         {
811                                             s.setIndentationLevel( 1 );
812                                         }
813                                     }
814                                 }
815                             }
816                             catch ( final ModelObjectException e )
817                             {
818                                 context.log( Level.WARNING, getMessage( e ), null );
819                             }
820                         }
821                     }
822 
823                     try
824                     {
825                         final JavaTypeName javaTypeName = implementation.getJavaTypeName();
826 
827                         if ( javaTypeName != null )
828                         {
829                             if ( javaTypeName.getName( false ).equals( s.getName() ) )
830                             {
831                                 if ( !isFieldSet( s, "editable" ) )
832                                 {
833                                     s.setEditable( true );
834                                 }
835                                 if ( !isFieldSet( s, "indentationLevel" ) )
836                                 {
837                                     s.setIndentationLevel( 1 );
838                                 }
839                             }
840                         }
841                     }
842                     catch ( final ModelObjectException e )
843                     {
844                         context.log( Level.WARNING, getMessage( e ), null );
845                     }
846 
847                     this.applyDefaults( context, modules, implementation, s.getSourceSections() );
848                 }
849             }
850         }
851         catch ( final NoSuchFieldException e )
852         {
853             throw new AssertionError( e );
854         }
855     }
856 
857     private static boolean isFieldSet( final Object object, final String fieldName ) throws NoSuchFieldException
858     {
859         final Field field = object.getClass().getDeclaredField( fieldName );
860         final boolean accessible = field.isAccessible();
861 
862         try
863         {
864             field.setAccessible( true );
865             return field.get( object ) != null;
866         }
867         catch ( final IllegalAccessException e )
868         {
869             throw new AssertionError( e );
870         }
871         finally
872         {
873             field.setAccessible( accessible );
874         }
875     }
876 
877     private static String getMessage( final Throwable t )
878     {
879         return t != null
880                ? t.getMessage() != null && t.getMessage().trim().length() > 0
881                  ? t.getMessage()
882                  : getMessage( t.getCause() )
883                : null;
884 
885     }
886 
887     private static String getMessage( final String key, final Object... args )
888     {
889         return MessageFormat.format( ResourceBundle.getBundle(
890             ToolsModelProcessor.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args );
891 
892     }
893 
894 }