001/*
002 *   Copyright (C) Christian Schulte <cs@schulte.it>, 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: DefaultModelValidator.java 5374 2016-09-05 12:24:12Z schulte $
029 *
030 */
031package org.jomc.model.modlet;
032
033import java.lang.reflect.UndeclaredThrowableException;
034import java.text.MessageFormat;
035import java.util.Collection;
036import java.util.Collections;
037import java.util.HashMap;
038import java.util.HashSet;
039import java.util.Iterator;
040import java.util.LinkedList;
041import java.util.List;
042import java.util.Locale;
043import java.util.Map;
044import java.util.ResourceBundle;
045import java.util.Set;
046import java.util.concurrent.Callable;
047import java.util.concurrent.CancellationException;
048import java.util.concurrent.ExecutionException;
049import java.util.concurrent.Future;
050import java.util.logging.Level;
051import javax.xml.bind.JAXBElement;
052import javax.xml.bind.JAXBException;
053import javax.xml.bind.util.JAXBSource;
054import javax.xml.namespace.QName;
055import javax.xml.transform.Source;
056import org.jomc.model.Argument;
057import org.jomc.model.Dependency;
058import org.jomc.model.Implementation;
059import org.jomc.model.ImplementationReference;
060import org.jomc.model.Implementations;
061import org.jomc.model.Inheritable;
062import org.jomc.model.InheritanceModel;
063import org.jomc.model.JavaIdentifier;
064import org.jomc.model.Message;
065import org.jomc.model.MessageReference;
066import org.jomc.model.ModelObject;
067import org.jomc.model.ModelObjectException;
068import org.jomc.model.Module;
069import org.jomc.model.Modules;
070import org.jomc.model.Multiplicity;
071import org.jomc.model.ObjectFactory;
072import org.jomc.model.Property;
073import org.jomc.model.PropertyReference;
074import org.jomc.model.Specification;
075import org.jomc.model.SpecificationReference;
076import org.jomc.model.Specifications;
077import org.jomc.model.Text;
078import org.jomc.modlet.Model;
079import org.jomc.modlet.ModelContext;
080import org.jomc.modlet.ModelException;
081import org.jomc.modlet.ModelValidationReport;
082import org.jomc.modlet.ModelValidator;
083import org.jomc.util.ParseException;
084import org.jomc.util.TokenMgrError;
085import org.jomc.util.VersionParser;
086import org.w3c.dom.Element;
087
088/**
089 * Default object management and configuration {@code ModelValidator} implementation.
090 *
091 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
092 * @version $JOMC: DefaultModelValidator.java 5374 2016-09-05 12:24:12Z schulte $
093 * @see ModelContext#validateModel(org.jomc.modlet.Model)
094 */
095public class DefaultModelValidator implements ModelValidator
096{
097
098    /**
099     * Constant for the name of the model context attribute backing property {@code enabled}.
100     *
101     * @see #validateModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
102     * @see ModelContext#getAttribute(java.lang.String)
103     * @since 1.7
104     */
105    public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.model.modlet.DefaultModelValidator.enabledAttribute";
106
107    /**
108     * Constant for the name of the system property controlling property {@code defaultEnabled}.
109     *
110     * @see #isDefaultEnabled()
111     * @since 1.7
112     */
113    private static final String DEFAULT_ENABLED_PROPERTY_NAME =
114        "org.jomc.model.modlet.DefaultModelValidator.defaultEnabled";
115
116    /**
117     * Default value of the flag indicating the validator is enabled by default.
118     *
119     * @see #isDefaultEnabled()
120     * @since 1.7
121     */
122    private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;
123
124    /**
125     * Flag indicating the validator is enabled by default.
126     *
127     * @since 1.7
128     */
129    private static volatile Boolean defaultEnabled;
130
131    /**
132     * Flag indicating the validator is enabled.
133     *
134     * @since 1.7
135     */
136    private Boolean enabled;
137
138    /**
139     * Constant for the name of the model context attribute backing property {@code validateJava}.
140     *
141     * @see ModelContext#getAttribute(java.lang.String)
142     * @since 1.4
143     */
144    public static final String VALIDATE_JAVA_ATTRIBUTE_NAME =
145        "org.jomc.model.modlet.DefaultModelValidator.validateJavaAttribute";
146
147    /**
148     * Constant for the name of the system property controlling property {@code defaultValidateJava}.
149     *
150     * @see #isDefaultValidateJava()
151     * @since 1.4
152     */
153    private static final String DEFAULT_VALIDATE_JAVA_PROPERTY_NAME =
154        "org.jomc.model.modlet.DefaultModelValidator.defaultValidateJava";
155
156    /**
157     * Default value of the flag indicating the validator is performing Java related validation by default.
158     *
159     * @see #isDefaultValidateJava()
160     * @since 1.4
161     */
162    private static final Boolean DEFAULT_VALIDATE_JAVA = Boolean.TRUE;
163
164    /**
165     * Flag indicating the validator is performing Java related validation by default.
166     *
167     * @since 1.4
168     */
169    private static volatile Boolean defaultValidateJava;
170
171    /**
172     * Flag indicating the validator is performing Java related validation.
173     *
174     * @since 1.4
175     */
176    private Boolean validateJava;
177
178    /**
179     * Creates a new {@code DefaultModelValidator} instance.
180     */
181    public DefaultModelValidator()
182    {
183        super();
184    }
185
186    /**
187     * Gets a flag indicating the validator is enabled by default.
188     * <p>
189     * The default enabled flag is controlled by system property
190     * {@code org.jomc.model.modlet.DefaultModelValidator.defaultEnabled} holding a value indicating the validator is
191     * enabled by default. If that property is not set, the {@code true} default is returned.
192     * </p>
193     *
194     * @return {@code true}, if the validator is enabled by default; {@code false}, if the validator is disabled by
195     * default.
196     *
197     * @see #setDefaultEnabled(java.lang.Boolean)
198     * @since 1.7
199     */
200    public static boolean isDefaultEnabled()
201    {
202        if ( defaultEnabled == null )
203        {
204            defaultEnabled = Boolean.valueOf( System.getProperty( DEFAULT_ENABLED_PROPERTY_NAME,
205                                                                  Boolean.toString( DEFAULT_ENABLED ) ) );
206
207        }
208
209        return defaultEnabled;
210    }
211
212    /**
213     * Sets the flag indicating the validator is enabled by default.
214     *
215     * @param value The new value of the flag indicating the validator is enabled by default or {@code null}.
216     *
217     * @see #isDefaultEnabled()
218     * @since 1.7
219     */
220    public static void setDefaultEnabled( final Boolean value )
221    {
222        defaultEnabled = value;
223    }
224
225    /**
226     * Gets a flag indicating the validator is enabled.
227     *
228     * @return {@code true}, if the validator is enabled; {@code false}, if the validator is disabled.
229     *
230     * @see #isDefaultEnabled()
231     * @see #setEnabled(java.lang.Boolean)
232     * @since 1.7
233     */
234    public final boolean isEnabled()
235    {
236        if ( this.enabled == null )
237        {
238            this.enabled = isDefaultEnabled();
239        }
240
241        return this.enabled;
242    }
243
244    /**
245     * Sets the flag indicating the validator is enabled.
246     *
247     * @param value The new value of the flag indicating the validator is enabled or {@code null}.
248     *
249     * @see #isEnabled()
250     * @since 1.7
251     */
252    public final void setEnabled( final Boolean value )
253    {
254        this.enabled = value;
255    }
256
257    /**
258     * Gets a flag indicating the validator is performing Java related validation by default.
259     * <p>
260     * The default validate Java flag is controlled by system property
261     * {@code org.jomc.model.modlet.DefaultModelValidator.defaultValidateJava} holding a value indicating the validator
262     * is performing Java related validation by default. If that property is not set, the {@code true} default is
263     * returned.
264     * </p>
265     *
266     * @return {@code true}, if the validator is performing Java related validation by default; {@code false}, if the
267     * validator is not performing Java related validation by default.
268     *
269     * @see #setDefaultValidateJava(java.lang.Boolean)
270     *
271     * @since 1.4
272     */
273    public static boolean isDefaultValidateJava()
274    {
275        if ( defaultValidateJava == null )
276        {
277            defaultValidateJava = Boolean.valueOf( System.getProperty( DEFAULT_VALIDATE_JAVA_PROPERTY_NAME,
278                                                                       Boolean.toString( DEFAULT_VALIDATE_JAVA ) ) );
279
280        }
281
282        return defaultValidateJava;
283    }
284
285    /**
286     * Sets the flag indicating the validator is performing Java related validation by default.
287     *
288     * @param value The new value of the flag indicating the validator is performing Java related validation by default
289     * or {@code null}.
290     *
291     * @see #isDefaultValidateJava()
292     *
293     * @since 1.4
294     */
295    public static void setDefaultValidateJava( final Boolean value )
296    {
297        defaultValidateJava = value;
298    }
299
300    /**
301     * Gets a flag indicating the validator is performing Java related validation.
302     *
303     * @return {@code true}, if the validator is performing Java related validation; {@code false}, if the the validator
304     * is not performing Java related validation.
305     *
306     * @see #isDefaultValidateJava()
307     * @see #setValidateJava(java.lang.Boolean)
308     *
309     * @since 1.4
310     */
311    public final boolean isValidateJava()
312    {
313        if ( this.validateJava == null )
314        {
315            this.validateJava = isDefaultValidateJava();
316        }
317
318        return this.validateJava;
319    }
320
321    /**
322     * Sets the flag indicating the validator is performing Java related validation.
323     *
324     * @param value The new value of the flag indicating the validator is performing Java related validation or
325     * {@code null}.
326     *
327     * @see #isValidateJava()
328     *
329     * @since 1.4
330     */
331    public final void setValidateJava( final Boolean value )
332    {
333        this.validateJava = value;
334    }
335
336    public ModelValidationReport validateModel( final ModelContext context, final Model model ) throws ModelException
337    {
338        if ( context == null )
339        {
340            throw new NullPointerException( "context" );
341        }
342        if ( model == null )
343        {
344            throw new NullPointerException( "model" );
345        }
346
347        boolean contextEnabled = this.isEnabled();
348        if ( DEFAULT_ENABLED == contextEnabled
349                 && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
350        {
351            contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME );
352        }
353
354        boolean contextValidateJava = this.isValidateJava();
355        if ( DEFAULT_VALIDATE_JAVA == contextValidateJava
356                 && context.getAttribute( VALIDATE_JAVA_ATTRIBUTE_NAME ) instanceof Boolean )
357        {
358            contextValidateJava = (Boolean) context.getAttribute( VALIDATE_JAVA_ATTRIBUTE_NAME );
359        }
360
361        try
362        {
363            ModelValidationReport report = new ModelValidationReport();
364
365            if ( contextEnabled )
366            {
367                final Source source = new JAXBSource( context.createContext( model.getIdentifier() ),
368                                                      new org.jomc.modlet.ObjectFactory().createModel( model ) );
369
370                report = context.validateModel( model.getIdentifier(), source );
371
372                final Modules modules = ModelHelper.getModules( model );
373
374                if ( modules != null )
375                {
376                    final ValidationContext validationContext =
377                        new ValidationContext( context, modules, report, contextValidateJava );
378
379                    assertModulesValid( validationContext );
380                    assertSpecificationsValid( validationContext );
381                    assertImplementationsValid( validationContext );
382                }
383            }
384            else if ( context.isLoggable( Level.FINER ) )
385            {
386                context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName(),
387                                                      model.getIdentifier() ), null );
388
389            }
390
391            return report;
392        }
393        catch ( final JAXBException e )
394        {
395            String message = getMessage( e );
396            if ( message == null && e.getLinkedException() != null )
397            {
398                message = getMessage( e.getLinkedException() );
399            }
400
401            if ( context.isLoggable( Level.FINE ) )
402            {
403                context.log( Level.FINE, message, e );
404            }
405
406            throw new ModelException( message, e );
407        }
408    }
409
410    private static void assertModulesValid( final ValidationContext validationContext ) throws ModelException
411    {
412        try
413        {
414            class ValidateModuleTask implements Callable<Void>
415            {
416
417                private final Module module;
418
419                ValidateModuleTask( final Module module )
420                {
421                    super();
422                    this.module = module;
423                }
424
425                public Void call()
426                {
427                    assertModuleValid( this.module, validationContext );
428                    return null;
429                }
430
431            }
432
433            final List<ValidateModuleTask> tasks = new LinkedList<ValidateModuleTask>();
434
435            for ( int i = 0, s0 = validationContext.getModules().getModule().size(); i < s0; i++ )
436            {
437                tasks.add( new ValidateModuleTask( validationContext.getModules().getModule().get( i ) ) );
438            }
439
440            if ( validationContext.getModelContext().getExecutorService() != null
441                     && tasks.size() > 1 )
442            {
443                for ( final Future<Void> task
444                          : validationContext.getModelContext().getExecutorService().invokeAll( tasks ) )
445                {
446                    task.get();
447                }
448            }
449            else
450            {
451                for ( final ValidateModuleTask task : tasks )
452                {
453                    task.call();
454                }
455            }
456        }
457        catch ( final CancellationException e )
458        {
459            throw new ModelException( getMessage( e ), e );
460        }
461        catch ( final InterruptedException e )
462        {
463            throw new ModelException( getMessage( e ), e );
464        }
465        catch ( final ExecutionException e )
466        {
467            if ( e.getCause() instanceof RuntimeException )
468            {
469                // The fork-join framework breaks the exception handling contract of Callable by re-throwing any
470                // exception caught using a runtime exception.
471                if ( e.getCause().getCause() instanceof RuntimeException )
472                {
473                    throw (RuntimeException) e.getCause().getCause();
474                }
475                else if ( e.getCause().getCause() instanceof Error )
476                {
477                    throw (Error) e.getCause().getCause();
478                }
479                else if ( e.getCause().getCause() instanceof Exception )
480                {
481                    // Checked exception not declared to be thrown by the Callable's 'call' method.
482                    throw new UndeclaredThrowableException( e.getCause().getCause() );
483                }
484                else
485                {
486                    throw (RuntimeException) e.getCause();
487                }
488            }
489            else if ( e.getCause() instanceof Error )
490            {
491                throw (Error) e.getCause();
492            }
493            else
494            {
495                // Checked exception not declared to be thrown by the Callable's 'call' method.
496                throw new UndeclaredThrowableException( e.getCause() );
497            }
498        }
499    }
500
501    private static void assertModuleValid( final Module m, final ValidationContext validationContext )
502    {
503
504        if ( m.getImplementations() != null )
505        {
506            for ( int j = 0, s1 = m.getImplementations().getReference().size(); j < s1; j++ )
507            {
508                final ImplementationReference r = m.getImplementations().getReference().get( j );
509                addDetail( validationContext.getReport(), "MODULE_IMPLEMENTATION_REFERENCE_DECLARATION_CONSTRAINT",
510                           Level.SEVERE, new ObjectFactory().createModule( m ),
511                           "moduleImplementationReferenceDeclarationConstraint", m.getName(), r.getIdentifier() );
512
513            }
514        }
515
516        if ( m.getMessages() != null )
517        {
518            for ( int j = 0, s1 = m.getMessages().getMessage().size(); j < s1; j++ )
519            {
520                final Message msg = m.getMessages().getMessage().get( j );
521
522                if ( msg.isFinal() )
523                {
524                    addDetail( validationContext.getReport(), "MODULE_FINAL_MESSAGE_DECLARATION_CONSTRAINT",
525                               Level.SEVERE, new ObjectFactory().createModule( m ), "moduleFinalMessageConstraint",
526                               m.getName(), msg.getName() );
527
528                }
529
530                if ( msg.isOverride() )
531                {
532                    addDetail( validationContext.getReport(), "MODULE_OVERRIDE_MESSAGE_DECLARATION_CONSTRAINT",
533                               Level.SEVERE, new ObjectFactory().createModule( m ),
534                               "moduleOverrideMessageConstraint", m.getName(), msg.getName() );
535
536                }
537
538                if ( validationContext.isValidateJava() )
539                {
540                    try
541                    {
542                        msg.getJavaConstantName();
543                    }
544                    catch ( final ModelObjectException e )
545                    {
546                        final String message = getMessage( e );
547
548                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
549                        {
550                            validationContext.getModelContext().log( Level.FINE, message, e );
551                        }
552
553                        addDetail( validationContext.getReport(),
554                                   "MODULE_MESSAGE_JAVA_CONSTANT_NAME_CONSTRAINT",
555                                   Level.SEVERE, new ObjectFactory().createModule( m ),
556                                   "moduleMessageJavaConstantNameConstraint", m.getName(), msg.getName(),
557                                   message != null && message.length() > 0 ? " " + message : "" );
558
559                    }
560
561                    try
562                    {
563                        msg.getJavaGetterMethodName();
564                    }
565                    catch ( final ModelObjectException e )
566                    {
567                        final String message = getMessage( e );
568
569                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
570                        {
571                            validationContext.getModelContext().log( Level.FINE, message, e );
572                        }
573
574                        addDetail( validationContext.getReport(),
575                                   "MODULE_MESSAGE_JAVA_GETTER_METHOD_NAME_CONSTRAINT",
576                                   Level.SEVERE, new ObjectFactory().createModule( m ),
577                                   "moduleMessageJavaGetterMethodNameConstraint", m.getName(), msg.getName(),
578                                   message != null && message.length() > 0 ? " " + message : "" );
579
580                    }
581
582                    try
583                    {
584                        msg.getJavaSetterMethodName();
585                    }
586                    catch ( final ModelObjectException e )
587                    {
588                        final String message = getMessage( e );
589
590                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
591                        {
592                            validationContext.getModelContext().log( Level.FINE, message, e );
593                        }
594
595                        addDetail( validationContext.getReport(),
596                                   "MODULE_MESSAGE_JAVA_SETTER_METHOD_NAME_CONSTRAINT",
597                                   Level.SEVERE, new ObjectFactory().createModule( m ),
598                                   "moduleMessageJavaSetterMethodNameConstraint", m.getName(), msg.getName(),
599                                   message != null && message.length() > 0 ? " " + message : "" );
600
601                    }
602
603                    try
604                    {
605                        msg.getJavaVariableName();
606                    }
607                    catch ( final ModelObjectException e )
608                    {
609                        final String message = getMessage( e );
610
611                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
612                        {
613                            validationContext.getModelContext().log( Level.FINE, message, e );
614                        }
615
616                        addDetail( validationContext.getReport(),
617                                   "MODULE_MESSAGE_JAVA_VARIABLE_NAME_CONSTRAINT",
618                                   Level.SEVERE, new ObjectFactory().createModule( m ),
619                                   "moduleMessageJavaVariableNameConstraint", m.getName(), msg.getName(),
620                                   message != null && message.length() > 0 ? " " + message : "" );
621
622                    }
623                }
624
625                if ( msg.getTemplate() != null )
626                {
627                    for ( int k = 0, s2 = msg.getTemplate().getText().size(); k < s2; k++ )
628                    {
629                        final Text t = msg.getTemplate().getText().get( k );
630
631                        try
632                        {
633                            t.getMimeType();
634                        }
635                        catch ( final ModelObjectException e )
636                        {
637                            final String message = getMessage( e );
638
639                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
640                            {
641                                validationContext.getModelContext().log( Level.FINE, message, e );
642                            }
643
644                            addDetail( validationContext.getReport(),
645                                       "MODULE_MESSAGE_TEMPLATE_MIME_TYPE_CONSTRAINT",
646                                       Level.SEVERE, new ObjectFactory().createModule( m ),
647                                       "moduleMessageTemplateMimeTypeConstraint", m.getName(), msg.getName(),
648                                       t.getLanguage(),
649                                       message != null && message.length() > 0 ? " " + message : "" );
650
651                        }
652
653                        if ( validationContext.isValidateJava() )
654                        {
655                            try
656                            {
657                                new MessageFormat( t.getValue(), new Locale( t.getLanguage() ) );
658                            }
659                            catch ( final IllegalArgumentException e )
660                            {
661                                final String message = getMessage( e );
662
663                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
664                                {
665                                    validationContext.getModelContext().log( Level.FINE, message, e );
666                                }
667
668                                addDetail( validationContext.getReport(), "MODULE_MESSAGE_TEMPLATE_CONSTRAINT",
669                                           Level.SEVERE, new ObjectFactory().createModule( m ),
670                                           "moduleMessageTemplateConstraint", m.getName(), msg.getName(),
671                                           t.getValue(),
672                                           message != null && message.length() > 0 ? " " + message : "" );
673
674                            }
675                        }
676                    }
677                }
678
679                if ( msg.getArguments() != null )
680                {
681                    final Map<JavaIdentifier, Argument> javaVariableNames =
682                        new HashMap<JavaIdentifier, Argument>( msg.getArguments().getArgument().size() );
683
684                    for ( int k = 0, s2 = msg.getArguments().getArgument().size(); k < s2; k++ )
685                    {
686                        final Argument a = msg.getArguments().getArgument( k );
687
688                        if ( validationContext.isValidateJava() )
689                        {
690                            try
691                            {
692                                a.getJavaTypeName();
693                            }
694                            catch ( final ModelObjectException e )
695                            {
696                                final String message = getMessage( e );
697
698                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
699                                {
700                                    validationContext.getModelContext().log( Level.FINE, message, e );
701                                }
702
703                                addDetail( validationContext.getReport(),
704                                           "MODULE_MESSAGE_ARGUMENT_JAVA_TYPE_NAME_CONSTRAINT",
705                                           Level.SEVERE, new ObjectFactory().createModule( m ),
706                                           "moduleMessageArgumentJavaTypeNameConstraint", m.getName(),
707                                           msg.getName(), a.getIndex(),
708                                           message != null && message.length() > 0 ? " " + message : "" );
709
710                            }
711
712                            try
713                            {
714                                final JavaIdentifier javaIdentifier = a.getJavaVariableName();
715
716                                if ( javaVariableNames.containsKey( javaIdentifier ) )
717                                {
718                                    addDetail( validationContext.getReport(),
719                                               "MODULE_MESSAGE_ARGUMENT_JAVA_VARIABLE_NAME_UNIQUENESS_CONSTRAINT",
720                                               Level.SEVERE, new ObjectFactory().createModule( m ),
721                                               "moduleMessageArgumentJavaVariableNameUniquenessConstraint",
722                                               m.getName(), msg.getName(), a.getName(),
723                                               javaIdentifier, javaVariableNames.get( javaIdentifier ).getName() );
724
725                                }
726                                else
727                                {
728                                    javaVariableNames.put( javaIdentifier, a );
729                                }
730                            }
731                            catch ( final ModelObjectException e )
732                            {
733                                final String message = getMessage( e );
734
735                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
736                                {
737                                    validationContext.getModelContext().log( Level.FINE, message, e );
738                                }
739
740                                addDetail( validationContext.getReport(),
741                                           "MODULE_MESSAGE_ARGUMENT_JAVA_VARIABLE_NAME_CONSTRAINT",
742                                           Level.SEVERE, new ObjectFactory().createModule( m ),
743                                           "moduleMessageArgumentJavaVariableNameConstraint", m.getName(),
744                                           msg.getName(), a.getIndex(),
745                                           message != null && message.length() > 0 ? " " + message : "" );
746
747                            }
748                        }
749                    }
750                }
751            }
752
753            for ( int j = 0, s1 = m.getMessages().getReference().size(); j < s1; j++ )
754            {
755                final MessageReference r = m.getMessages().getReference().get( j );
756                addDetail( validationContext.getReport(), "MODULE_MESSAGE_REFERENCE_DECLARATION_CONSTRAINT",
757                           Level.SEVERE, new ObjectFactory().createModule( m ),
758                           "moduleMessageReferenceDeclarationConstraint", m.getName(), r.getName() );
759
760            }
761        }
762
763        if ( m.getProperties() != null )
764        {
765            for ( int j = 0, s1 = m.getProperties().getProperty().size(); j < s1; j++ )
766            {
767                final Property p = m.getProperties().getProperty().get( j );
768
769                if ( p.isFinal() )
770                {
771                    addDetail( validationContext.getReport(), "MODULE_FINAL_PROPERTY_DECLARATION_CONSTRAINT",
772                               Level.SEVERE, new ObjectFactory().createModule( m ), "moduleFinalPropertyConstraint",
773                               m.getName(), p.getName() );
774
775                }
776
777                if ( p.isOverride() )
778                {
779                    addDetail( validationContext.getReport(), "MODULE_OVERRIDE_PROPERTY_DECLARATION_CONSTRAINT",
780                               Level.SEVERE, new ObjectFactory().createModule( m ),
781                               "moduleOverridePropertyConstraint", m.getName(), p.getName() );
782
783                }
784
785                if ( p.getValue() != null && p.getAny() != null )
786                {
787                    addDetail( validationContext.getReport(), "MODULE_PROPERTY_VALUE_CONSTRAINT", Level.SEVERE,
788                               new ObjectFactory().createModule( m ), "modulePropertyValueConstraint", m.getName(),
789                               p.getName() );
790
791                }
792
793                if ( p.getAny() != null && p.getType() == null )
794                {
795                    addDetail( validationContext.getReport(), "MODULE_PROPERTY_TYPE_CONSTRAINT", Level.SEVERE,
796                               new ObjectFactory().createModule( m ), "modulePropertyTypeConstraint", m.getName(),
797                               p.getName() );
798
799                }
800
801                if ( validationContext.isValidateJava() )
802                {
803                    try
804                    {
805                        p.getJavaConstantName();
806                    }
807                    catch ( final ModelObjectException e )
808                    {
809                        final String message = getMessage( e );
810
811                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
812                        {
813                            validationContext.getModelContext().log( Level.FINE, message, e );
814                        }
815
816                        addDetail( validationContext.getReport(),
817                                   "MODULE_PROPERTY_JAVA_CONSTANT_NAME_CONSTRAINT",
818                                   Level.SEVERE, new ObjectFactory().createModule( m ),
819                                   "modulePropertyJavaConstantNameConstraint", m.getName(), p.getName(),
820                                   message != null && message.length() > 0 ? " " + message : "" );
821
822                    }
823
824                    try
825                    {
826                        p.getJavaGetterMethodName();
827                    }
828                    catch ( final ModelObjectException e )
829                    {
830                        final String message = getMessage( e );
831
832                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
833                        {
834                            validationContext.getModelContext().log( Level.FINE, message, e );
835                        }
836
837                        addDetail( validationContext.getReport(),
838                                   "MODULE_PROPERTY_JAVA_GETTER_METHOD_NAME_CONSTRAINT",
839                                   Level.SEVERE, new ObjectFactory().createModule( m ),
840                                   "modulePropertyJavaGetterMethodNameConstraint", m.getName(), p.getName(),
841                                   message != null && message.length() > 0 ? " " + message : "" );
842
843                    }
844
845                    try
846                    {
847                        p.getJavaSetterMethodName();
848                    }
849                    catch ( final ModelObjectException e )
850                    {
851                        final String message = getMessage( e );
852
853                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
854                        {
855                            validationContext.getModelContext().log( Level.FINE, message, e );
856                        }
857
858                        addDetail( validationContext.getReport(),
859                                   "MODULE_PROPERTY_JAVA_SETTER_METHOD_NAME_CONSTRAINT",
860                                   Level.SEVERE, new ObjectFactory().createModule( m ),
861                                   "modulePropertyJavaSetterMethodNameConstraint", m.getName(), p.getName(),
862                                   message != null && message.length() > 0 ? " " + message : "" );
863
864                    }
865
866                    try
867                    {
868                        p.getJavaTypeName();
869                    }
870                    catch ( final ModelObjectException e )
871                    {
872                        final String message = getMessage( e );
873
874                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
875                        {
876                            validationContext.getModelContext().log( Level.FINE, message, e );
877                        }
878
879                        addDetail( validationContext.getReport(),
880                                   "MODULE_PROPERTY_JAVA_TYPE_NAME_CONSTRAINT",
881                                   Level.SEVERE, new ObjectFactory().createModule( m ),
882                                   "modulePropertyJavaTypeNameConstraint", m.getName(), p.getName(),
883                                   message != null && message.length() > 0 ? " " + message : "" );
884
885                    }
886
887                    try
888                    {
889                        p.getJavaVariableName();
890                    }
891                    catch ( final ModelObjectException e )
892                    {
893                        final String message = getMessage( e );
894
895                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
896                        {
897                            validationContext.getModelContext().log( Level.FINE, message, e );
898                        }
899
900                        addDetail( validationContext.getReport(),
901                                   "MODULE_PROPERTY_JAVA_VARIABLE_NAME_CONSTRAINT",
902                                   Level.SEVERE, new ObjectFactory().createModule( m ),
903                                   "modulePropertyJavaVariableNameConstraint", m.getName(), p.getName(),
904                                   message != null && message.length() > 0 ? " " + message : "" );
905
906                    }
907
908                    try
909                    {
910                        p.getJavaValue( validationContext.getModelContext().getClassLoader() );
911                    }
912                    catch ( final ModelObjectException e )
913                    {
914                        final String message = getMessage( e );
915
916                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
917                        {
918                            validationContext.getModelContext().log( Level.FINE, message, e );
919                        }
920
921                        addDetail( validationContext.getReport(), "MODULE_PROPERTY_JAVA_VALUE_CONSTRAINT",
922                                   Level.SEVERE, new ObjectFactory().createModule( m ),
923                                   "modulePropertyJavaValueConstraint", m.getName(), p.getName(),
924                                   message != null && message.length() > 0 ? " " + message : "" );
925
926                    }
927                }
928            }
929
930            for ( int j = 0, s1 = m.getProperties().getReference().size(); j < s1; j++ )
931            {
932                final PropertyReference r = m.getProperties().getReference().get( j );
933                addDetail( validationContext.getReport(), "MODULE_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT",
934                           Level.SEVERE, new ObjectFactory().createModule( m ),
935                           "modulePropertyReferenceDeclarationConstraint", m.getName(), r.getName() );
936
937            }
938        }
939
940        if ( m.getSpecifications() != null )
941        {
942            for ( int j = 0, s1 = m.getSpecifications().getReference().size(); j < s1; j++ )
943            {
944                final SpecificationReference r = m.getSpecifications().getReference().get( j );
945                addDetail( validationContext.getReport(), "MODULE_SPECIFICATION_REFERENCE_DECLARATION_CONSTRAINT",
946                           Level.SEVERE, new ObjectFactory().createModule( m ),
947                           "moduleSpecificationReferenceDeclarationConstraint", m.getName(), r.getIdentifier() );
948
949            }
950        }
951    }
952
953    private static void assertImplementationsValid( final ValidationContext validationContext ) throws ModelException
954    {
955        final Implementations implementations = validationContext.getAllImplementations();
956
957        if ( implementations != null )
958        {
959            final List<Callable<Void>> tasks = new LinkedList<Callable<Void>>();
960            final Map<String, Implementation> implementationClassDeclarations = new HashMap<String, Implementation>();
961            final Map<String, Implementation> implementationJavaClassDeclarations =
962                new HashMap<String, Implementation>();
963
964            for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
965            {
966                final Implementation impl = implementations.getImplementation().get( i );
967                final InheritanceModel imodel = validationContext.getInheritanceModel();
968                final Module moduleOfImpl = validationContext.getModuleOfImplementation( impl.getIdentifier() );
969                final Set<InheritanceModel.Node<ImplementationReference>> cyclicImplementationReferenceNodes =
970                    imodel.getCycleNodes( impl.getIdentifier() );
971
972                for ( final InheritanceModel.Node<ImplementationReference> node : cyclicImplementationReferenceNodes )
973                {
974                    addDetail( validationContext.getReport(), "IMPLEMENTATION_INHERITANCE_CYCLE_CONSTRAINT",
975                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
976                               "implementationInheritanceCycleConstraint", impl.getIdentifier(),
977                               moduleOfImpl.getName(), getNodePathString( node ) );
978
979                }
980
981                if ( validationContext.isValidateJava() )
982                {
983                    try
984                    {
985                        impl.getJavaTypeName();
986                    }
987                    catch ( final ModelObjectException e )
988                    {
989                        final String message = getMessage( e );
990
991                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
992                        {
993                            validationContext.getModelContext().log( Level.FINE, message, e );
994                        }
995
996                        addDetail( validationContext.getReport(),
997                                   "IMPLEMENTATION_JAVA_TYPE_NAME_CONSTRAINT",
998                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
999                                   "implementationJavaTypeNameConstraint", impl.getIdentifier(),
1000                                   moduleOfImpl.getName(), impl.getClazz(),
1001                                   message != null && message.length() > 0 ? " " + message : "" );
1002
1003                    }
1004                }
1005
1006                if ( impl.isClassDeclaration() )
1007                {
1008                    if ( impl.getClazz() == null )
1009                    {
1010                        addDetail( validationContext.getReport(), "IMPLEMENTATION_CLASS_CONSTRAINT", Level.SEVERE,
1011                                   new ObjectFactory().createImplementation( impl ), "implementationClassConstraint",
1012                                   impl.getIdentifier(), moduleOfImpl.getName() );
1013
1014                    }
1015                    else
1016                    {
1017                        final Implementation prev = implementationClassDeclarations.get( impl.getClazz() );
1018
1019                        if ( prev != null && !prev.getIdentifier().equals( impl.getIdentifier() ) )
1020                        {
1021                            final Module moduleOfPrev =
1022                                validationContext.getModuleOfImplementation( prev.getIdentifier() );
1023
1024                            addDetail( validationContext.getReport(), "IMPLEMENTATION_CLASS_DECLARATION_CONSTRAINT",
1025                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1026                                       "implementationClassDeclarationConstraint", impl.getIdentifier(),
1027                                       moduleOfImpl.getName(), impl.getClazz(), prev.getIdentifier(),
1028                                       moduleOfPrev.getName() );
1029
1030                        }
1031                        else
1032                        {
1033                            implementationClassDeclarations.put( impl.getClazz(), impl );
1034                        }
1035
1036                        if ( validationContext.isValidateJava() )
1037                        {
1038                            try
1039                            {
1040                                final Implementation java =
1041                                    implementationJavaClassDeclarations.get( impl.getJavaTypeName().getClassName() );
1042
1043                                if ( java != null && !java.getIdentifier().equals( impl.getIdentifier() ) )
1044                                {
1045                                    final Module moduleOfJava =
1046                                        validationContext.getModuleOfImplementation( java.getIdentifier() );
1047
1048                                    addDetail( validationContext.getReport(),
1049                                               "IMPLEMENTATION_JAVA_CLASS_DECLARATION_CONSTRAINT",
1050                                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1051                                               "implementationJavaClassDeclarationConstraint", impl.getIdentifier(),
1052                                               moduleOfImpl.getName(), impl.getJavaTypeName().getClassName(),
1053                                               java.getIdentifier(), moduleOfJava.getName() );
1054
1055                                }
1056                                else
1057                                {
1058                                    implementationJavaClassDeclarations.put( impl.getJavaTypeName().getClassName(),
1059                                                                             impl );
1060
1061                                }
1062                            }
1063                            catch ( final ModelObjectException e )
1064                            {
1065                                // Already validated above.
1066                            }
1067                        }
1068                    }
1069                }
1070
1071                if ( impl.isAbstract() && impl.getLocation() != null )
1072                {
1073                    addDetail( validationContext.getReport(), "IMPLEMENTATION_ABSTRACT_LOCATION_DECLARATION_CONSTRAINT",
1074                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1075                               "implementationAbstractLocationDeclarationConstraint", impl.getIdentifier(),
1076                               moduleOfImpl.getName(), impl.getLocation() );
1077
1078                }
1079
1080                if ( impl.getDependencies() != null )
1081                {
1082                    for ( int j = 0, s1 = impl.getDependencies().getDependency().size(); j < s1; j++ )
1083                    {
1084                        final Dependency d = impl.getDependencies().getDependency().get( j );
1085                        tasks.add( new Callable<Void>()
1086                        {
1087
1088                            public Void call()
1089                            {
1090                                assertValidDependency( validationContext, impl, d );
1091                                return null;
1092                            }
1093
1094                        } );
1095                    }
1096                }
1097
1098                if ( impl.getImplementations() != null )
1099                {
1100                    final Set<String> effImplementationReferences =
1101                        imodel.getImplementationReferenceIdentifiers( impl.getIdentifier() );
1102
1103                    for ( final String effImplementationReference : effImplementationReferences )
1104                    {
1105                        final Implementation ancestorImplementation =
1106                            validationContext.getImplementation( effImplementationReference );
1107
1108                        if ( ancestorImplementation != null && ancestorImplementation.isFinal() )
1109                        {
1110                            final Module moduleOfFinal =
1111                                validationContext.getModuleOfImplementation( ancestorImplementation.getIdentifier() );
1112
1113                            addDetail( validationContext.getReport(),
1114                                       "IMPLEMENTATION_IMPLEMENTATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
1115                                       new ObjectFactory().createImplementation( impl ),
1116                                       "implementationFinalImplementationConstraint", impl.getIdentifier(),
1117                                       moduleOfImpl.getName(), ancestorImplementation.getIdentifier(),
1118                                       moduleOfFinal.getName() );
1119
1120                        }
1121                    }
1122
1123                    for ( int j = 0, s1 = impl.getImplementations().getImplementation().size(); j < s1; j++ )
1124                    {
1125                        final Implementation pi = impl.getImplementations().getImplementation().get( j );
1126
1127                        addDetail( validationContext.getReport(),
1128                                   "IMPLEMENTATION_IMPLEMENTATION_DECLARATION_CONSTRAINT", Level.SEVERE,
1129                                   new ObjectFactory().createImplementation( impl ),
1130                                   "implementationImplementationDeclarationConstraint", impl.getIdentifier(),
1131                                   moduleOfImpl.getName(), pi.getIdentifier() );
1132
1133                    }
1134
1135                    for ( int j = 0, s1 = impl.getImplementations().getReference().size(); j < s1; j++ )
1136                    {
1137                        final ImplementationReference r = impl.getImplementations().getReference().get( j );
1138
1139                        tasks.add( new Callable<Void>()
1140                        {
1141
1142                            public Void call()
1143                            {
1144                                assertValidImplementationReference( validationContext, impl, r );
1145                                return null;
1146                            }
1147
1148                        } );
1149                    }
1150                }
1151
1152                if ( impl.getMessages() != null )
1153                {
1154                    for ( int j = 0, s1 = impl.getMessages().getMessage().size(); j < s1; j++ )
1155                    {
1156                        final Message m = impl.getMessages().getMessage().get( j );
1157                        tasks.add( new Callable<Void>()
1158                        {
1159
1160                            public Void call()
1161                            {
1162                                assertValidMessage( validationContext, impl, m );
1163                                return null;
1164                            }
1165
1166                        } );
1167
1168                    }
1169
1170                    for ( int j = 0, s1 = impl.getMessages().getReference().size(); j < s1; j++ )
1171                    {
1172                        final MessageReference r = impl.getMessages().getReference().get( j );
1173
1174                        tasks.add( new Callable<Void>()
1175                        {
1176
1177                            public Void call()
1178                            {
1179                                assertValidMessageReference( validationContext, impl, r );
1180                                return null;
1181                            }
1182
1183                        } );
1184                    }
1185                }
1186
1187                if ( impl.getProperties() != null )
1188                {
1189                    for ( int j = 0, s1 = impl.getProperties().getProperty().size(); j < s1; j++ )
1190                    {
1191                        final Property p = impl.getProperties().getProperty().get( j );
1192
1193                        tasks.add( new Callable<Void>()
1194                        {
1195
1196                            public Void call()
1197                            {
1198                                assertValidProperty( validationContext, impl, p );
1199                                return null;
1200                            }
1201
1202                        } );
1203
1204                    }
1205
1206                    for ( int j = 0, s1 = impl.getProperties().getReference().size(); j < s1; j++ )
1207                    {
1208                        final PropertyReference r = impl.getProperties().getReference().get( j );
1209
1210                        tasks.add( new Callable<Void>()
1211                        {
1212
1213                            public Void call()
1214                            {
1215                                assertValidPropertyReference( validationContext, impl, r );
1216                                return null;
1217                            }
1218
1219                        } );
1220
1221                    }
1222                }
1223
1224                if ( impl.getSpecifications() != null )
1225                {
1226                    for ( int j = 0, s1 = impl.getSpecifications().getSpecification().size(); j < s1; j++ )
1227                    {
1228                        final Specification s = impl.getSpecifications().getSpecification().get( j );
1229
1230                        addDetail( validationContext.getReport(), "IMPLEMENTATION_SPECIFICATION_DECLARATION_CONSTRAINT",
1231                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1232                                   "implementationSpecificationDeclarationConstraint", impl.getIdentifier(),
1233                                   moduleOfImpl.getName(), s.getIdentifier() );
1234
1235                    }
1236
1237                    for ( int j = 0, s1 = impl.getSpecifications().getReference().size(); j < s1; j++ )
1238                    {
1239                        final SpecificationReference r = impl.getSpecifications().getReference().get( j );
1240
1241                        tasks.add( new Callable<Void>()
1242                        {
1243
1244                            public Void call()
1245                            {
1246                                assertValidSpecificationReference( validationContext, impl, r );
1247                                return null;
1248                            }
1249
1250                        } );
1251
1252                    }
1253                }
1254
1255                if ( !impl.getAny().isEmpty() )
1256                {
1257                    for ( int j = 0, s1 = impl.getAny().size(); j < s1; j++ )
1258                    {
1259                        final Object any = impl.getAny().get( j );
1260
1261                        tasks.add( new Callable<Void>()
1262                        {
1263
1264                            public Void call()
1265                            {
1266                                assertValidAnyObject( validationContext, impl, any );
1267                                return null;
1268                            }
1269
1270                        } );
1271                    }
1272                }
1273
1274                tasks.add( new Callable<Void>()
1275                {
1276
1277                    public Void call()
1278                    {
1279                        assertUniqueDependencies( validationContext, impl );
1280                        return null;
1281                    }
1282
1283                } );
1284
1285                tasks.add( new Callable<Void>()
1286                {
1287
1288                    public Void call()
1289                    {
1290                        assertUniqueMessages( validationContext, impl );
1291                        return null;
1292                    }
1293
1294                } );
1295
1296                tasks.add( new Callable<Void>()
1297                {
1298
1299                    public Void call()
1300                    {
1301                        assertUniqueProperties( validationContext, impl );
1302                        return null;
1303                    }
1304
1305                } );
1306
1307                final Set<String> specificationReferenceIdentifiers =
1308                    imodel.getSpecificationReferenceIdentifiers( impl.getIdentifier() );
1309
1310                for ( final String specificationRefereneIdentifier : specificationReferenceIdentifiers )
1311                {
1312                    final Set<InheritanceModel.Node<SpecificationReference>> specificationReferenceNodes =
1313                        imodel.getSpecificationReferenceNodes( impl.getIdentifier(), specificationRefereneIdentifier );
1314
1315                    if ( specificationReferenceNodes.size() > 1 )
1316                    {
1317                        addDetail( validationContext.getReport(),
1318                                   "IMPLEMENTATION_SPECIFICATION_MULTIPLE_INHERITANCE_CONSTRAINT",
1319                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1320                                   "implementationMultipleInheritanceSpecificationConstraint",
1321                                   impl.getIdentifier(), moduleOfImpl.getName(), specificationRefereneIdentifier,
1322                                   getNodeListPathString( specificationReferenceNodes ) );
1323
1324                    }
1325                }
1326
1327                final Set<QName> xmlElementNames = imodel.getXmlElementNames( impl.getIdentifier() );
1328
1329                for ( final QName xmlElementName : xmlElementNames )
1330                {
1331                    final Set<InheritanceModel.Node<Element>> xmlElementNodes =
1332                        imodel.getXmlElementNodes( impl.getIdentifier(), xmlElementName );
1333
1334                    if ( xmlElementNodes.size() > 1 )
1335                    {
1336                        addDetail( validationContext.getReport(),
1337                                   "IMPLEMENTATION_XML_ELEMENT_MULTIPLE_INHERITANCE_CONSTRAINT",
1338                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1339                                   "implementationMultipleInheritanceXmlElementConstraint",
1340                                   impl.getIdentifier(), moduleOfImpl.getName(), xmlElementName.toString(),
1341                                   getNodeListPathString( xmlElementNodes ) );
1342
1343                    }
1344                }
1345
1346                final Set<QName> jaxbElementNames = imodel.getJaxbElementNames( impl.getIdentifier() );
1347
1348                for ( final QName jaxbElementName : jaxbElementNames )
1349                {
1350                    final Set<InheritanceModel.Node<JAXBElement<?>>> jaxbElementNodes =
1351                        imodel.getJaxbElementNodes( impl.getIdentifier(), jaxbElementName );
1352
1353                    if ( jaxbElementNodes.size() > 1 )
1354                    {
1355                        addDetail( validationContext.getReport(),
1356                                   "IMPLEMENTATION_JAXB_ELEMENT_MULTIPLE_INHERITANCE_CONSTRAINT",
1357                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1358                                   "implementationMultipleInheritanceJaxbElementConstraint",
1359                                   impl.getIdentifier(), moduleOfImpl.getName(), jaxbElementName.toString(),
1360                                   getNodeListPathString( jaxbElementNodes ) );
1361
1362                    }
1363                }
1364
1365                final Set<String> implementationReferenceIdentifiers =
1366                    imodel.getImplementationReferenceIdentifiers( impl.getIdentifier() );
1367
1368                for ( final String implementationReferenceIdentifier : implementationReferenceIdentifiers )
1369                {
1370                    final Set<InheritanceModel.Node<ImplementationReference>> implementationReferenceNodes =
1371                        imodel.getImplementationReferenceNodes( impl.getIdentifier(),
1372                                                                implementationReferenceIdentifier );
1373
1374                    for ( final InheritanceModel.Node<ImplementationReference> node : implementationReferenceNodes )
1375                    {
1376                        final ImplementationReference r = node.getModelObject();
1377
1378                        final Implementation referenced =
1379                            validationContext.getImplementation( r.getIdentifier() );
1380
1381                        final Module moduleOfReferenced =
1382                            validationContext.getModuleOfImplementation( referenced.getIdentifier() );
1383
1384                        if ( r.getVersion() != null && referenced != null )
1385                        {
1386                            if ( referenced.getVersion() == null )
1387                            {
1388                                addDetail( validationContext.getReport(),
1389                                           "IMPLEMENTATION_IMPLEMENTATION_VERSIONING_CONSTRAINT", Level.SEVERE,
1390                                           new ObjectFactory().createImplementation( impl ),
1391                                           "implementationImplementationVersioningConstraint",
1392                                           impl.getIdentifier(), moduleOfImpl.getName(), r.getIdentifier(),
1393                                           moduleOfReferenced.getName() );
1394
1395                            }
1396                            else
1397                            {
1398                                try
1399                                {
1400                                    if ( VersionParser.compare( r.getVersion(), referenced.getVersion() ) > 0 )
1401                                    {
1402                                        addDetail( validationContext.getReport(),
1403                                                   "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_CONSTRAINT",
1404                                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1405                                                   "implementationInheritanceCompatibilityConstraint",
1406                                                   impl.getIdentifier(), moduleOfImpl.getName(),
1407                                                   referenced.getIdentifier(), moduleOfReferenced.getName(),
1408                                                   r.getVersion(), referenced.getVersion() );
1409
1410                                    }
1411                                }
1412                                catch ( final ParseException ex )
1413                                {
1414                                    final String message = getMessage( ex );
1415
1416                                    if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1417                                    {
1418                                        validationContext.getModelContext().log( Level.FINE, message, ex );
1419                                    }
1420
1421                                    addDetail(
1422                                        validationContext.getReport(),
1423                                        "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_VERSIONING_PARSE_EXCEPTION",
1424                                        Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1425                                        "implementationInheritanceCompatibilityParseException",
1426                                        impl.getIdentifier(), moduleOfImpl.getName(), r.getIdentifier(),
1427                                        moduleOfReferenced.getName(), r.getVersion(),
1428                                        message != null && message.length() > 0 ? " " + message : "" );
1429
1430                                }
1431                                catch ( final TokenMgrError ex )
1432                                {
1433                                    final String message = getMessage( ex );
1434
1435                                    if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1436                                    {
1437                                        validationContext.getModelContext().log( Level.FINE, message, ex );
1438                                    }
1439
1440                                    addDetail(
1441                                        validationContext.getReport(),
1442                                        "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_VERSIONING_TOKEN_MANAGER_ERROR",
1443                                        Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1444                                        "implementationInheritanceCompatiblityVersioningTokenManagerError",
1445                                        impl.getIdentifier(), moduleOfImpl.getName(), r.getIdentifier(),
1446                                        moduleOfReferenced.getName(), r.getVersion(),
1447                                        message != null && message.length() > 0 ? " " + message : "" );
1448
1449                                }
1450                            }
1451                        }
1452                    }
1453                }
1454
1455                tasks.add( new Callable<Void>()
1456                {
1457
1458                    public Void call()
1459                    {
1460                        assertImplementationSpecificationCompatibility( validationContext, impl );
1461                        return null;
1462                    }
1463
1464                } );
1465
1466            }
1467
1468            if ( validationContext.getModelContext().getExecutorService() != null && tasks.size() > 1 )
1469            {
1470                try
1471                {
1472                    for ( final Future<Void> task
1473                              : validationContext.getModelContext().getExecutorService().invokeAll( tasks ) )
1474                    {
1475                        try
1476                        {
1477                            task.get();
1478                        }
1479                        catch ( final ExecutionException e )
1480                        {
1481                            if ( e.getCause() instanceof RuntimeException )
1482                            {
1483                                throw (RuntimeException) e.getCause();
1484                            }
1485                            else if ( e.getCause() instanceof Error )
1486                            {
1487                                throw (Error) e.getCause();
1488                            }
1489                            else
1490                            {
1491                                throw new UndeclaredThrowableException( e.getCause() );
1492                            }
1493                        }
1494                    }
1495                }
1496                catch ( final InterruptedException e )
1497                {
1498                    throw new ModelException( getMessage( e ), e );
1499                }
1500            }
1501            else
1502            {
1503                for ( final Callable<Void> task : tasks )
1504                {
1505                    try
1506                    {
1507                        task.call();
1508                    }
1509                    catch ( final Exception e )
1510                    {
1511                        // None of the callables has declared to throw an exception.
1512                        throw new UndeclaredThrowableException( e );
1513                    }
1514                }
1515            }
1516        }
1517    }
1518
1519    private static void assertValidDependency( final ValidationContext validationContext,
1520                                               final Implementation impl,
1521                                               final Dependency d )
1522    {
1523        final Set<InheritanceModel.Node<Dependency>> effDependencies =
1524            validationContext.getInheritanceModel().getDependencyNodes( impl.getIdentifier(), d.getName() );
1525
1526        for ( final InheritanceModel.Node<Dependency> effDependency : effDependencies )
1527        {
1528            final Set<InheritanceModel.Node<Dependency>> overriddenDependencies =
1529                modifiableSet( effDependency.getOverriddenNodes() );
1530
1531            if ( d.isOverride() && effDependency.getOverriddenNodes().isEmpty() )
1532            {
1533                addDetail( validationContext.getReport(),
1534                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_CONSTRAINT",
1535                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1536                           "implementationDependencyOverrideConstraint", impl.getIdentifier(),
1537                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), d.getName() );
1538
1539            }
1540
1541            if ( !( d.isOverride() || overriddenDependencies.isEmpty() ) )
1542            {
1543                for ( final InheritanceModel.Node<Dependency> overriddenDependency
1544                          : overriddenDependencies )
1545                {
1546                    Implementation overriddenImplementation = overriddenDependency.getImplementation();
1547                    if ( overriddenDependency.getClassDeclaration() != null )
1548                    {
1549                        overriddenImplementation = overriddenDependency.getClassDeclaration();
1550                    }
1551
1552                    final Module moduleOfDependency =
1553                        validationContext.getModuleOfImplementation(
1554                            overriddenImplementation.getIdentifier() );
1555
1556                    addDetail( validationContext.getReport(),
1557                               "IMPLEMENTATION_DEPENDENCY_OVERRIDE_WARNING",
1558                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
1559                               "implementationDependencyOverrideWarning", impl.getIdentifier(),
1560                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
1561                               d.getName(), overriddenImplementation.getIdentifier(), moduleOfDependency.getName(),
1562                               getNodePathString( overriddenDependency ) );
1563
1564                }
1565            }
1566
1567            retainFinalNodes( overriddenDependencies );
1568
1569            for ( final InheritanceModel.Node<Dependency> overriddenDependency : overriddenDependencies )
1570            {
1571                Implementation overriddenImplementation = overriddenDependency.getImplementation();
1572                if ( overriddenDependency.getClassDeclaration() != null )
1573                {
1574                    overriddenImplementation = overriddenDependency.getClassDeclaration();
1575                }
1576
1577                final Module moduleOfDependency =
1578                    validationContext.getModuleOfImplementation(
1579                        overriddenImplementation.getIdentifier() );
1580
1581                addDetail( validationContext.getReport(),
1582                           "IMPLEMENTATION_DEPENDENCY_INHERITANCE_CONSTRAINT", Level.SEVERE,
1583                           new ObjectFactory().createImplementation( impl ),
1584                           "implementationDependencyFinalConstraint", impl.getIdentifier(),
1585                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), d.getName(),
1586                           overriddenImplementation.getIdentifier(),
1587                           moduleOfDependency.getName(),
1588                           getNodePathString( overriddenDependency ) );
1589
1590            }
1591        }
1592
1593        if ( validationContext.isValidateJava() )
1594        {
1595            try
1596            {
1597                d.getJavaConstantName();
1598            }
1599            catch ( final ModelObjectException e )
1600            {
1601                final String message = getMessage( e );
1602
1603                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1604                {
1605                    validationContext.getModelContext().log( Level.FINE, message, e );
1606                }
1607
1608                addDetail( validationContext.getReport(),
1609                           "IMPLEMENTATION_DEPENDENCY_JAVA_CONSTANT_NAME_CONSTRAINT",
1610                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1611                           "implementationDependencyJavaConstantNameConstraint", impl.getIdentifier(),
1612                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), d.getName(),
1613                           message != null && message.length() > 0 ? " " + message : "" );
1614
1615            }
1616
1617            try
1618            {
1619                d.getJavaGetterMethodName();
1620            }
1621            catch ( final ModelObjectException e )
1622            {
1623                final String message = getMessage( e );
1624
1625                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1626                {
1627                    validationContext.getModelContext().log( Level.FINE, message, e );
1628                }
1629
1630                addDetail( validationContext.getReport(),
1631                           "IMPLEMENTATION_DEPENDENCY_JAVA_GETTER_METHOD_NAME_CONSTRAINT",
1632                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1633                           "implementationDependencyJavaGetterMethodNameConstraint",
1634                           impl.getIdentifier(),
1635                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), d.getName(),
1636                           message != null && message.length() > 0 ? " " + message : "" );
1637
1638            }
1639
1640            try
1641            {
1642                d.getJavaSetterMethodName();
1643            }
1644            catch ( final ModelObjectException e )
1645            {
1646                final String message = getMessage( e );
1647
1648                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1649                {
1650                    validationContext.getModelContext().log( Level.FINE, message, e );
1651                }
1652
1653                addDetail( validationContext.getReport(),
1654                           "IMPLEMENTATION_DEPENDENCY_JAVA_SETTER_METHOD_NAME_CONSTRAINT",
1655                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1656                           "implementationDependencyJavaSetterMethodNameConstraint",
1657                           impl.getIdentifier(),
1658                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), d.getName(),
1659                           message != null && message.length() > 0 ? " " + message : "" );
1660
1661            }
1662
1663            try
1664            {
1665                d.getJavaVariableName();
1666            }
1667            catch ( final ModelObjectException e )
1668            {
1669                final String message = getMessage( e );
1670
1671                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1672                {
1673                    validationContext.getModelContext().log( Level.FINE, message, e );
1674                }
1675
1676                addDetail( validationContext.getReport(),
1677                           "IMPLEMENTATION_DEPENDENCY_JAVA_VARIABLE_NAME_CONSTRAINT",
1678                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1679                           "implementationDependencyJavaVariableNameConstraint",
1680                           impl.getIdentifier(),
1681                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), d.getName(),
1682                           message != null && message.length() > 0 ? " " + message : "" );
1683
1684            }
1685        }
1686
1687        assertDependencyValid( validationContext, impl, d );
1688    }
1689
1690    private static void assertValidImplementationReference( final ValidationContext validationContext,
1691                                                            final Implementation impl,
1692                                                            final ImplementationReference r )
1693    {
1694        final Set<InheritanceModel.Node<ImplementationReference>> effReferences =
1695            validationContext.getInheritanceModel().getImplementationReferenceNodes( impl.getIdentifier(),
1696                                                                                     r.getIdentifier() );
1697
1698        for ( final InheritanceModel.Node<ImplementationReference> effReference : effReferences )
1699        {
1700            final Set<InheritanceModel.Node<ImplementationReference>> overriddenReferences =
1701                modifiableSet( effReference.getOverriddenNodes() );
1702
1703            if ( r.isOverride() && overriddenReferences.isEmpty() )
1704            {
1705                addDetail( validationContext.getReport(),
1706                           "IMPLEMENTATION_IMPLEMENTATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
1707                           new ObjectFactory().createImplementation( impl ),
1708                           "implementationImplementationOverrideConstraint", impl.getIdentifier(),
1709                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
1710                           r.getIdentifier() );
1711
1712            }
1713
1714            if ( !( r.isOverride() || overriddenReferences.isEmpty() ) )
1715            {
1716                for ( final InheritanceModel.Node<ImplementationReference> overriddenReference
1717                          : overriddenReferences )
1718                {
1719                    Implementation overriddenImplementation = overriddenReference.getImplementation();
1720                    if ( overriddenReference.getClassDeclaration() != null )
1721                    {
1722                        overriddenImplementation = overriddenReference.getClassDeclaration();
1723                    }
1724
1725                    final Module moduleOfReference =
1726                        validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
1727
1728                    addDetail( validationContext.getReport(),
1729                               "IMPLEMENTATION_IMPLEMENTATION_REFERENCE_OVERRIDE_WARNING",
1730                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
1731                               "implementationImplementationOverrideWarning", impl.getIdentifier(),
1732                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
1733                               r.getIdentifier(), overriddenImplementation.getIdentifier(), moduleOfReference.getName(),
1734                               getNodePathString( overriddenReference ) );
1735
1736                }
1737            }
1738
1739            retainFinalNodes( overriddenReferences );
1740
1741            for ( final InheritanceModel.Node<ImplementationReference> overriddenReference
1742                      : overriddenReferences )
1743            {
1744                Implementation overriddenImplementation = overriddenReference.getImplementation();
1745                if ( overriddenReference.getClassDeclaration() != null )
1746                {
1747                    overriddenImplementation = overriddenReference.getClassDeclaration();
1748                }
1749
1750                final Module moduleOfReference =
1751                    validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
1752
1753                addDetail( validationContext.getReport(),
1754                           "IMPLEMENTATION_IMPLEMENTATION_REFERENCE_INHERITANCE_CONSTRAINT",
1755                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1756                           "implementationFinalImplementatioReferenceConstraint", impl.getIdentifier(),
1757                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
1758                           r.getIdentifier(), overriddenImplementation.getIdentifier(), moduleOfReference.getName(),
1759                           getNodePathString( overriddenReference ) );
1760
1761            }
1762        }
1763    }
1764
1765    private static void assertValidMessage( final ValidationContext validationContext,
1766                                            final Implementation impl,
1767                                            final Message m )
1768    {
1769        if ( impl.getMessages().getReference( m.getName() ) != null )
1770        {
1771            addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGES_UNIQUENESS_CONSTRAINT",
1772                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1773                       "implementationMessagesUniquenessConstraint", impl.getIdentifier(),
1774                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), m.getName() );
1775
1776        }
1777
1778        if ( validationContext.isValidateJava() )
1779        {
1780            try
1781            {
1782                m.getJavaConstantName();
1783            }
1784            catch ( final ModelObjectException e )
1785            {
1786                final String message = getMessage( e );
1787
1788                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1789                {
1790                    validationContext.getModelContext().log( Level.FINE, message, e );
1791                }
1792
1793                addDetail( validationContext.getReport(),
1794                           "IMPLEMENTATION_MESSAGE_JAVA_CONSTANT_NAME_CONSTRAINT", Level.SEVERE,
1795                           new ObjectFactory().createImplementation( impl ),
1796                           "implementationMessageJavaConstantNameConstraint", impl.getIdentifier(),
1797                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), m.getName(),
1798                           message != null && message.length() > 0 ? " " + message : "" );
1799
1800            }
1801
1802            try
1803            {
1804                m.getJavaGetterMethodName();
1805            }
1806            catch ( final ModelObjectException e )
1807            {
1808                final String message = getMessage( e );
1809
1810                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1811                {
1812                    validationContext.getModelContext().log( Level.FINE, message, e );
1813                }
1814
1815                addDetail( validationContext.getReport(),
1816                           "IMPLEMENTATION_MESSAGE_JAVA_GETTER_METHOD_NAME_CONSTRAINT", Level.SEVERE,
1817                           new ObjectFactory().createImplementation( impl ),
1818                           "implementationMessageJavaGetterMethodNameConstraint", impl.getIdentifier(),
1819                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), m.getName(),
1820                           message != null && message.length() > 0 ? " " + message : "" );
1821
1822            }
1823
1824            try
1825            {
1826                m.getJavaSetterMethodName();
1827            }
1828            catch ( final ModelObjectException e )
1829            {
1830                final String message = getMessage( e );
1831
1832                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1833                {
1834                    validationContext.getModelContext().log( Level.FINE, message, e );
1835                }
1836
1837                addDetail( validationContext.getReport(),
1838                           "IMPLEMENTATION_MESSAGE_JAVA_SETTER_METHOD_NAME_CONSTRAINT", Level.SEVERE,
1839                           new ObjectFactory().createImplementation( impl ),
1840                           "implementationMessageJavaSetterMethodNameConstraint", impl.getIdentifier(),
1841                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), m.getName(),
1842                           message != null && message.length() > 0 ? " " + message : "" );
1843
1844            }
1845
1846            try
1847            {
1848                m.getJavaVariableName();
1849            }
1850            catch ( final ModelObjectException e )
1851            {
1852                final String message = getMessage( e );
1853
1854                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1855                {
1856                    validationContext.getModelContext().log( Level.FINE, message, e );
1857                }
1858
1859                addDetail( validationContext.getReport(),
1860                           "IMPLEMENTATION_MESSAGE_JAVA_VARIABLE_NAME_CONSTRAINT", Level.SEVERE,
1861                           new ObjectFactory().createImplementation( impl ),
1862                           "implementationMessageJavaVariableNameConstraint", impl.getIdentifier(),
1863                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), m.getName(),
1864                           message != null && message.length() > 0 ? " " + message : "" );
1865
1866            }
1867        }
1868
1869        if ( m.getTemplate() != null )
1870        {
1871            for ( int k = 0, s2 = m.getTemplate().getText().size(); k < s2; k++ )
1872            {
1873                final Text t = m.getTemplate().getText().get( k );
1874
1875                try
1876                {
1877                    t.getMimeType();
1878                }
1879                catch ( final ModelObjectException e )
1880                {
1881                    final String message = getMessage( e );
1882
1883                    if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1884                    {
1885                        validationContext.getModelContext().log( Level.FINE, message, e );
1886                    }
1887
1888                    addDetail( validationContext.getReport(),
1889                               "IMPLEMENTATION_MESSAGE_TEMPLATE_MIME_TYPE_CONSTRAINT", Level.SEVERE,
1890                               new ObjectFactory().createImplementation( impl ),
1891                               "implementationMessageTemplateMimeTypeConstraint", impl.getIdentifier(),
1892                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
1893                               m.getName(), t.getLanguage(),
1894                               message != null && message.length() > 0 ? " " + message : "" );
1895
1896                }
1897
1898                if ( validationContext.isValidateJava() )
1899                {
1900                    try
1901                    {
1902                        new MessageFormat( t.getValue(), new Locale( t.getLanguage() ) );
1903                    }
1904                    catch ( final IllegalArgumentException e )
1905                    {
1906                        final String message = getMessage( e );
1907
1908                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1909                        {
1910                            validationContext.getModelContext().log( Level.FINE, message, e );
1911                        }
1912
1913                        addDetail( validationContext.getReport(),
1914                                   "IMPLEMENTATION_MESSAGE_TEMPLATE_CONSTRAINT", Level.SEVERE,
1915                                   new ObjectFactory().createImplementation( impl ),
1916                                   "implementationMessageTemplateConstraint", impl.getIdentifier(),
1917                                   validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
1918                                   m.getName(), t.getLanguage(),
1919                                   message != null && message.length() > 0 ? " " + message : "" );
1920
1921                    }
1922                }
1923            }
1924        }
1925
1926        final Set<InheritanceModel.Node<Message>> effMessages =
1927            validationContext.getInheritanceModel().getMessageNodes( impl.getIdentifier(), m.getName() );
1928
1929        for ( final InheritanceModel.Node<Message> effMessage : effMessages )
1930        {
1931            final Set<InheritanceModel.Node<Message>> overriddenMessages =
1932                modifiableSet( effMessage.getOverriddenNodes() );
1933
1934            if ( m.isOverride() && overriddenMessages.isEmpty() )
1935            {
1936                addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT",
1937                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1938                           "implementationMessageOverrideConstraint", impl.getIdentifier(),
1939                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), m.getName() );
1940
1941            }
1942
1943            if ( !( m.isOverride() || overriddenMessages.isEmpty() ) )
1944            {
1945                for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
1946                {
1947                    Implementation overriddenImplementation = overriddenMessage.getImplementation();
1948                    if ( overriddenMessage.getClassDeclaration() != null )
1949                    {
1950                        overriddenImplementation = overriddenMessage.getClassDeclaration();
1951                    }
1952
1953                    final Module moduleOfMessage =
1954                        validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
1955
1956                    addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_WARNING",
1957                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
1958                               "implementationMessageOverrideWarning", impl.getIdentifier(),
1959                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
1960                               m.getName(), overriddenImplementation.getIdentifier(), moduleOfMessage.getName(),
1961                               getNodePathString( overriddenMessage ) );
1962
1963                }
1964            }
1965
1966            retainFinalNodes( overriddenMessages );
1967
1968            for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
1969            {
1970                Implementation overriddenImplementation = overriddenMessage.getImplementation();
1971                if ( overriddenMessage.getClassDeclaration() != null )
1972                {
1973                    overriddenImplementation = overriddenMessage.getClassDeclaration();
1974                }
1975
1976                final Module moduleOfMessage = validationContext.getModuleOfImplementation(
1977                    overriddenImplementation.getIdentifier() );
1978
1979                addDetail( validationContext.getReport(),
1980                           "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT",
1981                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1982                           "implementationMessageFinalConstraint", impl.getIdentifier(),
1983                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), m.getName(),
1984                           overriddenImplementation.getIdentifier(),
1985                           moduleOfMessage.getName(), getNodePathString( overriddenMessage ) );
1986
1987            }
1988        }
1989
1990        if ( m.getArguments() != null )
1991        {
1992            final Map<JavaIdentifier, Argument> javaVariableNames =
1993                new HashMap<JavaIdentifier, Argument>( m.getArguments().getArgument().size() );
1994
1995            for ( int k = 0, s2 = m.getArguments().getArgument().size(); k < s2; k++ )
1996            {
1997                final Argument a = m.getArguments().getArgument().get( k );
1998
1999                if ( validationContext.isValidateJava() )
2000                {
2001                    try
2002                    {
2003                        a.getJavaTypeName();
2004                    }
2005                    catch ( final ModelObjectException e )
2006                    {
2007                        final String message = getMessage( e );
2008
2009                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2010                        {
2011                            validationContext.getModelContext().log( Level.FINE, message, e );
2012                        }
2013
2014                        addDetail( validationContext.getReport(),
2015                                   "IMPLEMENTATION_MESSAGE_ARGUMENT_JAVA_TYPE_NAME_CONSTRAINT",
2016                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2017                                   "implementationMessageArgumentJavaTypeNameConstraint",
2018                                   impl.getIdentifier(),
2019                                   validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2020                                   m.getName(), a.getName(),
2021                                   message != null && message.length() > 0 ? " " + message : "" );
2022
2023                    }
2024
2025                    try
2026                    {
2027                        final JavaIdentifier javaIdentifier = a.getJavaVariableName();
2028
2029                        if ( javaVariableNames.containsKey( javaIdentifier ) )
2030                        {
2031                            addDetail( validationContext.getReport(),
2032                                       "IMPLEMENTATION_MESSAGE_ARGUMENT_JAVA_VARIABLE_NAME_UNIQUENESS_CONSTRAINT",
2033                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2034                                       "implementationMessageArgumentJavaVariableNameUniquenessConstraint",
2035                                       impl.getIdentifier(),
2036                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2037                                       m.getName(), a.getName(), javaIdentifier,
2038                                       javaVariableNames.get( javaIdentifier ).getName() );
2039
2040                        }
2041                        else
2042                        {
2043                            javaVariableNames.put( javaIdentifier, a );
2044                        }
2045                    }
2046                    catch ( final ModelObjectException e )
2047                    {
2048                        final String message = getMessage( e );
2049
2050                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2051                        {
2052                            validationContext.getModelContext().log( Level.FINE, message, e );
2053                        }
2054
2055                        addDetail( validationContext.getReport(),
2056                                   "IMPLEMENTATION_MESSAGE_ARGUMENT_JAVA_VARIABLE_NAME_CONSTRAINT",
2057                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2058                                   "implementationMessageArgumentJavaVariableNameConstraint",
2059                                   impl.getIdentifier(),
2060                                   validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2061                                   m.getName(), a.getIndex(),
2062                                   message != null && message.length() > 0 ? " " + message : "" );
2063
2064                    }
2065                }
2066            }
2067        }
2068    }
2069
2070    private static void assertValidMessageReference( final ValidationContext validationContext,
2071                                                     final Implementation impl,
2072                                                     final MessageReference r )
2073    {
2074        final Set<InheritanceModel.Node<Message>> effMessages =
2075            validationContext.getInheritanceModel().getMessageNodes( impl.getIdentifier(), r.getName() );
2076
2077        for ( final InheritanceModel.Node<Message> effMessage : effMessages )
2078        {
2079            final Set<InheritanceModel.Node<Message>> overriddenMessages =
2080                modifiableSet( effMessage.getOverriddenNodes() );
2081
2082            if ( r.isOverride() && overriddenMessages.isEmpty() )
2083            {
2084                addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT",
2085                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2086                           "implementationMessageOverrideConstraint", impl.getIdentifier(),
2087                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), r.getName() );
2088
2089            }
2090
2091            if ( !( r.isOverride() || overriddenMessages.isEmpty() ) )
2092            {
2093                for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
2094                {
2095                    Implementation overriddenImplementation = overriddenMessage.getImplementation();
2096                    if ( overriddenMessage.getClassDeclaration() != null )
2097                    {
2098                        overriddenImplementation = overriddenMessage.getClassDeclaration();
2099                    }
2100
2101                    final Module moduleOfMessage =
2102                        validationContext.getModuleOfImplementation(
2103                            overriddenImplementation.getIdentifier() );
2104
2105                    addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_WARNING",
2106                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
2107                               "implementationMessageOverrideWarning", impl.getIdentifier(),
2108                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2109                               r.getName(), overriddenImplementation.getIdentifier(),
2110                               moduleOfMessage.getName(), getNodePathString( overriddenMessage ) );
2111
2112                }
2113            }
2114
2115            retainFinalNodes( overriddenMessages );
2116
2117            for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
2118            {
2119                Implementation overriddenImplementation = overriddenMessage.getImplementation();
2120                if ( overriddenMessage.getClassDeclaration() != null )
2121                {
2122                    overriddenImplementation = overriddenMessage.getClassDeclaration();
2123                }
2124
2125                final Module moduleOfMessage =
2126                    validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
2127
2128                addDetail( validationContext.getReport(),
2129                           "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT",
2130                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2131                           "implementationMessageFinalConstraint", impl.getIdentifier(),
2132                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), r.getName(),
2133                           overriddenImplementation.getIdentifier(),
2134                           moduleOfMessage.getName(), getNodePathString( overriddenMessage ) );
2135
2136            }
2137        }
2138    }
2139
2140    private static void assertValidProperty( final ValidationContext validationContext,
2141                                             final Implementation impl,
2142                                             final Property p )
2143    {
2144        if ( impl.getProperties().getReference( p.getName() ) != null )
2145        {
2146            addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTIES_UNIQUENESS_CONSTRAINT",
2147                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2148                       "implementationPropertiesUniquenessConstraint", impl.getIdentifier(),
2149                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName() );
2150
2151        }
2152
2153        if ( p.getValue() != null && p.getAny() != null )
2154        {
2155            addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_VALUE_CONSTRAINT",
2156                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2157                       "implementationPropertyValueConstraint", impl.getIdentifier(),
2158                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName() );
2159
2160        }
2161
2162        if ( p.getAny() != null && p.getType() == null )
2163        {
2164            addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_TYPE_CONSTRAINT",
2165                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2166                       "implementationPropertyTypeConstraint", impl.getIdentifier(),
2167                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName() );
2168
2169        }
2170
2171        if ( validationContext.isValidateJava() )
2172        {
2173            try
2174            {
2175                p.getJavaConstantName();
2176            }
2177            catch ( final ModelObjectException e )
2178            {
2179                final String message = getMessage( e );
2180
2181                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2182                {
2183                    validationContext.getModelContext().log( Level.FINE, message, e );
2184                }
2185
2186                addDetail( validationContext.getReport(),
2187                           "IMPLEMENTATION_PROPERTY_JAVA_CONSTANT_NAME_CONSTRAINT",
2188                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2189                           "implementationPropertyJavaConstantNameConstraint", impl.getIdentifier(),
2190                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName(),
2191                           message != null && message.length() > 0 ? " " + message : "" );
2192
2193            }
2194
2195            try
2196            {
2197                p.getJavaGetterMethodName();
2198            }
2199            catch ( final ModelObjectException e )
2200            {
2201                final String message = getMessage( e );
2202
2203                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2204                {
2205                    validationContext.getModelContext().log( Level.FINE, message, e );
2206                }
2207
2208                addDetail( validationContext.getReport(),
2209                           "IMPLEMENTATION_PROPERTY_JAVA_GETTER_METHOD_NAME_CONSTRAINT",
2210                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2211                           "implementationPropertyJavaGetterMethodNameConstraint", impl.getIdentifier(),
2212                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName(),
2213                           message != null && message.length() > 0 ? " " + message : "" );
2214
2215            }
2216
2217            try
2218            {
2219                p.getJavaSetterMethodName();
2220            }
2221            catch ( final ModelObjectException e )
2222            {
2223                final String message = getMessage( e );
2224
2225                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2226                {
2227                    validationContext.getModelContext().log( Level.FINE, message, e );
2228                }
2229
2230                addDetail( validationContext.getReport(),
2231                           "IMPLEMENTATION_PROPERTY_JAVA_SETTER_METHOD_NAME_CONSTRAINT",
2232                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2233                           "implementationPropertyJavaSetterMethodNameConstraint", impl.getIdentifier(),
2234                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName(),
2235                           message != null && message.length() > 0 ? " " + message : "" );
2236
2237            }
2238
2239            try
2240            {
2241                p.getJavaTypeName();
2242            }
2243            catch ( final ModelObjectException e )
2244            {
2245                final String message = getMessage( e );
2246
2247                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2248                {
2249                    validationContext.getModelContext().log( Level.FINE, message, e );
2250                }
2251
2252                addDetail( validationContext.getReport(),
2253                           "IMPLEMENTATION_PROPERTY_JAVA_TYPE_NAME_CONSTRAINT",
2254                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2255                           "implementationPropertyJavaTypeNameConstraint", impl.getIdentifier(),
2256                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName(),
2257                           message != null && message.length() > 0 ? " " + message : "" );
2258
2259            }
2260
2261            try
2262            {
2263                p.getJavaVariableName();
2264            }
2265            catch ( final ModelObjectException e )
2266            {
2267                final String message = getMessage( e );
2268
2269                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2270                {
2271                    validationContext.getModelContext().log( Level.FINE, message, e );
2272                }
2273
2274                addDetail( validationContext.getReport(),
2275                           "IMPLEMENTATION_PROPERTY_JAVA_VARIABLE_NAME_CONSTRAINT",
2276                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2277                           "implementationPropertyJavaVariableNameConstraint", impl.getIdentifier(),
2278                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName(),
2279                           message != null && message.length() > 0 ? " " + message : "" );
2280
2281            }
2282
2283            try
2284            {
2285                p.getJavaValue( validationContext.getModelContext().getClassLoader() );
2286            }
2287            catch ( final ModelObjectException e )
2288            {
2289                final String message = getMessage( e );
2290
2291                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2292                {
2293                    validationContext.getModelContext().log( Level.FINE, message, e );
2294                }
2295
2296                addDetail( validationContext.getReport(),
2297                           "IMPLEMENTATION_PROPERTY_JAVA_VALUE_CONSTRAINT",
2298                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2299                           "implementationPropertyJavaValueConstraint", impl.getIdentifier(),
2300                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName(),
2301                           message != null && message.length() > 0 ? " " + message : "" );
2302
2303            }
2304        }
2305
2306        final Set<InheritanceModel.Node<Property>> effProperties =
2307            validationContext.getInheritanceModel().getPropertyNodes( impl.getIdentifier(), p.getName() );
2308
2309        for ( final InheritanceModel.Node<Property> effProperty : effProperties )
2310        {
2311            final Set<InheritanceModel.Node<Property>> overriddenProperties =
2312                modifiableSet( effProperty.getOverriddenNodes() );
2313
2314            if ( p.isOverride() && overriddenProperties.isEmpty() )
2315            {
2316                addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT",
2317                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2318                           "implementationPropertyOverrideConstraint", impl.getIdentifier(),
2319                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName() );
2320
2321            }
2322
2323            if ( !( p.isOverride() || overriddenProperties.isEmpty() ) )
2324            {
2325                for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
2326                {
2327                    if ( overriddenProperty.getSpecification() != null )
2328                    {
2329                        final Module moduleOfProperty =
2330                            validationContext.getModuleOfSpecification(
2331                                overriddenProperty.getSpecification().getIdentifier() );
2332
2333                        addDetail( validationContext.getReport(),
2334                                   "IMPLEMENTATION_PROPERTY_OVERRIDE_WARNING", Level.WARNING,
2335                                   new ObjectFactory().createImplementation( impl ),
2336                                   "implementationSpecificationPropertyOverrideWarning",
2337                                   impl.getIdentifier(),
2338                                   validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2339                                   p.getName(), overriddenProperty.getSpecification().getIdentifier(),
2340                                   moduleOfProperty.getName(),
2341                                   getNodePathString( overriddenProperty ) );
2342
2343                    }
2344                    else
2345                    {
2346                        Implementation overriddenImplementation =
2347                            overriddenProperty.getImplementation();
2348
2349                        if ( overriddenProperty.getClassDeclaration() != null )
2350                        {
2351                            overriddenImplementation = overriddenProperty.getClassDeclaration();
2352                        }
2353
2354                        final Module moduleOfProperty =
2355                            validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
2356
2357                        addDetail( validationContext.getReport(),
2358                                   "IMPLEMENTATION_PROPERTY_OVERRIDE_WARNING", Level.WARNING,
2359                                   new ObjectFactory().createImplementation( impl ),
2360                                   "implementationPropertyOverrideWarning", impl.getIdentifier(),
2361                                   validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2362                                   p.getName(), overriddenImplementation.getIdentifier(), moduleOfProperty.getName(),
2363                                   getNodePathString( overriddenProperty ) );
2364
2365                    }
2366                }
2367            }
2368
2369            retainFinalNodes( overriddenProperties );
2370
2371            for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
2372            {
2373                Implementation overriddenImplementation = overriddenProperty.getImplementation();
2374                if ( overriddenProperty.getClassDeclaration() != null )
2375                {
2376                    overriddenImplementation = overriddenProperty.getClassDeclaration();
2377                }
2378
2379                final Module moduleOfProperty =
2380                    validationContext.getModuleOfImplementation(
2381                        overriddenImplementation.getIdentifier() );
2382
2383                addDetail( validationContext.getReport(),
2384                           "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT",
2385                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2386                           "implementationPropertyFinalConstraint", impl.getIdentifier(),
2387                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), p.getName(),
2388                           overriddenImplementation.getIdentifier(),
2389                           moduleOfProperty.getName(), getNodePathString( overriddenProperty ) );
2390
2391            }
2392        }
2393    }
2394
2395    private static void assertValidPropertyReference( final ValidationContext validationContext,
2396                                                      final Implementation impl,
2397                                                      final PropertyReference r )
2398    {
2399        final Set<InheritanceModel.Node<Property>> effProperties =
2400            validationContext.getInheritanceModel().getPropertyNodes( impl.getIdentifier(), r.getName() );
2401
2402        for ( final InheritanceModel.Node<Property> effProperty : effProperties )
2403        {
2404            final Set<InheritanceModel.Node<Property>> overriddenProperties =
2405                modifiableSet( effProperty.getOverriddenNodes() );
2406
2407            if ( r.isOverride() && overriddenProperties.isEmpty() )
2408            {
2409                addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT",
2410                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2411                           "implementationPropertyOverrideConstraint", impl.getIdentifier(),
2412                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), r.getName() );
2413
2414            }
2415
2416            if ( !( r.isOverride() || overriddenProperties.isEmpty() ) )
2417            {
2418                for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
2419                {
2420                    Implementation overriddenImplementation = overriddenProperty.getImplementation();
2421                    if ( overriddenProperty.getClassDeclaration() != null )
2422                    {
2423                        overriddenImplementation = overriddenProperty.getClassDeclaration();
2424                    }
2425
2426                    final Module moduleOfProperty =
2427                        validationContext.getModuleOfImplementation(
2428                            overriddenImplementation.getIdentifier() );
2429
2430                    addDetail( validationContext.getReport(),
2431                               "IMPLEMENTATION_PROPERTY_OVERRIDE_WARNING", Level.WARNING,
2432                               new ObjectFactory().createImplementation( impl ),
2433                               "implementationPropertyOverrideWarning", impl.getIdentifier(),
2434                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2435                               r.getName(), overriddenImplementation.getIdentifier(),
2436                               moduleOfProperty.getName(), getNodePathString( overriddenProperty ) );
2437
2438                }
2439            }
2440
2441            retainFinalNodes( overriddenProperties );
2442
2443            for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
2444            {
2445                Implementation overriddenImplementation = overriddenProperty.getImplementation();
2446                if ( overriddenProperty.getClassDeclaration() != null )
2447                {
2448                    overriddenImplementation = overriddenProperty.getClassDeclaration();
2449                }
2450
2451                final Module moduleOfProperty =
2452                    validationContext.getModuleOfImplementation(
2453                        overriddenImplementation.getIdentifier() );
2454
2455                addDetail( validationContext.getReport(),
2456                           "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT",
2457                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2458                           "implementationPropertyFinalConstraint", impl.getIdentifier(),
2459                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), r.getName(),
2460                           overriddenImplementation.getIdentifier(),
2461                           moduleOfProperty.getName(), getNodePathString( overriddenProperty ) );
2462
2463            }
2464        }
2465    }
2466
2467    private static void assertValidSpecificationReference( final ValidationContext validationContext,
2468                                                           final Implementation impl,
2469                                                           final SpecificationReference r )
2470    {
2471        final Set<InheritanceModel.Node<SpecificationReference>> effReferences =
2472            validationContext.getInheritanceModel().getSpecificationReferenceNodes( impl.getIdentifier(),
2473                                                                                    r.getIdentifier() );
2474
2475        for ( final InheritanceModel.Node<SpecificationReference> effReference : effReferences )
2476        {
2477            final Set<InheritanceModel.Node<SpecificationReference>> overriddenReferences =
2478                modifiableSet( effReference.getOverriddenNodes() );
2479
2480            if ( r.isOverride() && overriddenReferences.isEmpty() )
2481            {
2482                addDetail( validationContext.getReport(),
2483                           "IMPLEMENTATION_SPECIFICATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
2484                           new ObjectFactory().createImplementation( impl ),
2485                           "implementationSpecificationOverrideConstraint", impl.getIdentifier(),
2486                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2487                           r.getIdentifier() );
2488
2489            }
2490
2491            if ( !( r.isOverride() || overriddenReferences.isEmpty() ) )
2492            {
2493                for ( final InheritanceModel.Node<SpecificationReference> overriddenReference : overriddenReferences )
2494                {
2495                    Implementation overriddenImplementation = overriddenReference.getImplementation();
2496                    if ( overriddenReference.getClassDeclaration() != null )
2497                    {
2498                        overriddenImplementation = overriddenReference.getClassDeclaration();
2499                    }
2500
2501                    final Module moduleOfReference =
2502                        validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
2503
2504                    addDetail( validationContext.getReport(),
2505                               "IMPLEMENTATION_SPECIFICATION_REFERENCE_OVERRIDE_WARNING",
2506                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
2507                               "implementationSpecificationOverrideWarning", impl.getIdentifier(),
2508                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2509                               r.getIdentifier(), overriddenImplementation.getIdentifier(),
2510                               moduleOfReference.getName(), getNodePathString( overriddenReference ) );
2511
2512                }
2513            }
2514
2515            retainFinalNodes( overriddenReferences );
2516
2517            for ( final InheritanceModel.Node<SpecificationReference> overriddenReference
2518                      : overriddenReferences )
2519            {
2520                Implementation overriddenImplementation = overriddenReference.getImplementation();
2521                if ( overriddenReference.getClassDeclaration() != null )
2522                {
2523                    overriddenImplementation = overriddenReference.getClassDeclaration();
2524                }
2525
2526                final Module moduleOfReference =
2527                    validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
2528
2529                addDetail( validationContext.getReport(),
2530                           "IMPLEMENTATION_SPECIFICATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
2531                           new ObjectFactory().createImplementation( impl ),
2532                           "implementationSpecificationFinalConstraint", impl.getIdentifier(),
2533                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2534                           r.getIdentifier(), overriddenImplementation.getIdentifier(),
2535                           moduleOfReference.getName(), getNodePathString( overriddenReference ) );
2536
2537            }
2538        }
2539    }
2540
2541    private static void assertValidAnyObject( final ValidationContext validationContext,
2542                                              final Implementation impl,
2543                                              final Object any )
2544    {
2545
2546        if ( any instanceof JAXBElement<?> )
2547        {
2548            final JAXBElement<?> jaxbElement = (JAXBElement<?>) any;
2549            boolean overrideNode = false;
2550
2551            if ( jaxbElement.getValue() instanceof Inheritable )
2552            {
2553                overrideNode = ( (Inheritable) jaxbElement.getValue() ).isOverride();
2554            }
2555
2556            final Set<InheritanceModel.Node<JAXBElement<?>>> effElements =
2557                validationContext.getInheritanceModel().getJaxbElementNodes( impl.getIdentifier(),
2558                                                                             jaxbElement.getName() );
2559
2560            for ( final InheritanceModel.Node<JAXBElement<?>> effElement : effElements )
2561            {
2562                final Set<InheritanceModel.Node<JAXBElement<?>>> overriddenElements =
2563                    modifiableSet( effElement.getOverriddenNodes() );
2564
2565                if ( overrideNode && overriddenElements.isEmpty() )
2566                {
2567                    addDetail( validationContext.getReport(),
2568                               "IMPLEMENTATION_JAXB_ELEMENT_OVERRIDE_CONSTRAINT",
2569                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2570                               "implementationJaxbElementOverrideConstraint", impl.getIdentifier(),
2571                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2572                               jaxbElement.getName().toString() );
2573
2574                }
2575
2576                if ( !( overrideNode || overriddenElements.isEmpty() ) )
2577                {
2578                    for ( final InheritanceModel.Node<JAXBElement<?>> overriddenElement : overriddenElements )
2579                    {
2580                        Implementation overriddenImplementation = overriddenElement.getImplementation();
2581                        if ( overriddenElement.getClassDeclaration() != null )
2582                        {
2583                            overriddenImplementation = overriddenElement.getClassDeclaration();
2584                        }
2585
2586                        final Module moduleOfElement =
2587                            validationContext.getModuleOfImplementation(
2588                                overriddenElement.getImplementation().getIdentifier() );
2589
2590                        addDetail( validationContext.getReport(),
2591                                   "IMPLEMENTATION_JAXB_ELEMENT_OVERRIDE_WARNING",
2592                                   Level.WARNING, new ObjectFactory().createImplementation( impl ),
2593                                   "implementationJaxbElementOverrideWarning", impl.getIdentifier(),
2594                                   validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2595                                   jaxbElement.getName().toString(), overriddenImplementation.getIdentifier(),
2596                                   moduleOfElement.getName(), getNodePathString( overriddenElement ) );
2597
2598                    }
2599                }
2600
2601                retainFinalNodes( overriddenElements );
2602
2603                for ( final InheritanceModel.Node<JAXBElement<?>> overriddenElement : overriddenElements )
2604                {
2605                    Implementation overriddenImplementation = overriddenElement.getImplementation();
2606                    if ( overriddenElement.getClassDeclaration() != null )
2607                    {
2608                        overriddenImplementation = overriddenElement.getClassDeclaration();
2609                    }
2610
2611                    final Module moduleOfElement =
2612                        validationContext.getModuleOfImplementation( overriddenImplementation.getIdentifier() );
2613
2614                    addDetail( validationContext.getReport(),
2615                               "IMPLEMENTATION_JAXB_ELEMENT_INHERITANCE_CONSTRAINT",
2616                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2617                               "implementationJaxbElementFinalConstraint", impl.getIdentifier(),
2618                               validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2619                               jaxbElement.getName().toString(), overriddenImplementation.getIdentifier(),
2620                               moduleOfElement.getName(), getNodePathString( overriddenElement ) );
2621
2622                }
2623            }
2624        }
2625    }
2626
2627    private static void assertUniqueDependencies( final ValidationContext validationContext,
2628                                                  final Implementation impl )
2629    {
2630        final Set<String> dependencyNames =
2631            validationContext.getInheritanceModel().getDependencyNames( impl.getIdentifier() );
2632
2633        final Map<JavaIdentifier, InheritanceModel.Node<Dependency>> dependencyJavaConstantNames =
2634            new HashMap<JavaIdentifier, InheritanceModel.Node<Dependency>>( dependencyNames.size() );
2635
2636        final Map<JavaIdentifier, InheritanceModel.Node<Dependency>> dependencyJavaGetterMethodNames =
2637            new HashMap<JavaIdentifier, InheritanceModel.Node<Dependency>>( dependencyNames.size() );
2638
2639        final Map<JavaIdentifier, InheritanceModel.Node<Dependency>> dependencyJavaSetterMethodNames =
2640            new HashMap<JavaIdentifier, InheritanceModel.Node<Dependency>>( dependencyNames.size() );
2641
2642        final Map<JavaIdentifier, InheritanceModel.Node<Dependency>> dependencyJavaVariableNames =
2643            new HashMap<JavaIdentifier, InheritanceModel.Node<Dependency>>( dependencyNames.size() );
2644
2645        for ( final String dependencyName : dependencyNames )
2646        {
2647            final Set<InheritanceModel.Node<Dependency>> dependencyNodes =
2648                validationContext.getInheritanceModel().getDependencyNodes( impl.getIdentifier(), dependencyName );
2649
2650            if ( dependencyNodes.size() > 1 )
2651            {
2652                addDetail( validationContext.getReport(),
2653                           "IMPLEMENTATION_DEPENDENCY_MULTIPLE_INHERITANCE_CONSTRAINT",
2654                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2655                           "implementationMultipleInheritanceDependencyConstraint", impl.getIdentifier(),
2656                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2657                           dependencyName, getNodeListPathString( dependencyNodes ) );
2658
2659            }
2660
2661            if ( validationContext.isValidateJava() )
2662            {
2663                for ( final InheritanceModel.Node<Dependency> node : dependencyNodes )
2664                {
2665                    try
2666                    {
2667                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaConstantName();
2668                        final InheritanceModel.Node<Dependency> existingNode =
2669                            dependencyJavaConstantNames.get( javaIdentifier );
2670
2671                        if ( existingNode != null )
2672                        {
2673                            addDetail( validationContext.getReport(),
2674                                       "IMPLEMENTATION_DEPENDENCY_JAVA_CONSTANT_NAME_UNIQUENESS_CONSTRAINT",
2675                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2676                                       "implementationDependencyJavaConstantNameUniquenessConstraint",
2677                                       impl.getIdentifier(),
2678                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2679                                       dependencyName, getNodePathString( node ),
2680                                       existingNode.getModelObject().getName(),
2681                                       getNodePathString( existingNode ), javaIdentifier );
2682
2683                        }
2684                        else
2685                        {
2686                            dependencyJavaConstantNames.put( javaIdentifier, node );
2687                        }
2688                    }
2689                    catch ( final ModelObjectException e )
2690                    {
2691                        // Validated elsewhere.
2692                    }
2693
2694                    try
2695                    {
2696                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaGetterMethodName();
2697                        final InheritanceModel.Node<Dependency> existingNode =
2698                            dependencyJavaGetterMethodNames.get( javaIdentifier );
2699
2700                        if ( existingNode != null )
2701                        {
2702                            addDetail( validationContext.getReport(),
2703                                       "IMPLEMENTATION_DEPENDENCY_JAVA_GETTER_METHOD_NAME_UNIQUENESS_CONSTRAINT",
2704                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2705                                       "implementationDependencyJavaGetterMethodNameUniquenessConstraint",
2706                                       impl.getIdentifier(),
2707                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2708                                       dependencyName, getNodePathString( node ),
2709                                       existingNode.getModelObject().getName(),
2710                                       getNodePathString( existingNode ), javaIdentifier );
2711
2712                        }
2713                        else
2714                        {
2715                            dependencyJavaGetterMethodNames.put( javaIdentifier, node );
2716                        }
2717                    }
2718                    catch ( final ModelObjectException e )
2719                    {
2720                        // Validated elsewhere.
2721                    }
2722
2723                    try
2724                    {
2725                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaSetterMethodName();
2726                        final InheritanceModel.Node<Dependency> existingNode =
2727                            dependencyJavaSetterMethodNames.get( javaIdentifier );
2728
2729                        if ( existingNode != null )
2730                        {
2731                            addDetail( validationContext.getReport(),
2732                                       "IMPLEMENTATION_DEPENDENCY_JAVA_SETTER_METHOD_NAME_UNIQUENESS_CONSTRAINT",
2733                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2734                                       "implementationDependencyJavaSetterMethodNameUniquenessConstraint",
2735                                       impl.getIdentifier(),
2736                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2737                                       dependencyName, getNodePathString( node ),
2738                                       existingNode.getModelObject().getName(),
2739                                       getNodePathString( existingNode ), javaIdentifier );
2740
2741                        }
2742                        else
2743                        {
2744                            dependencyJavaSetterMethodNames.put( javaIdentifier, node );
2745                        }
2746                    }
2747                    catch ( final ModelObjectException e )
2748                    {
2749                        // Validated elsewhere.
2750                    }
2751
2752                    try
2753                    {
2754                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaSetterMethodName();
2755                        final InheritanceModel.Node<Dependency> existingNode =
2756                            dependencyJavaVariableNames.get( javaIdentifier );
2757
2758                        if ( existingNode != null )
2759                        {
2760                            addDetail( validationContext.getReport(),
2761                                       "IMPLEMENTATION_DEPENDENCY_JAVA_VARIABLE_NAME_UNIQUENESS_CONSTRAINT",
2762                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2763                                       "implementationDependencyJavaVariableNameUniquenessConstraint",
2764                                       impl.getIdentifier(),
2765                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2766                                       dependencyName,
2767                                       getNodePathString( node ), existingNode.getModelObject().getName(),
2768                                       getNodePathString( existingNode ), javaIdentifier );
2769
2770                        }
2771                        else
2772                        {
2773                            dependencyJavaVariableNames.put( javaIdentifier, node );
2774                        }
2775                    }
2776                    catch ( final ModelObjectException e )
2777                    {
2778                        // Validated elsewhere.
2779                    }
2780                }
2781            }
2782        }
2783    }
2784
2785    private static void assertUniqueMessages( final ValidationContext validationContext,
2786                                              final Implementation impl )
2787    {
2788        final Set<String> messageNames =
2789            validationContext.getInheritanceModel().getMessageNames( impl.getIdentifier() );
2790
2791        final Map<JavaIdentifier, InheritanceModel.Node<Message>> messageJavaConstantNames =
2792            new HashMap<JavaIdentifier, InheritanceModel.Node<Message>>( messageNames.size() );
2793
2794        final Map<JavaIdentifier, InheritanceModel.Node<Message>> messageJavaGetterMethodNames =
2795            new HashMap<JavaIdentifier, InheritanceModel.Node<Message>>( messageNames.size() );
2796
2797        final Map<JavaIdentifier, InheritanceModel.Node<Message>> messageJavaSetterMethodNames =
2798            new HashMap<JavaIdentifier, InheritanceModel.Node<Message>>( messageNames.size() );
2799
2800        final Map<JavaIdentifier, InheritanceModel.Node<Message>> messageJavaVariableNames =
2801            new HashMap<JavaIdentifier, InheritanceModel.Node<Message>>( messageNames.size() );
2802
2803        for ( final String messageName : messageNames )
2804        {
2805            final Set<InheritanceModel.Node<Message>> messageNodes =
2806                validationContext.getInheritanceModel().getMessageNodes( impl.getIdentifier(), messageName );
2807
2808            if ( messageNodes.size() > 1 )
2809            {
2810                addDetail( validationContext.getReport(),
2811                           "IMPLEMENTATION_MESSAGE_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
2812                           new ObjectFactory().createImplementation( impl ),
2813                           "implementationMultipleInheritanceMessageConstraint", impl.getIdentifier(),
2814                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(), messageName,
2815                           getNodeListPathString( messageNodes ) );
2816
2817            }
2818
2819            if ( validationContext.isValidateJava() )
2820            {
2821                for ( final InheritanceModel.Node<Message> node : messageNodes )
2822                {
2823                    try
2824                    {
2825                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaConstantName();
2826                        final InheritanceModel.Node<Message> existingNode =
2827                            messageJavaConstantNames.get( javaIdentifier );
2828
2829                        if ( existingNode != null )
2830                        {
2831                            addDetail( validationContext.getReport(),
2832                                       "IMPLEMENTATION_MESSAGE_JAVA_CONSTANT_NAME_UNIQUENESS_CONSTRAINT",
2833                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2834                                       "implementationMessageJavaConstantNameUniquenessConstraint",
2835                                       impl.getIdentifier(),
2836                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2837                                       messageName, getNodePathString( node ), existingNode.getModelObject().getName(),
2838                                       getNodePathString( existingNode ), javaIdentifier );
2839
2840                        }
2841                        else
2842                        {
2843                            messageJavaConstantNames.put( javaIdentifier, node );
2844                        }
2845                    }
2846                    catch ( final ModelObjectException e )
2847                    {
2848                        // Validated elsewhere.
2849                    }
2850
2851                    try
2852                    {
2853                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaGetterMethodName();
2854                        final InheritanceModel.Node<Message> existingNode =
2855                            messageJavaGetterMethodNames.get( javaIdentifier );
2856
2857                        if ( existingNode != null )
2858                        {
2859                            addDetail( validationContext.getReport(),
2860                                       "IMPLEMENTATION_MESSAGE_JAVA_GETTER_METHOD_NAME_UNIQUENESS_CONSTRAINT",
2861                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2862                                       "implementationMessageJavaGetterMethodNameUniquenessConstraint",
2863                                       impl.getIdentifier(),
2864                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2865                                       messageName, getNodePathString( node ), existingNode.getModelObject().getName(),
2866                                       getNodePathString( existingNode ), javaIdentifier );
2867
2868                        }
2869                        else
2870                        {
2871                            messageJavaGetterMethodNames.put( javaIdentifier, node );
2872                        }
2873                    }
2874                    catch ( final ModelObjectException e )
2875                    {
2876                        // Validated elsewhere.
2877                    }
2878
2879                    try
2880                    {
2881                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaSetterMethodName();
2882                        final InheritanceModel.Node<Message> existingNode =
2883                            messageJavaSetterMethodNames.get( javaIdentifier );
2884
2885                        if ( existingNode != null )
2886                        {
2887                            addDetail( validationContext.getReport(),
2888                                       "IMPLEMENTATION_MESSAGE_JAVA_SETTER_METHOD_NAME_UNIQUENESS_CONSTRAINT",
2889                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2890                                       "implementationMessageJavaSetterMethodNameUniquenessConstraint",
2891                                       impl.getIdentifier(),
2892                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2893                                       messageName, getNodePathString( node ), existingNode.getModelObject().getName(),
2894                                       getNodePathString( existingNode ), javaIdentifier );
2895
2896                        }
2897                        else
2898                        {
2899                            messageJavaSetterMethodNames.put( javaIdentifier, node );
2900                        }
2901                    }
2902                    catch ( final ModelObjectException e )
2903                    {
2904                        // Validated elsewhere.
2905                    }
2906
2907                    try
2908                    {
2909                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaSetterMethodName();
2910                        final InheritanceModel.Node<Message> existingNode =
2911                            messageJavaVariableNames.get( javaIdentifier );
2912
2913                        if ( existingNode != null )
2914                        {
2915                            addDetail( validationContext.getReport(),
2916                                       "IMPLEMENTATION_MESSAGE_JAVA_VARIABLE_NAME_UNIQUENESS_CONSTRAINT",
2917                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2918                                       "implementationMessageJavaVariableNameUniquenessConstraint",
2919                                       impl.getIdentifier(),
2920                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2921                                       messageName, getNodePathString( node ), existingNode.getModelObject().getName(),
2922                                       getNodePathString( existingNode ), javaIdentifier );
2923
2924                        }
2925                        else
2926                        {
2927                            messageJavaVariableNames.put( javaIdentifier, node );
2928                        }
2929                    }
2930                    catch ( final ModelObjectException e )
2931                    {
2932                        // Validated elsewhere.
2933                    }
2934                }
2935            }
2936        }
2937    }
2938
2939    private static void assertUniqueProperties( final ValidationContext validationContext,
2940                                                final Implementation impl )
2941    {
2942        final Set<String> propertyNames =
2943            validationContext.getInheritanceModel().getPropertyNames( impl.getIdentifier() );
2944
2945        final Map<JavaIdentifier, InheritanceModel.Node<Property>> propertyJavaConstantNames =
2946            new HashMap<JavaIdentifier, InheritanceModel.Node<Property>>( propertyNames.size() );
2947
2948        final Map<JavaIdentifier, InheritanceModel.Node<Property>> propertyJavaGetterMethodNames =
2949            new HashMap<JavaIdentifier, InheritanceModel.Node<Property>>( propertyNames.size() );
2950
2951        final Map<JavaIdentifier, InheritanceModel.Node<Property>> propertyJavaSetterMethodNames =
2952            new HashMap<JavaIdentifier, InheritanceModel.Node<Property>>( propertyNames.size() );
2953
2954        final Map<JavaIdentifier, InheritanceModel.Node<Property>> propertyJavaVariableNames =
2955            new HashMap<JavaIdentifier, InheritanceModel.Node<Property>>( propertyNames.size() );
2956
2957        for ( final String propertyName : propertyNames )
2958        {
2959            final Set<InheritanceModel.Node<Property>> propertyNodes =
2960                validationContext.getInheritanceModel().getPropertyNodes( impl.getIdentifier(), propertyName );
2961
2962            if ( propertyNodes.size() > 1 )
2963            {
2964                addDetail( validationContext.getReport(),
2965                           "IMPLEMENTATION_PROPERTY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
2966                           new ObjectFactory().createImplementation( impl ),
2967                           "implementationMultipleInheritancePropertyConstraint", impl.getIdentifier(),
2968                           validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2969                           propertyName, getNodeListPathString( propertyNodes ) );
2970
2971            }
2972
2973            if ( validationContext.isValidateJava() )
2974            {
2975                for ( final InheritanceModel.Node<Property> node : propertyNodes )
2976                {
2977                    try
2978                    {
2979                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaConstantName();
2980                        final InheritanceModel.Node<Property> existingNode =
2981                            propertyJavaConstantNames.get( javaIdentifier );
2982
2983                        if ( existingNode != null )
2984                        {
2985                            addDetail( validationContext.getReport(),
2986                                       "IMPLEMENTATION_PROPERTY_JAVA_CONSTANT_NAME_UNIQUENESS_CONSTRAINT",
2987                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
2988                                       "implementationPropertyJavaConstantNameUniquenessConstraint",
2989                                       impl.getIdentifier(),
2990                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
2991                                       propertyName, getNodePathString( node ), existingNode.getModelObject().getName(),
2992                                       getNodePathString( existingNode ), javaIdentifier );
2993
2994                        }
2995                        else
2996                        {
2997                            propertyJavaConstantNames.put( javaIdentifier, node );
2998                        }
2999                    }
3000                    catch ( final ModelObjectException e )
3001                    {
3002                        // Validated elsewhere.
3003                    }
3004
3005                    try
3006                    {
3007                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaGetterMethodName();
3008                        final InheritanceModel.Node<Property> existingNode =
3009                            propertyJavaGetterMethodNames.get( javaIdentifier );
3010
3011                        if ( existingNode != null )
3012                        {
3013                            addDetail( validationContext.getReport(),
3014                                       "IMPLEMENTATION_PROPERTY_JAVA_GETTER_METHOD_NAME_UNIQUENESS_CONSTRAINT",
3015                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
3016                                       "implementationPropertyJavaGetterMethodNameUniquenessConstraint",
3017                                       impl.getIdentifier(),
3018                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
3019                                       propertyName, getNodePathString( node ), existingNode.getModelObject().getName(),
3020                                       getNodePathString( existingNode ), javaIdentifier );
3021
3022                        }
3023                        else
3024                        {
3025                            propertyJavaGetterMethodNames.put( javaIdentifier, node );
3026                        }
3027                    }
3028                    catch ( final ModelObjectException e )
3029                    {
3030                        // Validated elsewhere.
3031                    }
3032
3033                    try
3034                    {
3035                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaSetterMethodName();
3036                        final InheritanceModel.Node<Property> existingNode =
3037                            propertyJavaSetterMethodNames.get( javaIdentifier );
3038
3039                        if ( existingNode != null )
3040                        {
3041                            addDetail( validationContext.getReport(),
3042                                       "IMPLEMENTATION_PROPERTY_JAVA_SETTER_METHOD_NAME_UNIQUENESS_CONSTRAINT",
3043                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
3044                                       "implementationPropertyJavaSetterMethodNameUniquenessConstraint",
3045                                       impl.getIdentifier(),
3046                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
3047                                       propertyName, getNodePathString( node ), existingNode.getModelObject().getName(),
3048                                       getNodePathString( existingNode ), javaIdentifier );
3049
3050                        }
3051                        else
3052                        {
3053                            propertyJavaSetterMethodNames.put( javaIdentifier, node );
3054                        }
3055                    }
3056                    catch ( final ModelObjectException e )
3057                    {
3058                        // Validated elsewhere.
3059                    }
3060
3061                    try
3062                    {
3063                        final JavaIdentifier javaIdentifier = node.getModelObject().getJavaSetterMethodName();
3064                        final InheritanceModel.Node<Property> existingNode =
3065                            propertyJavaVariableNames.get( javaIdentifier );
3066
3067                        if ( existingNode != null )
3068                        {
3069                            addDetail( validationContext.getReport(),
3070                                       "IMPLEMENTATION_PROPERTY_JAVA_VARIABLE_NAME_UNIQUENESS_CONSTRAINT",
3071                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
3072                                       "implementationPropertyJavaVariableNameUniquenessConstraint",
3073                                       impl.getIdentifier(),
3074                                       validationContext.getModuleOfImplementation( impl.getIdentifier() ).getName(),
3075                                       propertyName, getNodePathString( node ), existingNode.getModelObject().getName(),
3076                                       getNodePathString( existingNode ), javaIdentifier );
3077
3078                        }
3079                        else
3080                        {
3081                            propertyJavaVariableNames.put( javaIdentifier, node );
3082                        }
3083                    }
3084                    catch ( final ModelObjectException e )
3085                    {
3086                        // Validated elsewhere.
3087                    }
3088                }
3089            }
3090        }
3091    }
3092
3093    private static void assertSpecificationsValid( final ValidationContext validationContext )
3094    {
3095        final Specifications specifications = validationContext.getAllSpecifications();
3096        final Map<String, Specification> specificationClassDeclarations = new HashMap<String, Specification>();
3097        final Map<String, Specification> specificationJavaClassDeclarations =
3098            new HashMap<String, Specification>();
3099
3100        if ( specifications != null )
3101        {
3102            for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
3103            {
3104                final Specification s = specifications.getSpecification().get( i );
3105                final Implementations impls = validationContext.getImplementations( s.getIdentifier() );
3106                final Module moduleOfS = validationContext.getModuleOfSpecification( s.getIdentifier() );
3107
3108                if ( validationContext.isValidateJava() )
3109                {
3110                    try
3111                    {
3112                        s.getJavaTypeName();
3113                    }
3114                    catch ( final ModelObjectException e )
3115                    {
3116                        final String message = getMessage( e );
3117
3118                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3119                        {
3120                            validationContext.getModelContext().log( Level.FINE, message, e );
3121                        }
3122
3123                        addDetail( validationContext.getReport(),
3124                                   "SPECIFICATION_JAVA_TYPE_NAME_CONSTRAINT",
3125                                   Level.SEVERE, new ObjectFactory().createSpecification( s ),
3126                                   "specificationJavaTypeNameConstraint", s.getIdentifier(),
3127                                   moduleOfS.getName(), s.getClazz(),
3128                                   message != null && message.length() > 0 ? " " + message : "" );
3129
3130                    }
3131                }
3132
3133                if ( s.isClassDeclaration() )
3134                {
3135                    if ( s.getClazz() == null )
3136                    {
3137                        addDetail( validationContext.getReport(), "SPECIFICATION_CLASS_CONSTRAINT", Level.SEVERE,
3138                                   new ObjectFactory().createSpecification( s ), "specificationClassConstraint",
3139                                   s.getIdentifier(), moduleOfS.getName() );
3140
3141                    }
3142                    else
3143                    {
3144                        final Specification prev = specificationClassDeclarations.get( s.getClazz() );
3145
3146                        if ( prev != null && !prev.getIdentifier().equals( s.getIdentifier() ) )
3147                        {
3148                            final Module moduleOfPrev =
3149                                validationContext.getModuleOfSpecification( prev.getIdentifier() );
3150
3151                            addDetail( validationContext.getReport(), "SPECIFICATION_CLASS_DECLARATION_CONSTRAINT",
3152                                       Level.SEVERE, new ObjectFactory().createSpecification( s ),
3153                                       "specificationClassDeclarationConstraint", s.getIdentifier(),
3154                                       moduleOfS.getName(), s.getClazz(), prev.getIdentifier(),
3155                                       moduleOfPrev.getName() );
3156
3157                        }
3158                        else
3159                        {
3160                            specificationClassDeclarations.put( s.getClazz(), s );
3161                        }
3162
3163                        if ( validationContext.isValidateJava() )
3164                        {
3165                            try
3166                            {
3167                                final Specification java =
3168                                    specificationJavaClassDeclarations.get( s.getJavaTypeName().getClassName() );
3169
3170                                if ( java != null && !java.getIdentifier().equals( s.getIdentifier() ) )
3171                                {
3172                                    final Module moduleOfJava =
3173                                        validationContext.getModuleOfSpecification( java.getIdentifier() );
3174
3175                                    addDetail( validationContext.getReport(),
3176                                               "SPECIFICATION_JAVA_CLASS_DECLARATION_CONSTRAINT",
3177                                               Level.SEVERE, new ObjectFactory().createSpecification( s ),
3178                                               "specificationJavaClassDeclarationConstraint", s.getIdentifier(),
3179                                               moduleOfS.getName(), s.getJavaTypeName().getClassName(),
3180                                               java.getIdentifier(), moduleOfJava.getName() );
3181
3182                                }
3183                                else
3184                                {
3185                                    specificationJavaClassDeclarations.put( s.getJavaTypeName().getClassName(), s );
3186                                }
3187                            }
3188                            catch ( final ModelObjectException e )
3189                            {
3190                                // Already validated above.
3191                            }
3192                        }
3193                    }
3194                }
3195
3196                if ( impls != null )
3197                {
3198                    final Map<String, Implementations> map = new HashMap<String, Implementations>();
3199
3200                    for ( int j = 0, s1 = impls.getImplementation().size(); j < s1; j++ )
3201                    {
3202                        final Implementation impl = impls.getImplementation().get( j );
3203                        Implementations implementations = map.get( impl.getName() );
3204
3205                        if ( implementations == null )
3206                        {
3207                            implementations = new Implementations();
3208                            map.put( impl.getName(), implementations );
3209                        }
3210
3211                        implementations.getImplementation().add( impl );
3212                    }
3213
3214                    for ( final Map.Entry<String, Implementations> e : map.entrySet() )
3215                    {
3216                        if ( e.getValue().getImplementation().size() > 1 )
3217                        {
3218                            for ( int j = 0, s1 = e.getValue().getImplementation().size(); j < s1; j++ )
3219                            {
3220                                final Implementation impl = e.getValue().getImplementation().get( j );
3221                                final Module moduleOfImpl =
3222                                    validationContext.getModuleOfImplementation( impl.getIdentifier() );
3223
3224                                addDetail( validationContext.getReport(),
3225                                           "SPECIFICATION_IMPLEMENTATION_NAME_UNIQUENESS_CONSTRAINT",
3226                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
3227                                           "specificationImplementationNameConstraint", impl.getIdentifier(),
3228                                           moduleOfImpl.getName(), s.getIdentifier(), moduleOfS.getName(),
3229                                           impl.getName() );
3230
3231                            }
3232                        }
3233                    }
3234
3235                    if ( s.getMultiplicity() == Multiplicity.ONE && impls.getImplementation().size() > 1 )
3236                    {
3237                        for ( int j = 0, s1 = impls.getImplementation().size(); j < s1; j++ )
3238                        {
3239                            final Implementation impl = impls.getImplementation().get( j );
3240                            final Module moduleOfImpl =
3241                                validationContext.getModuleOfImplementation( impl.getIdentifier() );
3242
3243                            addDetail( validationContext.getReport(),
3244                                       "SPECIFICATION_IMPLEMENTATION_MULTIPLICITY_CONSTRAINT", Level.SEVERE,
3245                                       new ObjectFactory().createImplementation( impl ),
3246                                       "specificationMultiplicityConstraint", impl.getIdentifier(),
3247                                       moduleOfImpl.getName(), s.getIdentifier(), moduleOfS.getName(),
3248                                       s.getMultiplicity() );
3249
3250                        }
3251                    }
3252                }
3253
3254                if ( s.getProperties() != null )
3255                {
3256                    for ( int j = 0, s1 = s.getProperties().getProperty().size(); j < s1; j++ )
3257                    {
3258                        final Property p = s.getProperties().getProperty().get( j );
3259
3260                        if ( p.getValue() != null && p.getAny() != null )
3261                        {
3262                            addDetail( validationContext.getReport(), "SPECIFICATION_PROPERTY_VALUE_CONSTRAINT",
3263                                       Level.SEVERE, new ObjectFactory().createSpecification( s ),
3264                                       "specificationPropertyValueConstraint", s.getIdentifier(),
3265                                       moduleOfS.getName(), p.getName() );
3266
3267                        }
3268
3269                        if ( p.getAny() != null && p.getType() == null )
3270                        {
3271                            addDetail( validationContext.getReport(), "SPECIFICATION_PROPERTY_TYPE_CONSTRAINT",
3272                                       Level.SEVERE, new ObjectFactory().createSpecification( s ),
3273                                       "specificationPropertyTypeConstraint", s.getIdentifier(),
3274                                       moduleOfS.getName(), p.getName() );
3275
3276                        }
3277
3278                        if ( validationContext.isValidateJava() )
3279                        {
3280                            try
3281                            {
3282                                p.getJavaConstantName();
3283                            }
3284                            catch ( final ModelObjectException e )
3285                            {
3286                                final String message = getMessage( e );
3287
3288                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3289                                {
3290                                    validationContext.getModelContext().log( Level.FINE, message, e );
3291                                }
3292
3293                                addDetail( validationContext.getReport(),
3294                                           "SPECIFICATION_PROPERTY_JAVA_CONSTANT_NAME_CONSTRAINT",
3295                                           Level.SEVERE, new ObjectFactory().createSpecification( s ),
3296                                           "specificationPropertyJavaConstantNameConstraint", s.getIdentifier(),
3297                                           moduleOfS.getName(), p.getName(),
3298                                           message != null && message.length() > 0 ? " " + message : "" );
3299
3300                            }
3301
3302                            try
3303                            {
3304                                p.getJavaGetterMethodName();
3305                            }
3306                            catch ( final ModelObjectException e )
3307                            {
3308                                final String message = getMessage( e );
3309
3310                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3311                                {
3312                                    validationContext.getModelContext().log( Level.FINE, message, e );
3313                                }
3314
3315                                addDetail( validationContext.getReport(),
3316                                           "SPECIFICATION_PROPERTY_JAVA_GETTER_METHOD_NAME_CONSTRAINT",
3317                                           Level.SEVERE, new ObjectFactory().createSpecification( s ),
3318                                           "specificationPropertyJavaGetterMethodNameConstraint", s.getIdentifier(),
3319                                           moduleOfS.getName(), p.getName(),
3320                                           message != null && message.length() > 0 ? " " + message : "" );
3321
3322                            }
3323
3324                            try
3325                            {
3326                                p.getJavaSetterMethodName();
3327                            }
3328                            catch ( final ModelObjectException e )
3329                            {
3330                                final String message = getMessage( e );
3331
3332                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3333                                {
3334                                    validationContext.getModelContext().log( Level.FINE, message, e );
3335                                }
3336
3337                                addDetail( validationContext.getReport(),
3338                                           "SPECIFICATION_PROPERTY_JAVA_SETTER_METHOD_NAME_CONSTRAINT",
3339                                           Level.SEVERE, new ObjectFactory().createSpecification( s ),
3340                                           "specificationPropertyJavaSetterMethodNameConstraint", s.getIdentifier(),
3341                                           moduleOfS.getName(), p.getName(),
3342                                           message != null && message.length() > 0 ? " " + message : "" );
3343
3344                            }
3345
3346                            try
3347                            {
3348                                p.getJavaTypeName();
3349                            }
3350                            catch ( final ModelObjectException e )
3351                            {
3352                                final String message = getMessage( e );
3353
3354                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3355                                {
3356                                    validationContext.getModelContext().log( Level.FINE, message, e );
3357                                }
3358
3359                                addDetail( validationContext.getReport(),
3360                                           "SPECIFICATION_PROPERTY_JAVA_TYPE_NAME_CONSTRAINT",
3361                                           Level.SEVERE, new ObjectFactory().createSpecification( s ),
3362                                           "specificationPropertyJavaTypeNameConstraint", s.getIdentifier(),
3363                                           moduleOfS.getName(), p.getName(),
3364                                           message != null && message.length() > 0 ? " " + message : "" );
3365
3366                            }
3367
3368                            try
3369                            {
3370                                p.getJavaVariableName();
3371                            }
3372                            catch ( final ModelObjectException e )
3373                            {
3374                                final String message = getMessage( e );
3375
3376                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3377                                {
3378                                    validationContext.getModelContext().log( Level.FINE, message, e );
3379                                }
3380
3381                                addDetail( validationContext.getReport(),
3382                                           "SPECIFICATION_PROPERTY_JAVA_VARIABLE_NAME_CONSTRAINT",
3383                                           Level.SEVERE, new ObjectFactory().createSpecification( s ),
3384                                           "specificationPropertyJavaVariableNameConstraint", s.getIdentifier(),
3385                                           moduleOfS.getName(), p.getName(),
3386                                           message != null && message.length() > 0 ? " " + message : "" );
3387
3388                            }
3389
3390                            try
3391                            {
3392                                p.getJavaValue( validationContext.getModelContext().getClassLoader() );
3393                            }
3394                            catch ( final ModelObjectException e )
3395                            {
3396                                final String message = getMessage( e );
3397
3398                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3399                                {
3400                                    validationContext.getModelContext().log( Level.FINE, message, e );
3401                                }
3402
3403                                addDetail( validationContext.getReport(),
3404                                           "SPECIFICATION_PROPERTY_JAVA_VALUE_CONSTRAINT",
3405                                           Level.SEVERE, new ObjectFactory().createSpecification( s ),
3406                                           "specificationPropertyJavaValueConstraint", s.getIdentifier(),
3407                                           moduleOfS.getName(), p.getName(),
3408                                           message != null && message.length() > 0 ? " " + message : "" );
3409
3410                            }
3411                        }
3412                    }
3413
3414                    for ( int j = 0, s1 = s.getProperties().getReference().size(); j < s1; j++ )
3415                    {
3416                        final PropertyReference r = s.getProperties().getReference().get( j );
3417
3418                        addDetail( validationContext.getReport(),
3419                                   "SPECIFICATION_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3420                                   new ObjectFactory().createSpecification( s ),
3421                                   "specificationPropertyReferenceDeclarationConstraint", s.getIdentifier(),
3422                                   moduleOfS.getName(), r.getName() );
3423
3424                    }
3425                }
3426            }
3427        }
3428    }
3429
3430    private static void assertDependencyValid( final ValidationContext validationContext,
3431                                               final Implementation implementation, final Dependency dependency )
3432    {
3433        final Specification s = validationContext.getSpecification( dependency.getIdentifier() );
3434        final Implementations available = validationContext.getImplementations( dependency.getIdentifier() );
3435        final Module moduleOfImpl =
3436            validationContext.getModuleOfImplementation( implementation.getIdentifier() );
3437
3438        if ( !dependency.isOptional()
3439                 && ( available == null || available.getImplementation().isEmpty()
3440                      || ( dependency.getImplementationName() != null
3441                           && available.getImplementationByName( dependency.getImplementationName() ) == null ) ) )
3442        {
3443            addDetail( validationContext.getReport(), "IMPLEMENTATION_MANDATORY_DEPENDENCY_CONSTRAINT", Level.SEVERE,
3444                       new ObjectFactory().createImplementation( implementation ),
3445                       "implementationMandatoryDependencyConstraint", implementation.getIdentifier(),
3446                       moduleOfImpl.getName(), dependency.getName() );
3447
3448        }
3449
3450        if ( s != null )
3451        {
3452            final Module moduleOfS = validationContext.getModuleOfSpecification( s.getIdentifier() );
3453
3454            if ( s.getClazz() == null )
3455            {
3456                addDetail( validationContext.getReport(), "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_CLASS_CONSTRAINT",
3457                           Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3458                           "implementationDependencySpecificationClassConstraint", implementation.getIdentifier(),
3459                           moduleOfImpl.getName(), dependency.getName(), dependency.getIdentifier(),
3460                           moduleOfS.getName() );
3461
3462            }
3463
3464            if ( dependency.getVersion() != null )
3465            {
3466                if ( s.getVersion() == null )
3467                {
3468                    addDetail( validationContext.getReport(),
3469                               "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
3470                               new ObjectFactory().createImplementation( implementation ),
3471                               "implementationDependencySpecificationVersioningConstraint",
3472                               implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3473                               s.getIdentifier(), moduleOfS.getName() );
3474
3475                }
3476                else
3477                {
3478                    try
3479                    {
3480                        if ( VersionParser.compare( dependency.getVersion(), s.getVersion() ) > 0 )
3481                        {
3482                            addDetail( validationContext.getReport(),
3483                                       "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_CONSTRAINT",
3484                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3485                                       "implementationDependencySpecificationCompatibilityConstraint",
3486                                       implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
3487                                       moduleOfS.getName(), dependency.getVersion(), s.getVersion() );
3488
3489                        }
3490                    }
3491                    catch ( final ParseException e )
3492                    {
3493                        final String message = getMessage( e );
3494
3495                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3496                        {
3497                            validationContext.getModelContext().log( Level.FINE, message, e );
3498                        }
3499
3500                        addDetail( validationContext.getReport(),
3501                                   "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_VERSIONING_PARSE_EXCEPTION",
3502                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3503                                   "implementationDependencySpecificationCompatibilityParseException",
3504                                   implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
3505                                   moduleOfS.getName(), dependency.getVersion(),
3506                                   message != null && message.length() > 0 ? " " + message : "" );
3507
3508                    }
3509                    catch ( final TokenMgrError e )
3510                    {
3511                        final String message = getMessage( e );
3512
3513                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3514                        {
3515                            validationContext.getModelContext().log( Level.FINE, message, e );
3516                        }
3517
3518                        addDetail( validationContext.getReport(),
3519                                   "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_VERSIONING_TOKEN_MANAGER_ERROR",
3520                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3521                                   "implementationDependencySpecificationCompatibilityTokenMgrError",
3522                                   implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
3523                                   moduleOfS.getName(), dependency.getVersion(),
3524                                   message != null && message.length() > 0 ? " " + message : "" );
3525
3526                    }
3527                }
3528            }
3529
3530            if ( s.getScope() != null )
3531            {
3532                if ( dependency.getDependencies() != null )
3533                {
3534                    for ( int i = 0, s0 = dependency.getDependencies().getDependency().size(); i < s0; i++ )
3535                    {
3536                        final Dependency d = dependency.getDependencies().getDependency().get( i );
3537
3538                        addDetail( validationContext.getReport(),
3539                                   "IMPLEMENTATION_DEPENDENCY_DEPENDENCIES_OVERRIDE_CONSTRAINT", Level.SEVERE,
3540                                   new ObjectFactory().createImplementation( implementation ),
3541                                   "implementationDependencyDependenciesOverrideConstraint",
3542                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3543                                   d.getName(), s.getIdentifier(), moduleOfS.getName(), s.getScope() );
3544
3545                    }
3546                }
3547
3548                if ( dependency.getMessages() != null )
3549                {
3550                    for ( int i = 0, s0 = dependency.getMessages().getMessage().size(); i < s0; i++ )
3551                    {
3552                        final Message m = dependency.getMessages().getMessage().get( i );
3553
3554                        addDetail( validationContext.getReport(),
3555                                   "IMPLEMENTATION_DEPENDENCY_MESSAGES_OVERRIDE_CONSTRAINT", Level.SEVERE,
3556                                   new ObjectFactory().createImplementation( implementation ),
3557                                   "implementationDependencyMessagesOverrideConstraint", implementation.getIdentifier(),
3558                                   moduleOfImpl.getName(), dependency.getName(), m.getName(), s.getIdentifier(),
3559                                   moduleOfS.getName(), s.getScope() );
3560
3561                    }
3562                }
3563
3564                if ( dependency.getProperties() != null )
3565                {
3566                    for ( int i = 0, s0 = dependency.getProperties().getProperty().size(); i < s0; i++ )
3567                    {
3568                        final Property p = dependency.getProperties().getProperty().get( i );
3569                        addDetail( validationContext.getReport(),
3570                                   "IMPLEMENTATION_DEPENDENCY_PROPERTIES_OVERRIDE_CONSTRAINT", Level.SEVERE,
3571                                   new ObjectFactory().createImplementation( implementation ),
3572                                   "implementationDependencyPropertiesOverrideConstraint",
3573                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3574                                   p.getName(), s.getIdentifier(), moduleOfS.getName(), s.getScope() );
3575
3576                    }
3577                }
3578            }
3579        }
3580
3581        if ( dependency.getMessages() != null )
3582        {
3583            for ( int i = 0, s0 = dependency.getMessages().getMessage().size(); i < s0; i++ )
3584            {
3585                final Message m = dependency.getMessages().getMessage().get( i );
3586
3587                if ( validationContext.isValidateJava() )
3588                {
3589                    try
3590                    {
3591                        m.getJavaConstantName();
3592                    }
3593                    catch ( final ModelObjectException e )
3594                    {
3595                        final String message = getMessage( e );
3596
3597                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3598                        {
3599                            validationContext.getModelContext().log( Level.FINE, message, e );
3600                        }
3601
3602                        addDetail( validationContext.getReport(),
3603                                   "IMPLEMENTATION_DEPENDENCY_MESSAGE_JAVA_CONSTANT_NAME_CONSTRAINT", Level.SEVERE,
3604                                   new ObjectFactory().createImplementation( implementation ),
3605                                   "implementationDependencyMessageJavaConstantNameConstraint",
3606                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3607                                   m.getName(), message != null && message.length() > 0 ? " " + message : "" );
3608                    }
3609
3610                    try
3611                    {
3612                        m.getJavaGetterMethodName();
3613                    }
3614                    catch ( final ModelObjectException e )
3615                    {
3616                        final String message = getMessage( e );
3617
3618                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3619                        {
3620                            validationContext.getModelContext().log( Level.FINE, message, e );
3621                        }
3622
3623                        addDetail( validationContext.getReport(),
3624                                   "IMPLEMENTATION_DEPENDENCY_MESSAGE_JAVA_GETTER_METHOD_NAME_CONSTRAINT", Level.SEVERE,
3625                                   new ObjectFactory().createImplementation( implementation ),
3626                                   "implementationDependencyMessageJavaGetterMethodNameConstraint",
3627                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3628                                   m.getName(), message != null && message.length() > 0 ? " " + message : "" );
3629                    }
3630
3631                    try
3632                    {
3633                        m.getJavaSetterMethodName();
3634                    }
3635                    catch ( final ModelObjectException e )
3636                    {
3637                        final String message = getMessage( e );
3638
3639                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3640                        {
3641                            validationContext.getModelContext().log( Level.FINE, message, e );
3642                        }
3643
3644                        addDetail( validationContext.getReport(),
3645                                   "IMPLEMENTATION_DEPENDENCY_MESSAGE_JAVA_SETTER_METHOD_NAME_CONSTRAINT", Level.SEVERE,
3646                                   new ObjectFactory().createImplementation( implementation ),
3647                                   "implementationDependencyMessageJavaSetterMethodNameConstraint",
3648                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3649                                   m.getName(), message != null && message.length() > 0 ? " " + message : "" );
3650                    }
3651
3652                    try
3653                    {
3654                        m.getJavaVariableName();
3655                    }
3656                    catch ( final ModelObjectException e )
3657                    {
3658                        final String message = getMessage( e );
3659
3660                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3661                        {
3662                            validationContext.getModelContext().log( Level.FINE, message, e );
3663                        }
3664
3665                        addDetail( validationContext.getReport(),
3666                                   "IMPLEMENTATION_DEPENDENCY_MESSAGE_JAVA_VARIABLE_NAME_CONSTRAINT", Level.SEVERE,
3667                                   new ObjectFactory().createImplementation( implementation ),
3668                                   "implementationDependencyMessageJavaVariableNameConstraint",
3669                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3670                                   m.getName(), message != null && message.length() > 0 ? " " + message : "" );
3671                    }
3672                }
3673
3674                if ( m.getTemplate() != null )
3675                {
3676                    for ( int j = 0, s1 = m.getTemplate().getText().size(); j < s1; j++ )
3677                    {
3678                        final Text t = m.getTemplate().getText().get( j );
3679
3680                        try
3681                        {
3682                            t.getMimeType();
3683                        }
3684                        catch ( final ModelObjectException e )
3685                        {
3686                            final String message = getMessage( e );
3687
3688                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3689                            {
3690                                validationContext.getModelContext().log( Level.FINE, message, e );
3691                            }
3692
3693                            addDetail( validationContext.getReport(),
3694                                       "IMPLEMENTATION_DEPENDENCY_MESSAGE_TEMPLATE_MIME_TYPE_CONSTRAINT", Level.SEVERE,
3695                                       new ObjectFactory().createImplementation( implementation ),
3696                                       "implementationDependencyMessageTemplateMimeTypeConstraint",
3697                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3698                                       m.getName(), t.getLanguage(),
3699                                       message != null && message.length() > 0 ? " " + message : "" );
3700
3701                        }
3702
3703                        if ( validationContext.isValidateJava() )
3704                        {
3705                            try
3706                            {
3707                                new MessageFormat( t.getValue(), new Locale( t.getLanguage() ) );
3708                            }
3709                            catch ( final IllegalArgumentException e )
3710                            {
3711                                final String message = getMessage( e );
3712
3713                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3714                                {
3715                                    validationContext.getModelContext().log( Level.FINE, message, e );
3716                                }
3717
3718                                addDetail( validationContext.getReport(),
3719                                           "IMPLEMENTATION_DEPENDENCY_MESSAGE_TEMPLATE_CONSTRAINT", Level.SEVERE,
3720                                           new ObjectFactory().createImplementation( implementation ),
3721                                           "implementationDependencyMessageTemplateConstraint",
3722                                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3723                                           m.getName(), t.getLanguage(),
3724                                           message != null && message.length() > 0 ? " " + message : "" );
3725
3726                            }
3727                        }
3728                    }
3729                }
3730
3731                if ( m.getArguments() != null )
3732                {
3733                    final Map<JavaIdentifier, Argument> javaVariableNames =
3734                        new HashMap<JavaIdentifier, Argument>( m.getArguments().getArgument().size() );
3735
3736                    for ( int j = 0, s1 = m.getArguments().getArgument().size(); j < s1; j++ )
3737                    {
3738                        final Argument a = m.getArguments().getArgument().get( j );
3739
3740                        if ( validationContext.isValidateJava() )
3741                        {
3742                            try
3743                            {
3744                                a.getJavaTypeName();
3745                            }
3746                            catch ( final ModelObjectException e )
3747                            {
3748                                final String message = getMessage( e );
3749
3750                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3751                                {
3752                                    validationContext.getModelContext().log( Level.FINE, message, e );
3753                                }
3754
3755                                addDetail( validationContext.getReport(),
3756                                           "IMPLEMENTATION_DEPENDENCY_MESSAGE_ARGUMENT_JAVA_TYPE_NAME_CONSTRAINT",
3757                                           Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3758                                           "implementationDependencyMessageArgumentJavaTypeNameConstraint",
3759                                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3760                                           m.getName(), a.getName(),
3761                                           message != null && message.length() > 0 ? " " + message : "" );
3762
3763                            }
3764
3765                            try
3766                            {
3767                                final JavaIdentifier javaIdentifier = a.getJavaVariableName();
3768
3769                                if ( javaVariableNames.containsKey( javaIdentifier ) )
3770                                {
3771                                    addDetail( validationContext.getReport(),
3772                                               "IMPLEMENTATION_DEPENDENCY_MESSAGE_ARGUMENT_JAVA_VARIABLE_NAME_UNIQUENESS_CONSTRAINT",
3773                                               Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3774                                               "implementationDependencyMessageArgumentJavaVariableNameUniquenessConstraint",
3775                                               implementation.getIdentifier(), moduleOfImpl.getName(),
3776                                               dependency.getName(), m.getName(), a.getName(), javaIdentifier,
3777                                               javaVariableNames.get( javaIdentifier ).getName() );
3778
3779                                }
3780                                else
3781                                {
3782                                    javaVariableNames.put( javaIdentifier, a );
3783                                }
3784                            }
3785                            catch ( final ModelObjectException e )
3786                            {
3787                                final String message = getMessage( e );
3788
3789                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3790                                {
3791                                    validationContext.getModelContext().log( Level.FINE, message, e );
3792                                }
3793
3794                                addDetail( validationContext.getReport(),
3795                                           "IMPLEMENTATION_DEPENDENCY_MESSAGE_ARGUMENT_JAVA_VARIABLE_NAME_CONSTRAINT",
3796                                           Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3797                                           "implementationDependencyMessageArgumentJavaVariableNameConstraint",
3798                                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3799                                           m.getName(), a.getIndex(),
3800                                           message != null && message.length() > 0 ? " " + message : "" );
3801
3802                            }
3803                        }
3804                    }
3805                }
3806            }
3807
3808            for ( int i = 0, s0 = dependency.getMessages().getReference().size(); i < s0; i++ )
3809            {
3810                final MessageReference r = dependency.getMessages().getReference().get( i );
3811
3812                addDetail( validationContext.getReport(),
3813                           "IMPLEMENTATION_DEPENDENCY_MESSAGE_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3814                           new ObjectFactory().createImplementation( implementation ),
3815                           "implementationDependencyMessageReferenceDeclarationConstraint",
3816                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(), r.getName() );
3817
3818            }
3819        }
3820
3821        if ( dependency.getProperties() != null )
3822        {
3823            for ( int i = 0, s0 = dependency.getProperties().getProperty().size(); i < s0; i++ )
3824            {
3825                final Property p = dependency.getProperties().getProperty().get( i );
3826
3827                if ( p.getValue() != null && p.getAny() != null )
3828                {
3829                    addDetail( validationContext.getReport(), "IMPLEMENTATION_DEPENDENCY_PROPERTY_VALUE_CONSTRAINT",
3830                               Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3831                               "implementationDependencyPropertyValueConstraint", implementation.getIdentifier(),
3832                               moduleOfImpl.getName(), dependency.getName(), p.getName() );
3833
3834                }
3835
3836                if ( p.getAny() != null && p.getType() == null )
3837                {
3838                    addDetail( validationContext.getReport(), "IMPLEMENTATION_DEPENDENCY_PROPERTY_TYPE_CONSTRAINT",
3839                               Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3840                               "implementationDependencyPropertyTypeConstraint", implementation.getIdentifier(),
3841                               moduleOfImpl.getName(), dependency.getName(), p.getName() );
3842
3843                }
3844
3845                if ( validationContext.isValidateJava() )
3846                {
3847                    try
3848                    {
3849                        p.getJavaConstantName();
3850                    }
3851                    catch ( final ModelObjectException e )
3852                    {
3853                        final String message = getMessage( e );
3854
3855                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3856                        {
3857                            validationContext.getModelContext().log( Level.FINE, message, e );
3858                        }
3859
3860                        addDetail( validationContext.getReport(),
3861                                   "IMPLEMENTATION_DEPENDENCY_PROPERTY_JAVA_CONSTANT_NAME_CONSTRAINT", Level.SEVERE,
3862                                   new ObjectFactory().createImplementation( implementation ),
3863                                   "implementationDependencyPropertyJavaConstantNameConstraint",
3864                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3865                                   p.getName(), message != null && message.length() > 0 ? " " + message : "" );
3866
3867                    }
3868
3869                    try
3870                    {
3871                        p.getJavaGetterMethodName();
3872                    }
3873                    catch ( final ModelObjectException e )
3874                    {
3875                        final String message = getMessage( e );
3876
3877                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3878                        {
3879                            validationContext.getModelContext().log( Level.FINE, message, e );
3880                        }
3881
3882                        addDetail( validationContext.getReport(),
3883                                   "IMPLEMENTATION_DEPENDENCY_PROPERTY_JAVA_GETTER_METHOD_NAME_CONSTRAINT",
3884                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3885                                   "implementationDependencyPropertyJavaGetterMethodNameConstraint",
3886                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3887                                   p.getName(), message != null && message.length() > 0 ? " " + message : "" );
3888
3889                    }
3890
3891                    try
3892                    {
3893                        p.getJavaSetterMethodName();
3894                    }
3895                    catch ( final ModelObjectException e )
3896                    {
3897                        final String message = getMessage( e );
3898
3899                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3900                        {
3901                            validationContext.getModelContext().log( Level.FINE, message, e );
3902                        }
3903
3904                        addDetail( validationContext.getReport(),
3905                                   "IMPLEMENTATION_DEPENDENCY_PROPERTY_JAVA_SETTER_METHOD_NAME_CONSTRAINT",
3906                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3907                                   "implementationDependencyPropertyJavaSetterMethodNameConstraint",
3908                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3909                                   p.getName(), message != null && message.length() > 0 ? " " + message : "" );
3910
3911                    }
3912
3913                    try
3914                    {
3915                        p.getJavaTypeName();
3916                    }
3917                    catch ( final ModelObjectException e )
3918                    {
3919                        final String message = getMessage( e );
3920
3921                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3922                        {
3923                            validationContext.getModelContext().log( Level.FINE, message, e );
3924                        }
3925
3926                        addDetail( validationContext.getReport(),
3927                                   "IMPLEMENTATION_DEPENDENCY_PROPERTY_JAVA_TYPE_NAME_CONSTRAINT",
3928                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3929                                   "implementationDependencyPropertyJavaTypeNameConstraint",
3930                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3931                                   p.getName(), message != null && message.length() > 0 ? " " + message : "" );
3932
3933                    }
3934
3935                    try
3936                    {
3937                        p.getJavaVariableName();
3938                    }
3939                    catch ( final ModelObjectException e )
3940                    {
3941                        final String message = getMessage( e );
3942
3943                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3944                        {
3945                            validationContext.getModelContext().log( Level.FINE, message, e );
3946                        }
3947
3948                        addDetail( validationContext.getReport(),
3949                                   "IMPLEMENTATION_DEPENDENCY_PROPERTY_JAVA_VARIABLE_NAME_CONSTRAINT",
3950                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
3951                                   "implementationDependencyPropertyJavaVariableNameConstraint",
3952                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3953                                   p.getName(), message != null && message.length() > 0 ? " " + message : "" );
3954
3955                    }
3956
3957                    try
3958                    {
3959                        p.getJavaValue( validationContext.getModelContext().getClassLoader() );
3960                    }
3961                    catch ( final ModelObjectException e )
3962                    {
3963                        final String message = getMessage( e );
3964
3965                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
3966                        {
3967                            validationContext.getModelContext().log( Level.FINE, message, e );
3968                        }
3969
3970                        addDetail( validationContext.getReport(),
3971                                   "IMPLEMENTATION_DEPENDENCY_PROPERTY_JAVA_VALUE_CONSTRAINT", Level.SEVERE,
3972                                   new ObjectFactory().createImplementation( implementation ),
3973                                   "implementationDependencyPropertyJavaValueConstraint",
3974                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
3975                                   p.getName(), message != null && message.length() > 0 ? " " + message : "" );
3976
3977                    }
3978                }
3979            }
3980
3981            for ( int i = 0, s0 = dependency.getProperties().getReference().size(); i < s0; i++ )
3982            {
3983                final PropertyReference r = dependency.getProperties().getReference().get( i );
3984
3985                addDetail( validationContext.getReport(),
3986                           "IMPLEMENTATION_DEPENDENCY_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3987                           new ObjectFactory().createImplementation( implementation ),
3988                           "implementationDependencyPropertyReferenceDeclarationConstraint",
3989                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(), r.getName() );
3990
3991            }
3992        }
3993
3994        if ( available != null )
3995        {
3996            for ( int i = 0, s0 = available.getImplementation().size(); i < s0; i++ )
3997            {
3998                final Implementation a = available.getImplementation().get( i );
3999
4000                if ( dependency.getImplementationName() != null
4001                         && !dependency.getImplementationName().equals( a.getName() ) )
4002                {
4003                    continue;
4004                }
4005
4006                final InheritanceModel imodel = validationContext.getInheritanceModel();
4007                final Module moduleOfA = validationContext.getModuleOfImplementation( a.getIdentifier() );
4008
4009                if ( dependency.getDependencies() != null )
4010                {
4011                    for ( int j = 0, s1 = dependency.getDependencies().getDependency().size(); j < s1; j++ )
4012                    {
4013                        final Dependency override = dependency.getDependencies().getDependency().get( j );
4014
4015                        final Set<InheritanceModel.Node<Dependency>> effDependencies =
4016                            imodel.getDependencyNodes( a.getIdentifier(), override.getName() );
4017
4018                        final Set<InheritanceModel.Node<Dependency>> overriddenDependencies =
4019                            modifiableSet( effDependencies );
4020
4021                        final boolean effectiveDependencyOverridden = !overriddenDependencies.isEmpty();
4022
4023                        if ( override.isOverride() && overriddenDependencies.isEmpty() )
4024                        {
4025                            addDetail( validationContext.getReport(),
4026                                       "IMPLEMENTATION_DEPENDENCY_OVERRIDE_DEPENDENCY_CONSTRAINT",
4027                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
4028                                       "implementationDependencyOverrideDependencyConstraint",
4029                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4030                                       override.getName(), a.getIdentifier(), moduleOfA.getName() );
4031
4032                        }
4033
4034                        if ( !( override.isOverride() || overriddenDependencies.isEmpty() ) )
4035                        {
4036                            for ( final InheritanceModel.Node<Dependency> overriddenDependency : overriddenDependencies )
4037                            {
4038                                addDetail( validationContext.getReport(),
4039                                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_DEPENDENCY_WARNING",
4040                                           Level.WARNING, new ObjectFactory().createImplementation( implementation ),
4041                                           "implementationDependencyOverrideDependencyWarning",
4042                                           implementation.getIdentifier(), moduleOfImpl.getName(),
4043                                           dependency.getName(), override.getName(), a.getIdentifier(),
4044                                           moduleOfA.getName(), getNodePathString( overriddenDependency ) );
4045
4046                            }
4047                        }
4048
4049                        retainFinalNodes( overriddenDependencies );
4050
4051                        for ( final InheritanceModel.Node<Dependency> overriddenDependency : overriddenDependencies )
4052                        {
4053                            addDetail( validationContext.getReport(),
4054                                       "IMPLEMENTATION_DEPENDENCY_FINAL_DEPENDENCY_CONSTRAINT",
4055                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
4056                                       "implementationDependencyFinalDependencyConstraint",
4057                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4058                                       override.getName(), a.getIdentifier(), moduleOfA.getName(),
4059                                       getNodePathString( overriddenDependency ) );
4060
4061                        }
4062
4063                        if ( effectiveDependencyOverridden )
4064                        {
4065                            for ( final InheritanceModel.Node<Dependency> node : effDependencies )
4066                            {
4067                                final Dependency overridden = node.getModelObject();
4068
4069                                final Specification overrideSpecification =
4070                                    validationContext.getSpecification( override.getIdentifier() );
4071
4072                                final Specification overriddenSpecification =
4073                                    validationContext.getSpecification( overridden.getIdentifier() );
4074
4075                                if ( overrideSpecification != null && overriddenSpecification != null )
4076                                {
4077                                    if ( overrideSpecification.getMultiplicity()
4078                                             != overriddenSpecification.getMultiplicity() )
4079                                    {
4080                                        addDetail( validationContext.getReport(),
4081                                                   "IMPLEMENTATION_DEPENDENCY_MULTIPLICITY_CONSTRAINT",
4082                                                   Level.SEVERE,
4083                                                   new ObjectFactory().createImplementation( implementation ),
4084                                                   "implementationDependencyMultiplicityConstraint",
4085                                                   implementation.getIdentifier(), moduleOfImpl.getName(),
4086                                                   dependency.getName(), overridden.getName(),
4087                                                   a.getIdentifier(), moduleOfA.getName(),
4088                                                   overrideSpecification.getMultiplicity().value(),
4089                                                   overriddenSpecification.getMultiplicity().value() );
4090
4091                                    }
4092
4093                                    if ( overrideSpecification.getScope() != null
4094                                             ? !overrideSpecification.getScope().equals(
4095                                            overriddenSpecification.getScope() )
4096                                             : overriddenSpecification.getScope() != null )
4097                                    {
4098                                        addDetail( validationContext.getReport(),
4099                                                   "IMPLEMENTATION_DEPENDENCY_SCOPE_CONSTRAINT", Level.SEVERE,
4100                                                   new ObjectFactory().createImplementation( implementation ),
4101                                                   "implementationDependencyScopeConstraint",
4102                                                   implementation.getIdentifier(), moduleOfImpl.getName(),
4103                                                   dependency.getName(), override.getName(),
4104                                                   a.getIdentifier(), moduleOfA.getName(),
4105                                                   overrideSpecification.getScope() == null
4106                                                       ? "Multiton" : overrideSpecification.getScope(),
4107                                                   overriddenSpecification.getScope() == null
4108                                                       ? "Multiton" : overriddenSpecification.getScope() );
4109
4110                                    }
4111
4112                                    if ( overriddenSpecification.getMultiplicity() == Multiplicity.MANY )
4113                                    {
4114                                        if ( override.getImplementationName() == null
4115                                                 && overridden.getImplementationName() != null )
4116                                        {
4117                                            addDetail( validationContext.getReport(),
4118                                                       "IMPLEMENTATION_DEPENDENCY_NO_IMPLEMENTATION_NAME_CONSTRAINT",
4119                                                       Level.SEVERE,
4120                                                       new ObjectFactory().createImplementation( implementation ),
4121                                                       "implementationDependencyNoImplementationNameConstraint",
4122                                                       implementation.getIdentifier(), moduleOfImpl.getName(),
4123                                                       dependency.getName(), override.getName(),
4124                                                       a.getIdentifier(), moduleOfA.getName() );
4125
4126                                        }
4127
4128                                        if ( override.getImplementationName() != null
4129                                                 && overridden.getImplementationName() == null )
4130                                        {
4131                                            addDetail( validationContext.getReport(),
4132                                                       "IMPLEMENTATION_DEPENDENCY_IMPLEMENTATION_NAME_CONSTRAINT",
4133                                                       Level.SEVERE,
4134                                                       new ObjectFactory().createImplementation( implementation ),
4135                                                       "implementationDependencyImplementationNameConstraint",
4136                                                       implementation.getIdentifier(), moduleOfImpl.getName(),
4137                                                       dependency.getName(), overridden.getName(),
4138                                                       a.getIdentifier(), moduleOfA.getName(),
4139                                                       override.getImplementationName() );
4140
4141                                        }
4142                                    }
4143                                }
4144
4145                                if ( override.isOptional() != overridden.isOptional() )
4146                                {
4147                                    addDetail( validationContext.getReport(),
4148                                               "IMPLEMENTATION_DEPENDENCY_OPTIONALITY_CONSTRAINT", Level.SEVERE,
4149                                               new ObjectFactory().createImplementation( implementation ),
4150                                               "implementationDependencyOptonalityConstraint",
4151                                               implementation.getIdentifier(), moduleOfImpl.getName(),
4152                                               dependency.getName(), overridden.getName(),
4153                                               a.getIdentifier(), moduleOfA.getName() );
4154
4155                                }
4156                            }
4157                        }
4158                    }
4159                }
4160
4161                if ( dependency.getMessages() != null )
4162                {
4163                    for ( int j = 0, s1 = dependency.getMessages().getMessage().size(); j < s1; j++ )
4164                    {
4165                        final Message override = dependency.getMessages().getMessage().get( j );
4166
4167                        final Set<InheritanceModel.Node<Message>> overriddenMessages =
4168                            modifiableSet( imodel.getMessageNodes( a.getIdentifier(), override.getName() ) );
4169
4170                        if ( override.isOverride() && overriddenMessages.isEmpty() )
4171                        {
4172                            addDetail( validationContext.getReport(),
4173                                       "IMPLEMENTATION_DEPENDENCY_OVERRIDE_MESSAGE_CONSTRAINT", Level.SEVERE,
4174                                       new ObjectFactory().createImplementation( implementation ),
4175                                       "implementationDependencyOverrideMessageConstraint",
4176                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4177                                       override.getName(), a.getIdentifier(), moduleOfA.getName() );
4178
4179                        }
4180
4181                        if ( !( override.isOverride() || overriddenMessages.isEmpty() ) )
4182                        {
4183                            for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
4184                            {
4185                                addDetail( validationContext.getReport(),
4186                                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_MESSAGE_WARNING", Level.WARNING,
4187                                           new ObjectFactory().createImplementation( implementation ),
4188                                           "implementationDependencyOverrideMessageWarning",
4189                                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4190                                           override.getName(), a.getIdentifier(), moduleOfA.getName(),
4191                                           getNodePathString( overriddenMessage ) );
4192
4193                            }
4194                        }
4195
4196                        retainFinalNodes( overriddenMessages );
4197
4198                        for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
4199                        {
4200                            addDetail( validationContext.getReport(),
4201                                       "IMPLEMENTATION_DEPENDENCY_FINAL_MESSAGE_CONSTRAINT", Level.SEVERE,
4202                                       new ObjectFactory().createImplementation( implementation ),
4203                                       "implementationDependencyFinalMessageConstraint",
4204                                       implementation.getIdentifier(), moduleOfImpl.getName(),
4205                                       dependency.getName(), override.getName(), a.getIdentifier(),
4206                                       moduleOfA.getName(), getNodePathString( overriddenMessage ) );
4207
4208                        }
4209                    }
4210                }
4211
4212                if ( dependency.getProperties() != null )
4213                {
4214                    for ( int j = 0, s1 = dependency.getProperties().getProperty().size(); j < s1; j++ )
4215                    {
4216                        final Property override = dependency.getProperties().getProperty().get( j );
4217
4218                        final Set<InheritanceModel.Node<Property>> overriddenProperties =
4219                            modifiableSet( imodel.getPropertyNodes( a.getIdentifier(), override.getName() ) );
4220
4221                        if ( override.isOverride() && overriddenProperties.isEmpty() )
4222                        {
4223                            addDetail( validationContext.getReport(),
4224                                       "IMPLEMENTATION_DEPENDENCY_OVERRIDE_PROPERTY_CONSTRAINT", Level.SEVERE,
4225                                       new ObjectFactory().createImplementation( implementation ),
4226                                       "implementationDependencyOverridePropertyConstraint",
4227                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4228                                       override.getName(), a.getIdentifier(), moduleOfA.getName() );
4229
4230                        }
4231
4232                        if ( !( override.isOverride() || overriddenProperties.isEmpty() ) )
4233                        {
4234                            for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
4235                            {
4236                                addDetail( validationContext.getReport(),
4237                                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_PROPERTY_WARNING", Level.WARNING,
4238                                           new ObjectFactory().createImplementation( implementation ),
4239                                           "implementationDependencyOverridePropertyWarning",
4240                                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4241                                           override.getName(), a.getIdentifier(), moduleOfA.getName(),
4242                                           getNodePathString( overriddenProperty ) );
4243
4244                            }
4245                        }
4246
4247                        retainFinalNodes( overriddenProperties );
4248
4249                        for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
4250                        {
4251                            addDetail( validationContext.getReport(),
4252                                       "IMPLEMENTATION_DEPENDENCY_FINAL_PROPERTY_CONSTRAINT", Level.SEVERE,
4253                                       new ObjectFactory().createImplementation( implementation ),
4254                                       "implementationDependencyFinalPropertyConstraint",
4255                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4256                                       override.getName(), a.getIdentifier(), moduleOfA.getName(),
4257                                       getNodePathString( overriddenProperty ) );
4258
4259                        }
4260                    }
4261                }
4262            }
4263        }
4264
4265        if ( dependency.getDependencies() != null )
4266        {
4267            for ( int i = 0, s0 = dependency.getDependencies().getDependency().size(); i < s0; i++ )
4268            {
4269                final Dependency d = dependency.getDependencies().getDependency().get( i );
4270
4271                if ( validationContext.isValidateJava() )
4272                {
4273                    try
4274                    {
4275                        d.getJavaConstantName();
4276                    }
4277                    catch ( final ModelObjectException e )
4278                    {
4279                        final String message = getMessage( e );
4280
4281                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
4282                        {
4283                            validationContext.getModelContext().log( Level.FINE, message, e );
4284                        }
4285
4286                        addDetail( validationContext.getReport(),
4287                                   "IMPLEMENTATION_DEPENDENCY_DEPENDENCY_JAVA_CONSTANT_NAME_CONSTRAINT", Level.SEVERE,
4288                                   new ObjectFactory().createImplementation( implementation ),
4289                                   "implementationDependencyDependencyJavaConstantNameConstraint",
4290                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4291                                   d.getName(), message != null && message.length() > 0 ? " " + message : "" );
4292
4293                    }
4294
4295                    try
4296                    {
4297                        d.getJavaGetterMethodName();
4298                    }
4299                    catch ( final ModelObjectException e )
4300                    {
4301                        final String message = getMessage( e );
4302
4303                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
4304                        {
4305                            validationContext.getModelContext().log( Level.FINE, message, e );
4306                        }
4307
4308                        addDetail( validationContext.getReport(),
4309                                   "IMPLEMENTATION_DEPENDENCY_DEPENDENCY_JAVA_GETTER_METHOD_NAME_CONSTRAINT",
4310                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
4311                                   "implementationDependencyDependencyJavaGetterMethodNameConstraint",
4312                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4313                                   d.getName(), message != null && message.length() > 0 ? " " + message : "" );
4314
4315                    }
4316
4317                    try
4318                    {
4319                        d.getJavaSetterMethodName();
4320                    }
4321                    catch ( final ModelObjectException e )
4322                    {
4323                        final String message = getMessage( e );
4324
4325                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
4326                        {
4327                            validationContext.getModelContext().log( Level.FINE, message, e );
4328                        }
4329
4330                        addDetail( validationContext.getReport(),
4331                                   "IMPLEMENTATION_DEPENDENCY_DEPENDENCY_JAVA_SETTER_METHOD_NAME_CONSTRAINT",
4332                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
4333                                   "implementationDependencyDependencyJavaSetterMethodNameConstraint",
4334                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4335                                   d.getName(), message != null && message.length() > 0 ? " " + message : "" );
4336
4337                    }
4338
4339                    try
4340                    {
4341                        d.getJavaVariableName();
4342                    }
4343                    catch ( final ModelObjectException e )
4344                    {
4345                        final String message = getMessage( e );
4346
4347                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
4348                        {
4349                            validationContext.getModelContext().log( Level.FINE, message, e );
4350                        }
4351
4352                        addDetail( validationContext.getReport(),
4353                                   "IMPLEMENTATION_DEPENDENCY_DEPENDENCY_JAVA_VARIABLE_NAME_CONSTRAINT",
4354                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
4355                                   "implementationDependencyDependencyJavaVariableNameConstraint",
4356                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
4357                                   d.getName(), message != null && message.length() > 0 ? " " + message : "" );
4358
4359                    }
4360                }
4361
4362                assertDependencyValid( validationContext, implementation, d );
4363            }
4364        }
4365    }
4366
4367    private static void assertImplementationSpecificationCompatibility(
4368        final ValidationContext validationContext, final Implementation implementation )
4369    {
4370        final Specifications specs = validationContext.getSpecifications( implementation.getIdentifier() );
4371        final Module moduleOfImpl =
4372            validationContext.getModuleOfImplementation( implementation.getIdentifier() );
4373
4374        if ( specs != null )
4375        {
4376            for ( int i = 0, s0 = specs.getReference().size(); i < s0; i++ )
4377            {
4378                final SpecificationReference r = specs.getReference().get( i );
4379                final Specification s = specs.getSpecification( r.getIdentifier() );
4380
4381                if ( s != null && r.getVersion() != null )
4382                {
4383                    final Module moduleOfS =
4384                        validationContext.getModuleOfSpecification( s.getIdentifier() );
4385
4386                    if ( s.getVersion() == null )
4387                    {
4388                        addDetail( validationContext.getReport(),
4389                                   "IMPLEMENTATION_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
4390                                   new ObjectFactory().createImplementation( implementation ),
4391                                   "implementationSpecificationVersioningConstraint", implementation.getIdentifier(),
4392                                   moduleOfImpl.getName(), s.getIdentifier(), moduleOfS.getName() );
4393
4394                    }
4395                    else
4396                    {
4397                        try
4398                        {
4399                            if ( VersionParser.compare( r.getVersion(), s.getVersion() ) != 0 )
4400                            {
4401                                addDetail( validationContext.getReport(),
4402                                           "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
4403                                           new ObjectFactory().createImplementation( implementation ),
4404                                           "implementationSpecificationCompatibilityConstraint",
4405                                           implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
4406                                           moduleOfS.getName(), r.getVersion(), s.getVersion() );
4407
4408                            }
4409                        }
4410                        catch ( final ParseException e )
4411                        {
4412                            final String message = getMessage( e );
4413
4414                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
4415                            {
4416                                validationContext.getModelContext().log( Level.FINE, message, e );
4417                            }
4418
4419                            addDetail( validationContext.getReport(),
4420                                       "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_VERSIONING_PARSE_EXCEPTION",
4421                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
4422                                       "implementationSpecificationCompatibilityVersioningParseException",
4423                                       implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
4424                                       moduleOfS.getName(), r.getVersion(),
4425                                       message != null && message.length() > 0 ? " " + message : "" );
4426
4427                        }
4428                        catch ( final TokenMgrError e )
4429                        {
4430                            final String message = getMessage( e );
4431
4432                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
4433                            {
4434                                validationContext.getModelContext().log( Level.FINE, message, e );
4435                            }
4436
4437                            addDetail( validationContext.getReport(),
4438                                       "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_VERSIONING_TOKEN_MANAGER_ERROR",
4439                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
4440                                       "implementationSpecificationCompatibilityVersioningTokenManagerError",
4441                                       implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
4442                                       moduleOfS.getName(), r.getVersion(),
4443                                       message != null && message.length() > 0 ? " " + message : "" );
4444
4445                        }
4446                    }
4447                }
4448            }
4449        }
4450    }
4451
4452    private static <T> String getNodePathString( final InheritanceModel.Node<T> node )
4453    {
4454        final StringBuilder b = new StringBuilder( node.getPath().size() * 50 );
4455
4456        for ( int i = 0, s0 = node.getPath().size(); i < s0; i++ )
4457        {
4458            final InheritanceModel.Node<Implementation> pathNode = node.getPath().get( i );
4459
4460            if ( pathNode.getClassDeclaration() != null )
4461            {
4462                b.append( " -> [" ).append( pathNode.getClassDeclaration().getClazz() ).append( "] @ '" ).
4463                    append( pathNode.getImplementation().getIdentifier() ).append( "'" );
4464
4465            }
4466            if ( pathNode.getSpecification() != null )
4467            {
4468                b.append( " -> <" ).append( pathNode.getSpecification().getIdentifier() ).append( "> @ '" ).
4469                    append( pathNode.getImplementation().getIdentifier() ).append( "'" );
4470
4471            }
4472            else
4473            {
4474                b.append( " -> '" ).append( pathNode.getImplementation().getIdentifier() ).append( "'" );
4475            }
4476        }
4477
4478        if ( node.getClassDeclaration() != null )
4479        {
4480            b.append( " -> [" ).append( node.getClassDeclaration().getClazz() ).append( "] @ '" ).
4481                append( node.getImplementation().getIdentifier() ).append( "'" );
4482
4483        }
4484        if ( node.getSpecification() != null )
4485        {
4486            b.append( " -> <" ).append( node.getSpecification().getIdentifier() ).append( "> @ '" ).
4487                append( node.getImplementation().getIdentifier() ).append( "'" );
4488
4489        }
4490
4491        return b.length() > 0 ? b.substring( " -> ".length() ) : b.toString();
4492    }
4493
4494    private static <T> String getNodeListPathString( final Collection<? extends InheritanceModel.Node<T>> nodes )
4495    {
4496        final StringBuilder path = new StringBuilder( nodes.size() * 255 );
4497
4498        for ( final InheritanceModel.Node<T> node : nodes )
4499        {
4500            path.append( ", " ).append( getNodePathString( node ) );
4501        }
4502
4503        return path.length() > 1 ? path.substring( 2 ) : path.toString();
4504    }
4505
4506    private static <T> Set<InheritanceModel.Node<T>> retainFinalNodes( final Set<InheritanceModel.Node<T>> set )
4507    {
4508        if ( set != null )
4509        {
4510            for ( final Iterator<InheritanceModel.Node<T>> it = set.iterator(); it.hasNext(); )
4511            {
4512                if ( !it.next().isFinal() )
4513                {
4514                    it.remove();
4515                }
4516            }
4517        }
4518
4519        return set;
4520    }
4521
4522    private static void addDetail(
4523        final ModelValidationReport report, final String identifier, final Level level,
4524        final JAXBElement<? extends ModelObject> element, final String messageKey, final Object... messageArguments )
4525    {
4526        report.getDetails().add( new ModelValidationReport.Detail(
4527            identifier, level, getMessage( messageKey, messageArguments ), element ) );
4528
4529    }
4530
4531    private static <T> Set<T> modifiableSet( final Collection<? extends T> col )
4532    {
4533        Set<T> set = Collections.emptySet();
4534
4535        if ( col != null )
4536        {
4537            set = new HashSet<T>( col );
4538        }
4539
4540        return set;
4541    }
4542
4543    private static String getMessage( final String key, final Object... messageArguments )
4544    {
4545        return MessageFormat.format( ResourceBundle.getBundle(
4546            DefaultModelValidator.class.getName(), Locale.getDefault() ).getString( key ), messageArguments );
4547
4548    }
4549
4550    private static String getMessage( final Throwable t )
4551    {
4552        return t != null
4553                   ? t.getMessage() != null && t.getMessage().trim().length() > 0
4554                         ? t.getMessage()
4555                         : getMessage( t.getCause() )
4556                   : null;
4557
4558    }
4559
4560    /**
4561     * @since 1.2
4562     */
4563    private static final class ValidationContext
4564    {
4565
4566        private final ModelContext modelContext;
4567
4568        private final Modules modules;
4569
4570        private final ModelValidationReport report;
4571
4572        private final InheritanceModel inheritanceModel;
4573
4574        private final boolean validateJava;
4575
4576        private final Specifications allSpecifications;
4577
4578        private final Implementations allImplementations;
4579
4580        private final Map<String, Specification> specifications = new HashMap<String, Specification>( 128 );
4581
4582        private final Map<String, Specifications> specificationsByImplementation =
4583            new HashMap<String, Specifications>( 128 );
4584
4585        private final Map<String, Module> modulesOfSpecifications = new HashMap<String, Module>( 128 );
4586
4587        private final Map<String, Implementation> implementations = new HashMap<String, Implementation>();
4588
4589        private final Map<String, Implementations> implementationsBySpecification =
4590            new HashMap<String, Implementations>( 128 );
4591
4592        private final Map<String, Module> modulesOfImplementations = new HashMap<String, Module>( 128 );
4593
4594        private ValidationContext( final ModelContext modelContext, final Modules modules,
4595                                   final ModelValidationReport report, final boolean validateJava )
4596        {
4597            super();
4598            this.modelContext = modelContext;
4599            this.modules = modules;
4600            this.report = report;
4601            this.inheritanceModel = new InheritanceModel( modules );
4602            this.validateJava = validateJava;
4603            this.allImplementations = modules.getImplementations();
4604            this.allSpecifications = modules.getSpecifications();
4605
4606            if ( this.allSpecifications != null )
4607            {
4608                for ( final Specification s : this.allSpecifications.getSpecification() )
4609                {
4610                    this.specifications.put( s.getIdentifier(), s );
4611                    this.implementationsBySpecification.put(
4612                        s.getIdentifier(), modules.getImplementations( s.getIdentifier() ) );
4613
4614                    this.modulesOfSpecifications.put(
4615                        s.getIdentifier(), modules.getModuleOfSpecification( s.getIdentifier() ) );
4616
4617                }
4618            }
4619
4620            if ( this.allImplementations != null )
4621            {
4622                for ( final Implementation i : this.allImplementations.getImplementation() )
4623                {
4624                    this.implementations.put( i.getIdentifier(), i );
4625                    this.specificationsByImplementation.put(
4626                        i.getIdentifier(), modules.getSpecifications( i.getIdentifier() ) );
4627
4628                    this.modulesOfImplementations.put(
4629                        i.getIdentifier(), modules.getModuleOfImplementation( i.getIdentifier() ) );
4630                }
4631            }
4632        }
4633
4634        private ModelContext getModelContext()
4635        {
4636            return modelContext;
4637        }
4638
4639        private Modules getModules()
4640        {
4641            return modules;
4642        }
4643
4644        private ModelValidationReport getReport()
4645        {
4646            return report;
4647        }
4648
4649        private InheritanceModel getInheritanceModel()
4650        {
4651            return this.inheritanceModel;
4652        }
4653
4654        private boolean isValidateJava()
4655        {
4656            return this.validateJava;
4657        }
4658
4659        private Specifications getAllSpecifications()
4660        {
4661            return this.allSpecifications;
4662        }
4663
4664        private Implementations getAllImplementations()
4665        {
4666            return this.allImplementations;
4667        }
4668
4669        private Specification getSpecification( final String identifier )
4670        {
4671            return this.specifications.get( identifier );
4672        }
4673
4674        private Specifications getSpecifications( final String implementation )
4675        {
4676            return this.specificationsByImplementation.get( implementation );
4677        }
4678
4679        private Implementation getImplementation( final String identifier )
4680        {
4681            return this.implementations.get( identifier );
4682        }
4683
4684        private Implementations getImplementations( final String specification )
4685        {
4686            return this.implementationsBySpecification.get( specification );
4687        }
4688
4689        private Module getModuleOfSpecification( final String identifier )
4690        {
4691            return this.modulesOfSpecifications.get( identifier );
4692        }
4693
4694        private Module getModuleOfImplementation( final String identifier )
4695        {
4696            return this.modulesOfImplementations.get( identifier );
4697        }
4698
4699    }
4700
4701}