001    /*
002     *   Copyright (C) Christian Schulte, 2005-206
003     *   All rights reserved.
004     *
005     *   Redistribution and use in source and binary forms, with or without
006     *   modification, are permitted provided that the following conditions
007     *   are met:
008     *
009     *     o Redistributions of source code must retain the above copyright
010     *       notice, this list of conditions and the following disclaimer.
011     *
012     *     o Redistributions in binary form must reproduce the above copyright
013     *       notice, this list of conditions and the following disclaimer in
014     *       the documentation and/or other materials provided with the
015     *       distribution.
016     *
017     *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018     *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019     *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020     *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021     *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022     *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023     *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024     *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025     *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026     *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027     *
028     *   $JOMC: ToolsModelProcessor.java 4201 2012-01-25 09:47:12Z schulte2005 $
029     *
030     */
031    package org.jomc.tools.modlet;
032    
033    import java.lang.reflect.Field;
034    import java.text.MessageFormat;
035    import java.util.List;
036    import java.util.Locale;
037    import java.util.ResourceBundle;
038    import java.util.logging.Level;
039    import org.jomc.model.Dependencies;
040    import org.jomc.model.Implementation;
041    import org.jomc.model.Messages;
042    import org.jomc.model.Module;
043    import org.jomc.model.Modules;
044    import org.jomc.model.Properties;
045    import org.jomc.model.Specification;
046    import org.jomc.model.Specifications;
047    import org.jomc.model.modlet.ModelHelper;
048    import org.jomc.modlet.Model;
049    import org.jomc.modlet.ModelContext;
050    import org.jomc.modlet.ModelException;
051    import org.jomc.modlet.ModelProcessor;
052    import org.jomc.tools.JomcTool;
053    import org.jomc.tools.model.SourceFileType;
054    import org.jomc.tools.model.SourceFilesType;
055    import org.jomc.tools.model.SourceSectionType;
056    import org.jomc.tools.model.SourceSectionsType;
057    import static org.jomc.tools.modlet.ToolsModletConstants.*;
058    
059    /**
060     * Object management and configuration tools {@code ModelProcessor} implementation.
061     *
062     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
063     * @version $JOMC: ToolsModelProcessor.java 4201 2012-01-25 09:47:12Z schulte2005 $
064     * @see ModelContext#processModel(org.jomc.modlet.Model)
065     * @since 1.2
066     */
067    public class ToolsModelProcessor implements ModelProcessor
068    {
069    
070        /**
071         * Constant for the name of the model context attribute backing property {@code enabled}.
072         * @see #processModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
073         * @see ModelContext#getAttribute(java.lang.String)
074         */
075        public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.tools.modlet.ToolsModelProcessor.enabledAttribute";
076    
077        /**
078         * Constant for the name of the system property controlling property {@code defaultEnabled}.
079         * @see #isDefaultEnabled()
080         */
081        private static final String DEFAULT_ENABLED_PROPERTY_NAME =
082            "org.jomc.tools.modlet.ToolsModelProcessor.defaultEnabled";
083    
084        /**
085         * Default value of the flag indicating the processor is enabled by default.
086         * @see #isDefaultEnabled()
087         */
088        private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;
089    
090        /** Flag indicating the processor is enabled by default. */
091        private static volatile Boolean defaultEnabled;
092    
093        /** Flag indicating the processor is enabled. */
094        private Boolean enabled;
095    
096        /**
097         * Constant for the name of the model context attribute backing property
098         * {@code modelObjectClasspathResolutionEnabled}.
099         *
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    }