001/*
002 *   Copyright (C) Christian Schulte, 2005-206
003 *   All rights reserved.
004 *
005 *   Redistribution and use in source and binary forms, with or without
006 *   modification, are permitted provided that the following conditions
007 *   are met:
008 *
009 *     o Redistributions of source code must retain the above copyright
010 *       notice, this list of conditions and the following disclaimer.
011 *
012 *     o Redistributions in binary form must reproduce the above copyright
013 *       notice, this list of conditions and the following disclaimer in
014 *       the documentation and/or other materials provided with the
015 *       distribution.
016 *
017 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019 *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 *
028 *   $JOMC: DefaultModelValidator.java 4424 2012-03-14 08:48:26Z schulte2005 $
029 *
030 */
031package org.jomc.model.modlet;
032
033import java.text.MessageFormat;
034import java.util.Collection;
035import java.util.Collections;
036import java.util.HashMap;
037import java.util.HashSet;
038import java.util.Iterator;
039import java.util.LinkedList;
040import java.util.List;
041import java.util.Locale;
042import java.util.Map;
043import java.util.ResourceBundle;
044import java.util.Set;
045import java.util.logging.Level;
046import javax.xml.bind.JAXBElement;
047import javax.xml.bind.JAXBException;
048import javax.xml.bind.util.JAXBSource;
049import javax.xml.namespace.QName;
050import javax.xml.transform.Source;
051import org.jomc.model.Dependency;
052import org.jomc.model.Implementation;
053import org.jomc.model.ImplementationReference;
054import org.jomc.model.Implementations;
055import org.jomc.model.Inheritable;
056import org.jomc.model.InheritanceModel;
057import org.jomc.model.Message;
058import org.jomc.model.MessageReference;
059import org.jomc.model.ModelObject;
060import org.jomc.model.Module;
061import org.jomc.model.Modules;
062import org.jomc.model.Multiplicity;
063import org.jomc.model.ObjectFactory;
064import org.jomc.model.Property;
065import org.jomc.model.PropertyException;
066import org.jomc.model.PropertyReference;
067import org.jomc.model.Specification;
068import org.jomc.model.SpecificationReference;
069import org.jomc.model.Specifications;
070import org.jomc.model.Text;
071import org.jomc.modlet.Model;
072import org.jomc.modlet.ModelContext;
073import org.jomc.modlet.ModelException;
074import org.jomc.modlet.ModelValidationReport;
075import org.jomc.modlet.ModelValidator;
076import org.jomc.util.ParseException;
077import org.jomc.util.TokenMgrError;
078import org.jomc.util.VersionParser;
079import org.w3c.dom.Element;
080
081/**
082 * Default object management and configuration {@code ModelValidator} implementation.
083 *
084 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
085 * @version $JOMC: DefaultModelValidator.java 4424 2012-03-14 08:48:26Z schulte2005 $
086 * @see ModelContext#validateModel(org.jomc.modlet.Model)
087 */
088public class DefaultModelValidator implements ModelValidator
089{
090
091    /** Creates a new {@code DefaultModelValidator} instance. */
092    public DefaultModelValidator()
093    {
094        super();
095    }
096
097    public ModelValidationReport validateModel( final ModelContext context, final Model model ) throws ModelException
098    {
099        if ( context == null )
100        {
101            throw new NullPointerException( "context" );
102        }
103        if ( model == null )
104        {
105            throw new NullPointerException( "model" );
106        }
107
108        try
109        {
110            final Source source = new JAXBSource( context.createContext( model.getIdentifier() ),
111                                                  new org.jomc.modlet.ObjectFactory().createModel( model ) );
112
113            final ModelValidationReport report = context.validateModel( model.getIdentifier(), source );
114            final Modules modules = ModelHelper.getModules( model );
115
116            if ( modules != null )
117            {
118                final ValidationContext validationContext = new ValidationContext( context, modules, report );
119                assertModulesValid( validationContext );
120                assertSpecificationsValid( validationContext );
121                assertImplementationsValid( validationContext );
122            }
123
124            return report;
125        }
126        catch ( final JAXBException e )
127        {
128            String message = getMessage( e );
129            if ( message == null && e.getLinkedException() != null )
130            {
131                message = getMessage( e.getLinkedException() );
132            }
133
134            if ( context.isLoggable( Level.FINE ) )
135            {
136                context.log( Level.FINE, message, e );
137            }
138
139            throw new ModelException( message, e );
140        }
141    }
142
143    private static void assertModulesValid( final ValidationContext validationContext )
144    {
145        for ( int i = 0, s0 = validationContext.getModules().getModule().size(); i < s0; i++ )
146        {
147            final Module m = validationContext.getModules().getModule().get( i );
148
149            if ( m.getImplementations() != null )
150            {
151                for ( int j = 0, s1 = m.getImplementations().getReference().size(); j < s1; j++ )
152                {
153                    final ImplementationReference r = m.getImplementations().getReference().get( j );
154                    addDetail( validationContext.getReport(), "MODULE_IMPLEMENTATION_REFERENCE_DECLARATION_CONSTRAINT",
155                               Level.SEVERE, new ObjectFactory().createModule( m ),
156                               "moduleImplementationReferenceDeclarationConstraint", m.getName(), r.getIdentifier() );
157
158                }
159            }
160
161            if ( m.getMessages() != null )
162            {
163                for ( int j = 0, s1 = m.getMessages().getMessage().size(); j < s1; j++ )
164                {
165                    final Message msg = m.getMessages().getMessage().get( j );
166
167                    if ( msg.isFinal() )
168                    {
169                        addDetail( validationContext.getReport(), "MODULE_FINAL_MESSAGE_DECLARATION_CONSTRAINT",
170                                   Level.SEVERE, new ObjectFactory().createModule( m ), "moduleFinalMessageConstraint",
171                                   m.getName(), msg.getName() );
172
173                    }
174
175                    if ( msg.isOverride() )
176                    {
177                        addDetail( validationContext.getReport(), "MODULE_OVERRIDE_MESSAGE_DECLARATION_CONSTRAINT",
178                                   Level.SEVERE, new ObjectFactory().createModule( m ),
179                                   "moduleOverrideMessageConstraint", m.getName(), msg.getName() );
180
181                    }
182
183                    if ( msg.getTemplate() != null )
184                    {
185                        for ( int k = 0, s2 = msg.getTemplate().getText().size(); k < s2; k++ )
186                        {
187                            final Text t = msg.getTemplate().getText().get( k );
188
189                            try
190                            {
191                                new MessageFormat( t.getValue(), new Locale( t.getLanguage() ) );
192                            }
193                            catch ( final IllegalArgumentException e )
194                            {
195                                final String message = getMessage( e );
196
197                                if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
198                                {
199                                    validationContext.getModelContext().log( Level.FINE, message, e );
200                                }
201
202                                addDetail( validationContext.getReport(), "MODULE_MESSAGE_TEMPLATE_CONSTRAINT",
203                                           Level.SEVERE, new ObjectFactory().createModule( m ),
204                                           "moduleMessageTemplateConstraint", m.getName(), msg.getName(), t.getValue(),
205                                           message );
206
207                            }
208                        }
209                    }
210                }
211
212                for ( int j = 0, s1 = m.getMessages().getReference().size(); j < s1; j++ )
213                {
214                    final MessageReference r = m.getMessages().getReference().get( j );
215                    addDetail( validationContext.getReport(), "MODULE_MESSAGE_REFERENCE_DECLARATION_CONSTRAINT",
216                               Level.SEVERE, new ObjectFactory().createModule( m ),
217                               "moduleMessageReferenceDeclarationConstraint", m.getName(), r.getName() );
218
219                }
220            }
221
222            if ( m.getProperties() != null )
223            {
224                for ( int j = 0, s1 = m.getProperties().getProperty().size(); j < s1; j++ )
225                {
226                    final Property p = m.getProperties().getProperty().get( j );
227
228                    if ( p.isFinal() )
229                    {
230                        addDetail( validationContext.getReport(), "MODULE_FINAL_PROPERTY_DECLARATION_CONSTRAINT",
231                                   Level.SEVERE, new ObjectFactory().createModule( m ), "moduleFinalPropertyConstraint",
232                                   m.getName(), p.getName() );
233
234                    }
235
236                    if ( p.isOverride() )
237                    {
238                        addDetail( validationContext.getReport(), "MODULE_OVERRIDE_PROPERTY_DECLARATION_CONSTRAINT",
239                                   Level.SEVERE, new ObjectFactory().createModule( m ),
240                                   "moduleOverridePropertyConstraint", m.getName(), p.getName() );
241
242                    }
243
244                    if ( p.getValue() != null && p.getAny() != null )
245                    {
246                        addDetail( validationContext.getReport(), "MODULE_PROPERTY_VALUE_CONSTRAINT", Level.SEVERE,
247                                   new ObjectFactory().createModule( m ), "modulePropertyValueConstraint", m.getName(),
248                                   p.getName() );
249
250                    }
251
252                    if ( p.getAny() != null && p.getType() == null )
253                    {
254                        addDetail( validationContext.getReport(), "MODULE_PROPERTY_TYPE_CONSTRAINT", Level.SEVERE,
255                                   new ObjectFactory().createModule( m ), "modulePropertyTypeConstraint", m.getName(),
256                                   p.getName() );
257
258                    }
259
260                    try
261                    {
262                        p.getJavaValue( validationContext.getModelContext().getClassLoader() );
263                    }
264                    catch ( final PropertyException e )
265                    {
266                        final String message = getMessage( e );
267
268                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
269                        {
270                            validationContext.getModelContext().log( Level.FINE, message, e );
271                        }
272
273                        addDetail( validationContext.getReport(), "MODULE_PROPERTY_JAVA_VALUE_CONSTRAINT", Level.SEVERE,
274                                   new ObjectFactory().createModule( m ), "modulePropertyJavaValueConstraint",
275                                   m.getName(), p.getName(), message );
276
277                    }
278                }
279
280                for ( int j = 0, s1 = m.getProperties().getReference().size(); j < s1; j++ )
281                {
282                    final PropertyReference r = m.getProperties().getReference().get( j );
283                    addDetail( validationContext.getReport(), "MODULE_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT",
284                               Level.SEVERE, new ObjectFactory().createModule( m ),
285                               "modulePropertyReferenceDeclarationConstraint", m.getName(), r.getName() );
286
287                }
288            }
289
290            if ( m.getSpecifications() != null )
291            {
292                for ( int j = 0, s1 = m.getSpecifications().getReference().size(); j < s1; j++ )
293                {
294                    final SpecificationReference r = m.getSpecifications().getReference().get( j );
295                    addDetail( validationContext.getReport(), "MODULE_SPECIFICATION_REFERENCE_DECLARATION_CONSTRAINT",
296                               Level.SEVERE, new ObjectFactory().createModule( m ),
297                               "moduleSpecificationReferenceDeclarationConstraint", m.getName(), r.getIdentifier() );
298
299                }
300            }
301        }
302    }
303
304    private static void assertImplementationsValid( final ValidationContext validationContext )
305    {
306        final Implementations implementations = validationContext.getModules().getImplementations();
307
308        if ( implementations != null )
309        {
310            final Map<String, Implementation> implementationClassDeclarations = new HashMap<String, Implementation>();
311
312            for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
313            {
314                final Implementation impl = implementations.getImplementation().get( i );
315                final InheritanceModel imodel = validationContext.getInheritanceModel();
316                final List<String> cyclePath = new LinkedList<String>();
317                final Module moduleOfImpl =
318                    validationContext.getModules().getModuleOfImplementation( impl.getIdentifier() );
319
320                if ( isInheritanceCycle( validationContext, impl, null, cyclePath ) )
321                {
322                    final StringBuilder b = new StringBuilder( cyclePath.size() * 50 );
323
324                    for ( int j = 0, s1 = cyclePath.size(); j < s1; j++ )
325                    {
326                        b.append( " -> " ).append( "'" ).append( cyclePath.get( j ) ).append( "'" );
327                    }
328
329                    addDetail( validationContext.getReport(), "IMPLEMENTATION_INHERITANCE_CYCLE_CONSTRAINT",
330                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
331                               "implementationInheritanceCycleConstraint", impl.getIdentifier(),
332                               moduleOfImpl.getName(), b.substring( " -> ".length() ) );
333
334                }
335
336                if ( impl.isClassDeclaration() )
337                {
338                    if ( impl.getClazz() == null )
339                    {
340                        addDetail( validationContext.getReport(), "IMPLEMENTATION_CLASS_CONSTRAINT", Level.SEVERE,
341                                   new ObjectFactory().createImplementation( impl ), "implementationClassConstraint",
342                                   impl.getIdentifier(), moduleOfImpl.getName() );
343
344                    }
345                    else
346                    {
347                        final Implementation prev = implementationClassDeclarations.get( impl.getClazz() );
348
349                        if ( prev != null && !prev.getIdentifier().equals( impl.getIdentifier() ) )
350                        {
351                            final Module moduleOfPrev =
352                                validationContext.getModules().getModuleOfImplementation( prev.getIdentifier() );
353
354                            addDetail( validationContext.getReport(), "IMPLEMENTATION_CLASS_DECLARATION_CONSTRAINT",
355                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
356                                       "implementationClassDeclarationConstraint", impl.getIdentifier(),
357                                       moduleOfImpl.getName(), impl.getClazz(), prev.getIdentifier(),
358                                       moduleOfPrev.getName() );
359
360                        }
361                        else
362                        {
363                            implementationClassDeclarations.put( impl.getClazz(), impl );
364                        }
365                    }
366                }
367
368                if ( impl.isAbstract() && impl.getLocation() != null )
369                {
370                    addDetail( validationContext.getReport(), "IMPLEMENTATION_ABSTRACT_LOCATION_DECLARATION_CONSTRAINT",
371                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
372                               "implementationAbstractLocationDeclarationConstraint", impl.getIdentifier(),
373                               moduleOfImpl.getName(), impl.getLocation() );
374
375                }
376
377                if ( impl.getDependencies() != null )
378                {
379                    for ( int j = 0, s1 = impl.getDependencies().getDependency().size(); j < s1; j++ )
380                    {
381                        final Dependency d = impl.getDependencies().getDependency().get( j );
382
383                        final Set<InheritanceModel.Node<Dependency>> effDependencies =
384                            imodel.getDependencyNodes( impl.getIdentifier(), d.getName() );
385
386                        for ( final InheritanceModel.Node<Dependency> effDependency : effDependencies )
387                        {
388                            final Set<InheritanceModel.Node<Dependency>> overriddenDependencies =
389                                modifiableSet( effDependency.getOverriddenNodes() );
390
391                            if ( d.isOverride() && effDependency.getOverriddenNodes().isEmpty() )
392                            {
393                                addDetail( validationContext.getReport(),
394                                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_CONSTRAINT",
395                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
396                                           "implementationDependencyOverrideConstraint", impl.getIdentifier(),
397                                           moduleOfImpl.getName(), d.getName() );
398
399                            }
400
401                            if ( !( d.isOverride() || overriddenDependencies.isEmpty() ) )
402                            {
403                                for ( final InheritanceModel.Node<Dependency> overriddenDependency :
404                                      overriddenDependencies )
405                                {
406                                    Implementation overriddenImplementation = overriddenDependency.getImplementation();
407                                    if ( overriddenDependency.getClassDeclaration() != null )
408                                    {
409                                        overriddenImplementation = overriddenDependency.getClassDeclaration();
410                                    }
411
412                                    final Module moduleOfDependency =
413                                        validationContext.getModules().getModuleOfImplementation(
414                                        overriddenImplementation.getIdentifier() );
415
416                                    addDetail( validationContext.getReport(),
417                                               "IMPLEMENTATION_DEPENDENCY_OVERRIDE_WARNING",
418                                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
419                                               "implementationDependencyOverrideWarning", impl.getIdentifier(),
420                                               moduleOfImpl.getName(), d.getName(),
421                                               overriddenImplementation.getIdentifier(),
422                                               moduleOfDependency.getName(),
423                                               getNodePathString( overriddenDependency ) );
424
425                                }
426                            }
427
428                            retainFinalNodes( overriddenDependencies );
429
430                            for ( final InheritanceModel.Node<Dependency> overriddenDependency :
431                                  overriddenDependencies )
432                            {
433                                Implementation overriddenImplementation = overriddenDependency.getImplementation();
434                                if ( overriddenDependency.getClassDeclaration() != null )
435                                {
436                                    overriddenImplementation = overriddenDependency.getClassDeclaration();
437                                }
438
439                                final Module moduleOfDependency =
440                                    validationContext.getModules().getModuleOfImplementation(
441                                    overriddenImplementation.getIdentifier() );
442
443                                addDetail( validationContext.getReport(),
444                                           "IMPLEMENTATION_DEPENDENCY_INHERITANCE_CONSTRAINT", Level.SEVERE,
445                                           new ObjectFactory().createImplementation( impl ),
446                                           "implementationDependencyFinalConstraint", impl.getIdentifier(),
447                                           moduleOfImpl.getName(), d.getName(),
448                                           overriddenImplementation.getIdentifier(),
449                                           moduleOfDependency.getName(),
450                                           getNodePathString( overriddenDependency ) );
451
452                            }
453                        }
454
455                        assertDependencyValid( validationContext, impl, d );
456                    }
457                }
458
459                if ( impl.getImplementations() != null )
460                {
461                    final Set<String> effImplementationReferences =
462                        imodel.getImplementationReferenceIdentifiers( impl.getIdentifier() );
463
464                    for ( final String effImplementationReference : effImplementationReferences )
465                    {
466                        final Implementation ancestorImplementation =
467                            validationContext.getModules().getImplementation( effImplementationReference );
468
469                        if ( ancestorImplementation != null && ancestorImplementation.isFinal() )
470                        {
471                            final Module moduleOfFinal = validationContext.getModules().getModuleOfImplementation(
472                                ancestorImplementation.getIdentifier() );
473
474                            addDetail( validationContext.getReport(),
475                                       "IMPLEMENTATION_IMPLEMENTATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
476                                       new ObjectFactory().createImplementation( impl ),
477                                       "implementationFinalImplementationConstraint", impl.getIdentifier(),
478                                       moduleOfImpl.getName(), ancestorImplementation.getIdentifier(),
479                                       moduleOfFinal.getName() );
480
481                        }
482                    }
483
484                    for ( int j = 0, s1 = impl.getImplementations().getImplementation().size(); j < s1; j++ )
485                    {
486                        final Implementation pi = impl.getImplementations().getImplementation().get( j );
487
488                        addDetail( validationContext.getReport(),
489                                   "IMPLEMENTATION_IMPLEMENTATION_DECLARATION_CONSTRAINT", Level.SEVERE,
490                                   new ObjectFactory().createImplementation( impl ),
491                                   "implementationImplementationDeclarationConstraint", impl.getIdentifier(),
492                                   moduleOfImpl.getName(), pi.getIdentifier() );
493
494                    }
495
496                    for ( int j = 0, s1 = impl.getImplementations().getReference().size(); j < s1; j++ )
497                    {
498                        final ImplementationReference r = impl.getImplementations().getReference().get( j );
499
500                        final Set<InheritanceModel.Node<ImplementationReference>> effReferences =
501                            imodel.getImplementationReferenceNodes( impl.getIdentifier(), r.getIdentifier() );
502
503                        for ( final InheritanceModel.Node<ImplementationReference> effReference : effReferences )
504                        {
505                            final Set<InheritanceModel.Node<ImplementationReference>> overriddenReferences =
506                                modifiableSet( effReference.getOverriddenNodes() );
507
508                            if ( r.isOverride() && overriddenReferences.isEmpty() )
509                            {
510                                addDetail( validationContext.getReport(),
511                                           "IMPLEMENTATION_IMPLEMENTATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
512                                           new ObjectFactory().createImplementation( impl ),
513                                           "implementationImplementationOverrideConstraint", impl.getIdentifier(),
514                                           moduleOfImpl.getName(), r.getIdentifier() );
515
516                            }
517
518                            if ( !( r.isOverride() || overriddenReferences.isEmpty() ) )
519                            {
520                                for ( final InheritanceModel.Node<ImplementationReference> overriddenReference :
521                                      overriddenReferences )
522                                {
523                                    Implementation overriddenImplementation = overriddenReference.getImplementation();
524                                    if ( overriddenReference.getClassDeclaration() != null )
525                                    {
526                                        overriddenImplementation = overriddenReference.getClassDeclaration();
527                                    }
528
529                                    final Module moduleOfReference =
530                                        validationContext.getModules().getModuleOfImplementation(
531                                        overriddenImplementation.getIdentifier() );
532
533                                    addDetail( validationContext.getReport(),
534                                               "IMPLEMENTATION_IMPLEMENTATION_REFERENCE_OVERRIDE_WARNING",
535                                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
536                                               "implementationImplementationOverrideWarning", impl.getIdentifier(),
537                                               moduleOfImpl.getName(), r.getIdentifier(),
538                                               overriddenImplementation.getIdentifier(),
539                                               moduleOfReference.getName(),
540                                               getNodePathString( overriddenReference ) );
541
542                                }
543                            }
544
545                            retainFinalNodes( overriddenReferences );
546
547                            for ( final InheritanceModel.Node<ImplementationReference> overriddenReference :
548                                  overriddenReferences )
549                            {
550                                Implementation overriddenImplementation = overriddenReference.getImplementation();
551                                if ( overriddenReference.getClassDeclaration() != null )
552                                {
553                                    overriddenImplementation = overriddenReference.getClassDeclaration();
554                                }
555
556                                final Module moduleOfReference =
557                                    validationContext.getModules().getModuleOfImplementation(
558                                    overriddenImplementation.getIdentifier() );
559
560                                addDetail( validationContext.getReport(),
561                                           "IMPLEMENTATION_IMPLEMENTATION_REFERENCE_INHERITANCE_CONSTRAINT",
562                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
563                                           "implementationFinalImplementatioReferenceConstraint", impl.getIdentifier(),
564                                           moduleOfImpl.getName(), r.getIdentifier(),
565                                           overriddenImplementation.getIdentifier(),
566                                           moduleOfReference.getName(), getNodePathString( overriddenReference ) );
567
568                            }
569                        }
570                    }
571                }
572
573                if ( impl.getMessages() != null )
574                {
575                    for ( int j = 0, s1 = impl.getMessages().getMessage().size(); j < s1; j++ )
576                    {
577                        final Message m = impl.getMessages().getMessage().get( j );
578
579                        if ( impl.getMessages().getReference( m.getName() ) != null )
580                        {
581                            addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGES_UNIQUENESS_CONSTRAINT",
582                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
583                                       "implementationMessagesUniquenessConstraint", impl.getIdentifier(),
584                                       moduleOfImpl.getName(), m.getName() );
585
586                        }
587
588                        if ( m.getTemplate() != null )
589                        {
590                            for ( int k = 0, s2 = m.getTemplate().getText().size(); k < s2; k++ )
591                            {
592                                final Text t = m.getTemplate().getText().get( k );
593
594                                try
595                                {
596                                    new MessageFormat( t.getValue(), new Locale( t.getLanguage() ) );
597                                }
598                                catch ( final IllegalArgumentException e )
599                                {
600                                    final String message = getMessage( e );
601
602                                    if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
603                                    {
604                                        validationContext.getModelContext().log( Level.FINE, message, e );
605                                    }
606
607                                    addDetail( validationContext.getReport(),
608                                               "IMPLEMENTATION_MESSAGE_TEMPLATE_CONSTRAINT", Level.SEVERE,
609                                               new ObjectFactory().createImplementation( impl ),
610                                               "implementationMessageTemplateConstraint", impl.getIdentifier(),
611                                               moduleOfImpl.getName(), m.getName(), t.getValue(),
612                                               message != null && message.length() > 0 ? " " + message : "" );
613
614                                }
615                            }
616                        }
617
618                        final Set<InheritanceModel.Node<Message>> effMessages =
619                            imodel.getMessageNodes( impl.getIdentifier(), m.getName() );
620
621                        for ( final InheritanceModel.Node<Message> effMessage : effMessages )
622                        {
623                            final Set<InheritanceModel.Node<Message>> overriddenMessages =
624                                modifiableSet( effMessage.getOverriddenNodes() );
625
626                            if ( m.isOverride() && overriddenMessages.isEmpty() )
627                            {
628                                addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT",
629                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
630                                           "implementationMessageOverrideConstraint", impl.getIdentifier(),
631                                           moduleOfImpl.getName(), m.getName() );
632
633                            }
634
635                            if ( !( m.isOverride() || overriddenMessages.isEmpty() ) )
636                            {
637                                for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
638                                {
639                                    Implementation overriddenImplementation = overriddenMessage.getImplementation();
640                                    if ( overriddenMessage.getClassDeclaration() != null )
641                                    {
642                                        overriddenImplementation = overriddenMessage.getClassDeclaration();
643                                    }
644
645                                    final Module moduleOfMessage =
646                                        validationContext.getModules().getModuleOfImplementation(
647                                        overriddenImplementation.getIdentifier() );
648
649                                    addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_WARNING",
650                                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
651                                               "implementationMessageOverrideWarning", impl.getIdentifier(),
652                                               moduleOfImpl.getName(), m.getName(),
653                                               overriddenImplementation.getIdentifier(),
654                                               moduleOfMessage.getName(), getNodePathString( overriddenMessage ) );
655
656                                }
657                            }
658
659                            retainFinalNodes( overriddenMessages );
660
661                            for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
662                            {
663                                Implementation overriddenImplementation = overriddenMessage.getImplementation();
664                                if ( overriddenMessage.getClassDeclaration() != null )
665                                {
666                                    overriddenImplementation = overriddenMessage.getClassDeclaration();
667                                }
668
669                                final Module moduleOfMessage = validationContext.getModules().getModuleOfImplementation(
670                                    overriddenImplementation.getIdentifier() );
671
672                                addDetail( validationContext.getReport(),
673                                           "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT",
674                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
675                                           "implementationMessageFinalConstraint", impl.getIdentifier(),
676                                           moduleOfImpl.getName(), m.getName(),
677                                           overriddenImplementation.getIdentifier(),
678                                           moduleOfMessage.getName(), getNodePathString( overriddenMessage ) );
679
680                            }
681                        }
682                    }
683
684                    for ( int j = 0, s1 = impl.getMessages().getReference().size(); j < s1; j++ )
685                    {
686                        final MessageReference r = impl.getMessages().getReference().get( j );
687
688                        final Set<InheritanceModel.Node<Message>> effMessages =
689                            imodel.getMessageNodes( impl.getIdentifier(), r.getName() );
690
691                        for ( final InheritanceModel.Node<Message> effMessage : effMessages )
692                        {
693                            final Set<InheritanceModel.Node<Message>> overriddenMessages =
694                                modifiableSet( effMessage.getOverriddenNodes() );
695
696                            if ( r.isOverride() && overriddenMessages.isEmpty() )
697                            {
698                                addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT",
699                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
700                                           "implementationMessageOverrideConstraint", impl.getIdentifier(),
701                                           moduleOfImpl.getName(), r.getName() );
702
703                            }
704
705                            if ( !( r.isOverride() || overriddenMessages.isEmpty() ) )
706                            {
707                                for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
708                                {
709                                    Implementation overriddenImplementation = overriddenMessage.getImplementation();
710                                    if ( overriddenMessage.getClassDeclaration() != null )
711                                    {
712                                        overriddenImplementation = overriddenMessage.getClassDeclaration();
713                                    }
714
715                                    final Module moduleOfMessage =
716                                        validationContext.getModules().getModuleOfImplementation(
717                                        overriddenImplementation.getIdentifier() );
718
719                                    addDetail( validationContext.getReport(), "IMPLEMENTATION_MESSAGE_OVERRIDE_WARNING",
720                                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
721                                               "implementationMessageOverrideWarning", impl.getIdentifier(),
722                                               moduleOfImpl.getName(), r.getName(),
723                                               overriddenImplementation.getIdentifier(),
724                                               moduleOfMessage.getName(), getNodePathString( overriddenMessage ) );
725
726                                }
727                            }
728
729                            retainFinalNodes( overriddenMessages );
730
731                            for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
732                            {
733                                Implementation overriddenImplementation = overriddenMessage.getImplementation();
734                                if ( overriddenMessage.getClassDeclaration() != null )
735                                {
736                                    overriddenImplementation = overriddenMessage.getClassDeclaration();
737                                }
738
739                                final Module moduleOfMessage =
740                                    validationContext.getModules().getModuleOfImplementation(
741                                    overriddenImplementation.getIdentifier() );
742
743                                addDetail( validationContext.getReport(),
744                                           "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT",
745                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
746                                           "implementationMessageFinalConstraint", impl.getIdentifier(),
747                                           moduleOfImpl.getName(), r.getName(),
748                                           overriddenImplementation.getIdentifier(),
749                                           moduleOfMessage.getName(), getNodePathString( overriddenMessage ) );
750
751                            }
752                        }
753                    }
754                }
755
756                if ( impl.getProperties() != null )
757                {
758                    for ( int j = 0, s1 = impl.getProperties().getProperty().size(); j < s1; j++ )
759                    {
760                        final Property p = impl.getProperties().getProperty().get( j );
761
762                        if ( impl.getProperties().getReference( p.getName() ) != null )
763                        {
764                            addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTIES_UNIQUENESS_CONSTRAINT",
765                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
766                                       "implementationPropertiesUniquenessConstraint", impl.getIdentifier(),
767                                       moduleOfImpl.getName(), p.getName() );
768
769                        }
770
771                        if ( p.getValue() != null && p.getAny() != null )
772                        {
773                            addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_VALUE_CONSTRAINT",
774                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
775                                       "implementationPropertyValueConstraint", impl.getIdentifier(),
776                                       moduleOfImpl.getName(), p.getName() );
777
778                        }
779
780                        if ( p.getAny() != null && p.getType() == null )
781                        {
782                            addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_TYPE_CONSTRAINT",
783                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
784                                       "implementationPropertyTypeConstraint", impl.getIdentifier(),
785                                       moduleOfImpl.getName(), p.getName() );
786
787                        }
788
789                        try
790                        {
791                            p.getJavaValue( validationContext.getModelContext().getClassLoader() );
792                        }
793                        catch ( final PropertyException e )
794                        {
795                            final String message = getMessage( e );
796
797                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
798                            {
799                                validationContext.getModelContext().log( Level.FINE, message, e );
800                            }
801
802                            addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_JAVA_VALUE_CONSTRAINT",
803                                       Level.SEVERE, new ObjectFactory().createImplementation( impl ),
804                                       "implementationPropertyJavaValueConstraint", impl.getIdentifier(),
805                                       moduleOfImpl.getName(), p.getName(),
806                                       message != null && message.length() > 0 ? " " + message : "" );
807
808                        }
809
810                        final Set<InheritanceModel.Node<Property>> effProperties =
811                            imodel.getPropertyNodes( impl.getIdentifier(), p.getName() );
812
813                        for ( final InheritanceModel.Node<Property> effProperty : effProperties )
814                        {
815                            final Set<InheritanceModel.Node<Property>> overriddenProperties =
816                                modifiableSet( effProperty.getOverriddenNodes() );
817
818                            if ( p.isOverride() && overriddenProperties.isEmpty() )
819                            {
820                                addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT",
821                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
822                                           "implementationPropertyOverrideConstraint", impl.getIdentifier(),
823                                           moduleOfImpl.getName(), p.getName() );
824
825                            }
826
827                            if ( !( p.isOverride() || overriddenProperties.isEmpty() ) )
828                            {
829                                for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
830                                {
831                                    if ( overriddenProperty.getSpecification() != null )
832                                    {
833                                        final Module moduleOfProperty =
834                                            validationContext.getModules().getModuleOfSpecification(
835                                            overriddenProperty.getSpecification().getIdentifier() );
836
837                                        addDetail( validationContext.getReport(),
838                                                   "IMPLEMENTATION_PROPERTY_OVERRIDE_WARNING", Level.WARNING,
839                                                   new ObjectFactory().createImplementation( impl ),
840                                                   "implementationSpecificationPropertyOverrideWarning",
841                                                   impl.getIdentifier(), moduleOfImpl.getName(), p.getName(),
842                                                   overriddenProperty.getSpecification().getIdentifier(),
843                                                   moduleOfProperty.getName(),
844                                                   getNodePathString( overriddenProperty ) );
845
846                                    }
847                                    else
848                                    {
849                                        Implementation overriddenImplementation =
850                                            overriddenProperty.getImplementation();
851
852                                        if ( overriddenProperty.getClassDeclaration() != null )
853                                        {
854                                            overriddenImplementation = overriddenProperty.getClassDeclaration();
855                                        }
856
857                                        final Module moduleOfProperty =
858                                            validationContext.getModules().getModuleOfImplementation(
859                                            overriddenImplementation.getIdentifier() );
860
861                                        addDetail( validationContext.getReport(),
862                                                   "IMPLEMENTATION_PROPERTY_OVERRIDE_WARNING", Level.WARNING,
863                                                   new ObjectFactory().createImplementation( impl ),
864                                                   "implementationPropertyOverrideWarning", impl.getIdentifier(),
865                                                   moduleOfImpl.getName(), p.getName(),
866                                                   overriddenImplementation.getIdentifier(),
867                                                   moduleOfProperty.getName(),
868                                                   getNodePathString( overriddenProperty ) );
869
870                                    }
871                                }
872                            }
873
874                            retainFinalNodes( overriddenProperties );
875
876                            for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
877                            {
878                                Implementation overriddenImplementation = overriddenProperty.getImplementation();
879                                if ( overriddenProperty.getClassDeclaration() != null )
880                                {
881                                    overriddenImplementation = overriddenProperty.getClassDeclaration();
882                                }
883
884                                final Module moduleOfProperty =
885                                    validationContext.getModules().getModuleOfImplementation(
886                                    overriddenImplementation.getIdentifier() );
887
888                                addDetail( validationContext.getReport(),
889                                           "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT",
890                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
891                                           "implementationPropertyFinalConstraint", impl.getIdentifier(),
892                                           moduleOfImpl.getName(), p.getName(),
893                                           overriddenImplementation.getIdentifier(),
894                                           moduleOfProperty.getName(), getNodePathString( overriddenProperty ) );
895
896                            }
897                        }
898                    }
899
900                    for ( int j = 0, s1 = impl.getProperties().getReference().size(); j < s1; j++ )
901                    {
902                        final PropertyReference r = impl.getProperties().getReference().get( j );
903
904                        final Set<InheritanceModel.Node<Property>> effProperties =
905                            imodel.getPropertyNodes( impl.getIdentifier(), r.getName() );
906
907                        for ( final InheritanceModel.Node<Property> effProperty : effProperties )
908                        {
909                            final Set<InheritanceModel.Node<Property>> overriddenProperties =
910                                modifiableSet( effProperty.getOverriddenNodes() );
911
912                            if ( r.isOverride() && overriddenProperties.isEmpty() )
913                            {
914                                addDetail( validationContext.getReport(), "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT",
915                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
916                                           "implementationPropertyOverrideConstraint", impl.getIdentifier(),
917                                           moduleOfImpl.getName(), r.getName() );
918
919                            }
920
921                            if ( !( r.isOverride() || overriddenProperties.isEmpty() ) )
922                            {
923                                for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
924                                {
925                                    Implementation overriddenImplementation = overriddenProperty.getImplementation();
926                                    if ( overriddenProperty.getClassDeclaration() != null )
927                                    {
928                                        overriddenImplementation = overriddenProperty.getClassDeclaration();
929                                    }
930
931                                    final Module moduleOfProperty =
932                                        validationContext.getModules().getModuleOfImplementation(
933                                        overriddenImplementation.getIdentifier() );
934
935                                    addDetail( validationContext.getReport(),
936                                               "IMPLEMENTATION_PROPERTY_OVERRIDE_WARNING", Level.WARNING,
937                                               new ObjectFactory().createImplementation( impl ),
938                                               "implementationPropertyOverrideWarning", impl.getIdentifier(),
939                                               moduleOfImpl.getName(), r.getName(),
940                                               overriddenImplementation.getIdentifier(),
941                                               moduleOfProperty.getName(), getNodePathString( overriddenProperty ) );
942
943                                }
944                            }
945
946                            retainFinalNodes( overriddenProperties );
947
948                            for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
949                            {
950                                Implementation overriddenImplementation = overriddenProperty.getImplementation();
951                                if ( overriddenProperty.getClassDeclaration() != null )
952                                {
953                                    overriddenImplementation = overriddenProperty.getClassDeclaration();
954                                }
955
956                                final Module moduleOfProperty =
957                                    validationContext.getModules().getModuleOfImplementation(
958                                    overriddenImplementation.getIdentifier() );
959
960                                addDetail( validationContext.getReport(),
961                                           "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT",
962                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
963                                           "implementationPropertyFinalConstraint", impl.getIdentifier(),
964                                           moduleOfImpl.getName(), r.getName(),
965                                           overriddenImplementation.getIdentifier(),
966                                           moduleOfProperty.getName(), getNodePathString( overriddenProperty ) );
967
968                            }
969                        }
970                    }
971                }
972
973                if ( impl.getSpecifications() != null )
974                {
975                    for ( int j = 0, s1 = impl.getSpecifications().getSpecification().size(); j < s1; j++ )
976                    {
977                        final Specification s = impl.getSpecifications().getSpecification().get( j );
978
979                        addDetail( validationContext.getReport(), "IMPLEMENTATION_SPECIFICATION_DECLARATION_CONSTRAINT",
980                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
981                                   "implementationSpecificationDeclarationConstraint", impl.getIdentifier(),
982                                   moduleOfImpl.getName(), s.getIdentifier() );
983
984                    }
985
986                    for ( int j = 0, s1 = impl.getSpecifications().getReference().size(); j < s1; j++ )
987                    {
988                        final SpecificationReference r = impl.getSpecifications().getReference().get( j );
989
990                        final Set<InheritanceModel.Node<SpecificationReference>> effReferences =
991                            imodel.getSpecificationReferenceNodes( impl.getIdentifier(), r.getIdentifier() );
992
993                        for ( final InheritanceModel.Node<SpecificationReference> effReference : effReferences )
994                        {
995                            final Set<InheritanceModel.Node<SpecificationReference>> overriddenReferences =
996                                modifiableSet( effReference.getOverriddenNodes() );
997
998                            if ( r.isOverride() && overriddenReferences.isEmpty() )
999                            {
1000                                addDetail( validationContext.getReport(),
1001                                           "IMPLEMENTATION_SPECIFICATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
1002                                           new ObjectFactory().createImplementation( impl ),
1003                                           "implementationSpecificationOverrideConstraint", impl.getIdentifier(),
1004                                           moduleOfImpl.getName(), r.getIdentifier() );
1005
1006                            }
1007
1008                            if ( !( r.isOverride() || overriddenReferences.isEmpty() ) )
1009                            {
1010                                for ( final InheritanceModel.Node<SpecificationReference> overriddenReference :
1011                                      overriddenReferences )
1012                                {
1013                                    Implementation overriddenImplementation = overriddenReference.getImplementation();
1014                                    if ( overriddenReference.getClassDeclaration() != null )
1015                                    {
1016                                        overriddenImplementation = overriddenReference.getClassDeclaration();
1017                                    }
1018
1019                                    final Module moduleOfReference =
1020                                        validationContext.getModules().getModuleOfImplementation(
1021                                        overriddenImplementation.getIdentifier() );
1022
1023                                    addDetail( validationContext.getReport(),
1024                                               "IMPLEMENTATION_SPECIFICATION_REFERENCE_OVERRIDE_WARNING",
1025                                               Level.WARNING, new ObjectFactory().createImplementation( impl ),
1026                                               "implementationSpecificationOverrideWarning", impl.getIdentifier(),
1027                                               moduleOfImpl.getName(), r.getIdentifier(),
1028                                               overriddenImplementation.getIdentifier(),
1029                                               moduleOfReference.getName(), getNodePathString( overriddenReference ) );
1030
1031                                }
1032                            }
1033
1034                            retainFinalNodes( overriddenReferences );
1035
1036                            for ( final InheritanceModel.Node<SpecificationReference> overriddenReference :
1037                                  overriddenReferences )
1038                            {
1039                                Implementation overriddenImplementation = overriddenReference.getImplementation();
1040                                if ( overriddenReference.getClassDeclaration() != null )
1041                                {
1042                                    overriddenImplementation = overriddenReference.getClassDeclaration();
1043                                }
1044
1045                                final Module moduleOfReference =
1046                                    validationContext.getModules().getModuleOfImplementation(
1047                                    overriddenImplementation.getIdentifier() );
1048
1049                                addDetail( validationContext.getReport(),
1050                                           "IMPLEMENTATION_SPECIFICATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
1051                                           new ObjectFactory().createImplementation( impl ),
1052                                           "implementationSpecificationFinalConstraint", impl.getIdentifier(),
1053                                           moduleOfImpl.getName(), r.getIdentifier(),
1054                                           overriddenImplementation.getIdentifier(),
1055                                           moduleOfReference.getName(), getNodePathString( overriddenReference ) );
1056
1057                            }
1058                        }
1059                    }
1060                }
1061
1062                if ( !impl.getAny().isEmpty() )
1063                {
1064                    for ( int j = 0, s1 = impl.getAny().size(); j < s1; j++ )
1065                    {
1066                        final Object any = impl.getAny().get( j );
1067
1068                        if ( any instanceof JAXBElement<?> )
1069                        {
1070                            final JAXBElement<?> jaxbElement = (JAXBElement<?>) any;
1071                            boolean overrideNode = false;
1072
1073                            if ( jaxbElement.getValue() instanceof Inheritable )
1074                            {
1075                                overrideNode = ( (Inheritable) jaxbElement.getValue() ).isOverride();
1076                            }
1077
1078                            final Set<InheritanceModel.Node<JAXBElement<?>>> effElements =
1079                                imodel.getJaxbElementNodes( impl.getIdentifier(), jaxbElement.getName() );
1080
1081                            for ( final InheritanceModel.Node<JAXBElement<?>> effElement : effElements )
1082                            {
1083                                final Set<InheritanceModel.Node<JAXBElement<?>>> overriddenElements =
1084                                    modifiableSet( effElement.getOverriddenNodes() );
1085
1086                                if ( overrideNode && overriddenElements.isEmpty() )
1087                                {
1088                                    addDetail( validationContext.getReport(),
1089                                               "IMPLEMENTATION_JAXB_ELEMENT_OVERRIDE_CONSTRAINT",
1090                                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1091                                               "implementationJaxbElementOverrideConstraint", impl.getIdentifier(),
1092                                               moduleOfImpl.getName(), jaxbElement.getName().toString() );
1093
1094                                }
1095
1096                                if ( !( overrideNode || overriddenElements.isEmpty() ) )
1097                                {
1098                                    for ( final InheritanceModel.Node<JAXBElement<?>> overriddenElement :
1099                                          overriddenElements )
1100                                    {
1101                                        Implementation overriddenImplementation = overriddenElement.getImplementation();
1102                                        if ( overriddenElement.getClassDeclaration() != null )
1103                                        {
1104                                            overriddenImplementation = overriddenElement.getClassDeclaration();
1105                                        }
1106
1107                                        final Module moduleOfElement =
1108                                            validationContext.getModules().getModuleOfImplementation(
1109                                            overriddenElement.getImplementation().getIdentifier() );
1110
1111                                        addDetail( validationContext.getReport(),
1112                                                   "IMPLEMENTATION_JAXB_ELEMENT_OVERRIDE_WARNING",
1113                                                   Level.WARNING, new ObjectFactory().createImplementation( impl ),
1114                                                   "implementationJaxbElementOverrideWarning", impl.getIdentifier(),
1115                                                   moduleOfImpl.getName(), jaxbElement.getName().toString(),
1116                                                   overriddenImplementation.getIdentifier(),
1117                                                   moduleOfElement.getName(), getNodePathString( overriddenElement ) );
1118
1119                                    }
1120                                }
1121
1122                                retainFinalNodes( overriddenElements );
1123
1124                                for ( final InheritanceModel.Node<JAXBElement<?>> overriddenElement :
1125                                      overriddenElements )
1126                                {
1127                                    Implementation overriddenImplementation = overriddenElement.getImplementation();
1128                                    if ( overriddenElement.getClassDeclaration() != null )
1129                                    {
1130                                        overriddenImplementation = overriddenElement.getClassDeclaration();
1131                                    }
1132
1133                                    final Module moduleOfElement =
1134                                        validationContext.getModules().getModuleOfImplementation(
1135                                        overriddenImplementation.getIdentifier() );
1136
1137                                    addDetail( validationContext.getReport(),
1138                                               "IMPLEMENTATION_JAXB_ELEMENT_INHERITANCE_CONSTRAINT",
1139                                               Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1140                                               "implementationJaxbElementFinalConstraint", impl.getIdentifier(),
1141                                               moduleOfImpl.getName(), jaxbElement.getName().toString(),
1142                                               overriddenImplementation.getIdentifier(),
1143                                               moduleOfElement.getName(), getNodePathString( overriddenElement ) );
1144
1145                                }
1146                            }
1147                        }
1148                    }
1149                }
1150
1151                final Set<String> dependencyNames = imodel.getDependencyNames( impl.getIdentifier() );
1152
1153                for ( String dependencyName : dependencyNames )
1154                {
1155                    final Set<InheritanceModel.Node<Dependency>> dependencyNodes =
1156                        imodel.getDependencyNodes( impl.getIdentifier(), dependencyName );
1157
1158                    if ( dependencyNodes.size() > 1 )
1159                    {
1160                        addDetail( validationContext.getReport(),
1161                                   "IMPLEMENTATION_DEPENDENCY_MULTIPLE_INHERITANCE_CONSTRAINT",
1162                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1163                                   "implementationMultipleInheritanceDependencyConstraint", impl.getIdentifier(),
1164                                   moduleOfImpl.getName(), dependencyName, getNodeListPathString( dependencyNodes ) );
1165
1166                    }
1167                }
1168
1169                final Set<String> messageNames = imodel.getMessageNames( impl.getIdentifier() );
1170
1171                for ( String messageName : messageNames )
1172                {
1173                    final Set<InheritanceModel.Node<Message>> messageNodes =
1174                        imodel.getMessageNodes( impl.getIdentifier(), messageName );
1175
1176                    if ( messageNodes.size() > 1 )
1177                    {
1178                        addDetail( validationContext.getReport(),
1179                                   "IMPLEMENTATION_MESSAGE_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1180                                   new ObjectFactory().createImplementation( impl ),
1181                                   "implementationMultipleInheritanceMessageConstraint", impl.getIdentifier(),
1182                                   moduleOfImpl.getName(), messageName, getNodeListPathString( messageNodes ) );
1183
1184                    }
1185                }
1186
1187                final Set<String> propertyNames = imodel.getPropertyNames( impl.getIdentifier() );
1188
1189                for ( String propertyName : propertyNames )
1190                {
1191                    final Set<InheritanceModel.Node<Property>> propertyNodes =
1192                        imodel.getPropertyNodes( impl.getIdentifier(), propertyName );
1193
1194                    if ( propertyNodes.size() > 1 )
1195                    {
1196                        addDetail( validationContext.getReport(),
1197                                   "IMPLEMENTATION_PROPERTY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1198                                   new ObjectFactory().createImplementation( impl ),
1199                                   "implementationMultipleInheritancePropertyConstraint", impl.getIdentifier(),
1200                                   moduleOfImpl.getName(), propertyName, getNodeListPathString( propertyNodes ) );
1201
1202                    }
1203                }
1204
1205                final Set<String> specificationReferenceIdentifiers =
1206                    imodel.getSpecificationReferenceIdentifiers( impl.getIdentifier() );
1207
1208                for ( String specificationRefereneIdentifier : specificationReferenceIdentifiers )
1209                {
1210                    final Set<InheritanceModel.Node<SpecificationReference>> specificationReferenceNodes =
1211                        imodel.getSpecificationReferenceNodes( impl.getIdentifier(), specificationRefereneIdentifier );
1212
1213                    if ( specificationReferenceNodes.size() > 1 )
1214                    {
1215                        addDetail( validationContext.getReport(),
1216                                   "IMPLEMENTATION_SPECIFICATION_MULTIPLE_INHERITANCE_CONSTRAINT",
1217                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1218                                   "implementationMultipleInheritanceSpecificationConstraint",
1219                                   impl.getIdentifier(), moduleOfImpl.getName(), specificationRefereneIdentifier,
1220                                   getNodeListPathString( specificationReferenceNodes ) );
1221
1222                    }
1223                }
1224
1225                final Set<QName> xmlElementNames = imodel.getXmlElementNames( impl.getIdentifier() );
1226
1227                for ( QName xmlElementName : xmlElementNames )
1228                {
1229                    final Set<InheritanceModel.Node<Element>> xmlElementNodes =
1230                        imodel.getXmlElementNodes( impl.getIdentifier(), xmlElementName );
1231
1232                    if ( xmlElementNodes.size() > 1 )
1233                    {
1234                        addDetail( validationContext.getReport(),
1235                                   "IMPLEMENTATION_XML_ELEMENT_MULTIPLE_INHERITANCE_CONSTRAINT",
1236                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1237                                   "implementationMultipleInheritanceXmlElementConstraint",
1238                                   impl.getIdentifier(), moduleOfImpl.getName(), xmlElementName.toString(),
1239                                   getNodeListPathString( xmlElementNodes ) );
1240
1241                    }
1242                }
1243
1244                final Set<QName> jaxbElementNames = imodel.getJaxbElementNames( impl.getIdentifier() );
1245
1246                for ( QName jaxbElementName : jaxbElementNames )
1247                {
1248                    final Set<InheritanceModel.Node<JAXBElement<?>>> jaxbElementNodes =
1249                        imodel.getJaxbElementNodes( impl.getIdentifier(), jaxbElementName );
1250
1251                    if ( jaxbElementNodes.size() > 1 )
1252                    {
1253                        addDetail( validationContext.getReport(),
1254                                   "IMPLEMENTATION_JAXB_ELEMENT_MULTIPLE_INHERITANCE_CONSTRAINT",
1255                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1256                                   "implementationMultipleInheritanceJaxbElementConstraint",
1257                                   impl.getIdentifier(), moduleOfImpl.getName(), jaxbElementName.toString(),
1258                                   getNodeListPathString( jaxbElementNodes ) );
1259
1260                    }
1261                }
1262
1263                final Set<String> implementationReferenceIdentifiers =
1264                    imodel.getImplementationReferenceIdentifiers( impl.getIdentifier() );
1265
1266                for ( String implementationReferenceIdentifier : implementationReferenceIdentifiers )
1267                {
1268                    final Set<InheritanceModel.Node<ImplementationReference>> implementationReferenceNodes =
1269                        imodel.getImplementationReferenceNodes( impl.getIdentifier(),
1270                                                                implementationReferenceIdentifier );
1271
1272                    for ( final InheritanceModel.Node<ImplementationReference> node : implementationReferenceNodes )
1273                    {
1274                        final ImplementationReference r = node.getModelObject();
1275
1276                        final Implementation referenced =
1277                            validationContext.getModules().getImplementation( r.getIdentifier() );
1278
1279                        final Module moduleOfReferenced =
1280                            validationContext.getModules().getModuleOfImplementation( referenced.getIdentifier() );
1281
1282                        if ( r.getVersion() != null && referenced != null )
1283                        {
1284                            if ( referenced.getVersion() == null )
1285                            {
1286                                addDetail( validationContext.getReport(),
1287                                           "IMPLEMENTATION_IMPLEMENTATION_VERSIONING_CONSTRAINT", Level.SEVERE,
1288                                           new ObjectFactory().createImplementation( impl ),
1289                                           "implementationImplementationVersioningConstraint",
1290                                           impl.getIdentifier(), moduleOfImpl.getName(), r.getIdentifier(),
1291                                           moduleOfReferenced.getName() );
1292
1293                            }
1294                            else
1295                            {
1296                                try
1297                                {
1298                                    if ( VersionParser.compare( r.getVersion(), referenced.getVersion() ) > 0 )
1299                                    {
1300                                        addDetail( validationContext.getReport(),
1301                                                   "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_CONSTRAINT",
1302                                                   Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1303                                                   "implementationInheritanceCompatibilityConstraint",
1304                                                   impl.getIdentifier(), moduleOfImpl.getName(),
1305                                                   referenced.getIdentifier(), moduleOfReferenced.getName(),
1306                                                   r.getVersion(), referenced.getVersion() );
1307
1308                                    }
1309                                }
1310                                catch ( final ParseException ex )
1311                                {
1312                                    final String message = getMessage( ex );
1313
1314                                    if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1315                                    {
1316                                        validationContext.getModelContext().log( Level.FINE, message, ex );
1317                                    }
1318
1319                                    addDetail(
1320                                        validationContext.getReport(),
1321                                        "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_VERSIONING_PARSE_EXCEPTION",
1322                                        Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1323                                        "implementationInheritanceCompatibilityParseException",
1324                                        impl.getIdentifier(), moduleOfImpl.getName(), r.getIdentifier(),
1325                                        moduleOfReferenced.getName(), r.getVersion(),
1326                                        message != null && message.length() > 0 ? " " + message : "" );
1327
1328                                }
1329                                catch ( final TokenMgrError ex )
1330                                {
1331                                    final String message = getMessage( ex );
1332
1333                                    if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1334                                    {
1335                                        validationContext.getModelContext().log( Level.FINE, message, ex );
1336                                    }
1337
1338                                    addDetail(
1339                                        validationContext.getReport(),
1340                                        "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_VERSIONING_TOKEN_MANAGER_ERROR",
1341                                        Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1342                                        "implementationInheritanceCompatiblityVersioningTokenManagerError",
1343                                        impl.getIdentifier(), moduleOfImpl.getName(), r.getIdentifier(),
1344                                        moduleOfReferenced.getName(), r.getVersion(),
1345                                        message != null && message.length() > 0 ? " " + message : "" );
1346
1347                                }
1348                            }
1349                        }
1350                    }
1351                }
1352
1353                assertImplementationSpecificationCompatibility( validationContext, impl );
1354            }
1355        }
1356    }
1357
1358    private static void assertSpecificationsValid( final ValidationContext validationContext )
1359    {
1360        final Specifications specifications = validationContext.getModules().getSpecifications();
1361        final Map<String, Specification> specificationClassDeclarations = new HashMap<String, Specification>();
1362
1363        if ( specifications != null )
1364        {
1365            for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
1366            {
1367                final Specification s = specifications.getSpecification().get( i );
1368                final Implementations impls = validationContext.getModules().getImplementations( s.getIdentifier() );
1369                final Module moduleOfS = validationContext.getModules().getModuleOfSpecification( s.getIdentifier() );
1370
1371                if ( s.isClassDeclaration() )
1372                {
1373                    if ( s.getClazz() == null )
1374                    {
1375                        addDetail( validationContext.getReport(), "SPECIFICATION_CLASS_CONSTRAINT", Level.SEVERE,
1376                                   new ObjectFactory().createSpecification( s ), "specificationClassConstraint",
1377                                   s.getIdentifier(), moduleOfS.getName() );
1378
1379                    }
1380                    else
1381                    {
1382                        final Specification prev = specificationClassDeclarations.get( s.getClazz() );
1383
1384                        if ( prev != null && !prev.getIdentifier().equals( s.getIdentifier() ) )
1385                        {
1386                            final Module moduleOfPrev = validationContext.getModules().getModuleOfSpecification(
1387                                prev.getIdentifier() );
1388
1389                            addDetail( validationContext.getReport(), "SPECIFICATION_CLASS_DECLARATION_CONSTRAINT",
1390                                       Level.SEVERE, new ObjectFactory().createSpecification( s ),
1391                                       "specificationClassDeclarationConstraint", s.getIdentifier(),
1392                                       moduleOfS.getName(), s.getClazz(), prev.getIdentifier(),
1393                                       moduleOfPrev.getName() );
1394
1395                        }
1396                        else
1397                        {
1398                            specificationClassDeclarations.put( s.getClazz(), s );
1399                        }
1400                    }
1401                }
1402
1403                if ( impls != null )
1404                {
1405                    final Map<String, Implementations> map = new HashMap<String, Implementations>();
1406
1407                    for ( int j = 0, s1 = impls.getImplementation().size(); j < s1; j++ )
1408                    {
1409                        final Implementation impl = impls.getImplementation().get( j );
1410                        Implementations implementations = map.get( impl.getName() );
1411
1412                        if ( implementations == null )
1413                        {
1414                            implementations = new Implementations();
1415                            map.put( impl.getName(), implementations );
1416                        }
1417
1418                        implementations.getImplementation().add( impl );
1419                    }
1420
1421                    for ( Map.Entry<String, Implementations> e : map.entrySet() )
1422                    {
1423                        if ( e.getValue().getImplementation().size() > 1 )
1424                        {
1425                            for ( int j = 0, s1 = e.getValue().getImplementation().size(); j < s1; j++ )
1426                            {
1427                                final Implementation impl = e.getValue().getImplementation().get( j );
1428                                final Module moduleOfImpl = validationContext.getModules().getModuleOfImplementation(
1429                                    impl.getIdentifier() );
1430
1431                                addDetail( validationContext.getReport(),
1432                                           "SPECIFICATION_IMPLEMENTATION_NAME_UNIQUENESS_CONSTRAINT",
1433                                           Level.SEVERE, new ObjectFactory().createImplementation( impl ),
1434                                           "specificationImplementationNameConstraint", impl.getIdentifier(),
1435                                           moduleOfImpl.getName(), s.getIdentifier(), moduleOfS.getName(),
1436                                           impl.getName() );
1437
1438                            }
1439                        }
1440                    }
1441
1442                    if ( s.getMultiplicity() == Multiplicity.ONE && impls.getImplementation().size() > 1 )
1443                    {
1444                        for ( int j = 0, s1 = impls.getImplementation().size(); j < s1; j++ )
1445                        {
1446                            final Implementation impl = impls.getImplementation().get( j );
1447                            final Module moduleOfImpl = validationContext.getModules().getModuleOfImplementation(
1448                                impl.getIdentifier() );
1449
1450                            addDetail( validationContext.getReport(),
1451                                       "SPECIFICATION_IMPLEMENTATION_MULTIPLICITY_CONSTRAINT", Level.SEVERE,
1452                                       new ObjectFactory().createImplementation( impl ),
1453                                       "specificationMultiplicityConstraint", impl.getIdentifier(),
1454                                       moduleOfImpl.getName(), s.getIdentifier(), moduleOfS.getName(),
1455                                       s.getMultiplicity() );
1456
1457                        }
1458                    }
1459                }
1460
1461                if ( s.getProperties() != null )
1462                {
1463                    for ( int j = 0, s1 = s.getProperties().getProperty().size(); j < s1; j++ )
1464                    {
1465                        final Property p = s.getProperties().getProperty().get( j );
1466
1467                        if ( p.getValue() != null && p.getAny() != null )
1468                        {
1469                            addDetail( validationContext.getReport(), "SPECIFICATION_PROPERTY_VALUE_CONSTRAINT",
1470                                       Level.SEVERE, new ObjectFactory().createSpecification( s ),
1471                                       "specificationPropertyValueConstraint", s.getIdentifier(),
1472                                       moduleOfS.getName(), p.getName() );
1473
1474                        }
1475
1476                        if ( p.getAny() != null && p.getType() == null )
1477                        {
1478                            addDetail( validationContext.getReport(), "SPECIFICATION_PROPERTY_TYPE_CONSTRAINT",
1479                                       Level.SEVERE, new ObjectFactory().createSpecification( s ),
1480                                       "specificationPropertyTypeConstraint", s.getIdentifier(),
1481                                       moduleOfS.getName(), p.getName() );
1482
1483                        }
1484
1485                        try
1486                        {
1487                            p.getJavaValue( validationContext.getModelContext().getClassLoader() );
1488                        }
1489                        catch ( final PropertyException e )
1490                        {
1491                            final String message = getMessage( e );
1492
1493                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1494                            {
1495                                validationContext.getModelContext().log( Level.FINE, message, e );
1496                            }
1497
1498                            addDetail( validationContext.getReport(), "SPECIFICATION_PROPERTY_JAVA_VALUE_CONSTRAINT",
1499                                       Level.SEVERE, new ObjectFactory().createSpecification( s ),
1500                                       "specificationPropertyJavaValueConstraint", s.getIdentifier(),
1501                                       moduleOfS.getName(), p.getName(),
1502                                       message != null && message.length() > 0 ? " " + message : "" );
1503
1504                        }
1505                    }
1506
1507                    for ( int j = 0, s1 = s.getProperties().getReference().size(); j < s1; j++ )
1508                    {
1509                        final PropertyReference r = s.getProperties().getReference().get( j );
1510
1511                        addDetail( validationContext.getReport(),
1512                                   "SPECIFICATION_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
1513                                   new ObjectFactory().createSpecification( s ),
1514                                   "specificationPropertyReferenceDeclarationConstraint", s.getIdentifier(),
1515                                   moduleOfS.getName(), r.getName() );
1516
1517                    }
1518                }
1519            }
1520        }
1521    }
1522
1523    private static void assertDependencyValid( final ValidationContext validationContext,
1524                                               final Implementation implementation, final Dependency dependency )
1525    {
1526        final Specification s = validationContext.getModules().getSpecification( dependency.getIdentifier() );
1527        final Implementations available =
1528            validationContext.getModules().getImplementations( dependency.getIdentifier() );
1529
1530        final Module moduleOfImpl =
1531            validationContext.getModules().getModuleOfImplementation( implementation.getIdentifier() );
1532
1533        if ( !dependency.isOptional()
1534             && ( available == null || available.getImplementation().isEmpty()
1535                  || ( dependency.getImplementationName() != null
1536                       && available.getImplementationByName( dependency.getImplementationName() ) == null ) ) )
1537        {
1538            addDetail( validationContext.getReport(), "IMPLEMENTATION_MANDATORY_DEPENDENCY_CONSTRAINT", Level.SEVERE,
1539                       new ObjectFactory().createImplementation( implementation ),
1540                       "implementationMandatoryDependencyConstraint", implementation.getIdentifier(),
1541                       moduleOfImpl.getName(), dependency.getName() );
1542
1543        }
1544
1545        if ( s != null )
1546        {
1547            final Module moduleOfS = validationContext.getModules().getModuleOfSpecification( s.getIdentifier() );
1548
1549            if ( s.getClazz() == null )
1550            {
1551                addDetail( validationContext.getReport(), "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_CLASS_CONSTRAINT",
1552                           Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1553                           "implementationDependencySpecificationClassConstraint", implementation.getIdentifier(),
1554                           moduleOfImpl.getName(), dependency.getName(), dependency.getIdentifier(),
1555                           moduleOfS.getName() );
1556
1557            }
1558
1559            if ( dependency.getVersion() != null )
1560            {
1561                if ( s.getVersion() == null )
1562                {
1563                    addDetail( validationContext.getReport(),
1564                               "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
1565                               new ObjectFactory().createImplementation( implementation ),
1566                               "implementationDependencySpecificationVersioningConstraint",
1567                               implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1568                               s.getIdentifier(), moduleOfS.getName() );
1569
1570                }
1571                else
1572                {
1573
1574                    try
1575                    {
1576                        if ( VersionParser.compare( dependency.getVersion(), s.getVersion() ) > 0 )
1577                        {
1578                            addDetail( validationContext.getReport(),
1579                                       "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_CONSTRAINT",
1580                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1581                                       "implementationDependencySpecificationCompatibilityConstraint",
1582                                       implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
1583                                       moduleOfS.getName(), dependency.getVersion(), s.getVersion() );
1584
1585                        }
1586                    }
1587                    catch ( final ParseException e )
1588                    {
1589                        final String message = getMessage( e );
1590
1591                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1592                        {
1593                            validationContext.getModelContext().log( Level.FINE, message, e );
1594                        }
1595
1596                        addDetail( validationContext.getReport(),
1597                                   "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_VERSIONING_PARSE_EXCEPTION",
1598                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1599                                   "implementationDependencySpecificationCompatibilityParseException",
1600                                   implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
1601                                   moduleOfS.getName(), dependency.getVersion(),
1602                                   message != null && message.length() > 0 ? " " + message : "" );
1603
1604                    }
1605                    catch ( final TokenMgrError e )
1606                    {
1607                        final String message = getMessage( e );
1608
1609                        if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1610                        {
1611                            validationContext.getModelContext().log( Level.FINE, message, e );
1612                        }
1613
1614                        addDetail( validationContext.getReport(),
1615                                   "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_VERSIONING_TOKEN_MANAGER_ERROR",
1616                                   Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1617                                   "implementationDependencySpecificationCompatibilityTokenMgrError",
1618                                   implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
1619                                   moduleOfS.getName(), dependency.getVersion(),
1620                                   message != null && message.length() > 0 ? " " + message : "" );
1621
1622                    }
1623                }
1624            }
1625
1626            if ( s.getScope() != null )
1627            {
1628                if ( dependency.getDependencies() != null )
1629                {
1630                    for ( int i = 0, s0 = dependency.getDependencies().getDependency().size(); i < s0; i++ )
1631                    {
1632                        final Dependency d = dependency.getDependencies().getDependency().get( i );
1633
1634                        addDetail( validationContext.getReport(),
1635                                   "IMPLEMENTATION_DEPENDENCY_DEPENDENCIES_OVERRIDE_CONSTRAINT", Level.SEVERE,
1636                                   new ObjectFactory().createImplementation( implementation ),
1637                                   "implementationDependencyDependenciesOverrideConstraint",
1638                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1639                                   d.getName(), s.getIdentifier(), moduleOfS.getName(), s.getScope() );
1640
1641                    }
1642                }
1643
1644                if ( dependency.getMessages() != null )
1645                {
1646                    for ( int i = 0, s0 = dependency.getMessages().getMessage().size(); i < s0; i++ )
1647                    {
1648                        final Message m = dependency.getMessages().getMessage().get( i );
1649
1650                        addDetail( validationContext.getReport(),
1651                                   "IMPLEMENTATION_DEPENDENCY_MESSAGES_OVERRIDE_CONSTRAINT", Level.SEVERE,
1652                                   new ObjectFactory().createImplementation( implementation ),
1653                                   "implementationDependencyMessagesOverrideConstraint", implementation.getIdentifier(),
1654                                   moduleOfImpl.getName(), dependency.getName(), m.getName(), s.getIdentifier(),
1655                                   moduleOfS.getName(), s.getScope() );
1656
1657                    }
1658                }
1659
1660                if ( dependency.getProperties() != null )
1661                {
1662                    for ( int i = 0, s0 = dependency.getProperties().getProperty().size(); i < s0; i++ )
1663                    {
1664                        final Property p = dependency.getProperties().getProperty().get( i );
1665                        addDetail( validationContext.getReport(),
1666                                   "IMPLEMENTATION_DEPENDENCY_PROPERTIES_OVERRIDE_CONSTRAINT", Level.SEVERE,
1667                                   new ObjectFactory().createImplementation( implementation ),
1668                                   "implementationDependencyPropertiesOverrideConstraint",
1669                                   implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1670                                   p.getName(), s.getIdentifier(), moduleOfS.getName(), s.getScope() );
1671
1672                    }
1673                }
1674            }
1675        }
1676
1677        if ( dependency.getMessages() != null )
1678        {
1679            for ( int i = 0, s0 = dependency.getMessages().getReference().size(); i < s0; i++ )
1680            {
1681                final MessageReference r = dependency.getMessages().getReference().get( i );
1682
1683                addDetail( validationContext.getReport(),
1684                           "IMPLEMENTATION_DEPENDENCY_MESSAGE_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
1685                           new ObjectFactory().createImplementation( implementation ),
1686                           "implementationDependencyMessageReferenceDeclarationConstraint",
1687                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(), r.getName() );
1688
1689            }
1690        }
1691
1692        if ( dependency.getProperties() != null )
1693        {
1694            for ( int i = 0, s0 = dependency.getProperties().getProperty().size(); i < s0; i++ )
1695            {
1696                final Property p = dependency.getProperties().getProperty().get( i );
1697
1698                if ( p.getValue() != null && p.getAny() != null )
1699                {
1700                    addDetail( validationContext.getReport(), "IMPLEMENTATION_DEPENDENCY_PROPERTY_VALUE_CONSTRAINT",
1701                               Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1702                               "implementationDependencyPropertyValueConstraint", implementation.getIdentifier(),
1703                               moduleOfImpl.getName(), dependency.getName(), p.getName() );
1704
1705                }
1706
1707                if ( p.getAny() != null && p.getType() == null )
1708                {
1709                    addDetail( validationContext.getReport(), "IMPLEMENTATION_DEPENDENCY_PROPERTY_TYPE_CONSTRAINT",
1710                               Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1711                               "implementationDependencyPropertyTypeConstraint", implementation.getIdentifier(),
1712                               moduleOfImpl.getName(), dependency.getName(), p.getName() );
1713
1714                }
1715
1716                try
1717                {
1718                    p.getJavaValue( validationContext.getModelContext().getClassLoader() );
1719                }
1720                catch ( final PropertyException e )
1721                {
1722                    final String message = getMessage( e );
1723
1724                    if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
1725                    {
1726                        validationContext.getModelContext().log( Level.FINE, message, e );
1727                    }
1728
1729                    addDetail( validationContext.getReport(),
1730                               "IMPLEMENTATION_DEPENDENCY_PROPERTY_JAVA_VALUE_CONSTRAINT", Level.SEVERE,
1731                               new ObjectFactory().createImplementation( implementation ),
1732                               "implementationDependencyPropertyJavaValueConstraint", implementation.getIdentifier(),
1733                               moduleOfImpl.getName(), dependency.getName(), p.getName(),
1734                               message != null && message.length() > 0 ? " " + message : "" );
1735
1736                }
1737            }
1738
1739            for ( int i = 0, s0 = dependency.getProperties().getReference().size(); i < s0; i++ )
1740            {
1741                final PropertyReference r = dependency.getProperties().getReference().get( i );
1742
1743                addDetail( validationContext.getReport(),
1744                           "IMPLEMENTATION_DEPENDENCY_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
1745                           new ObjectFactory().createImplementation( implementation ),
1746                           "implementationDependencyPropertyReferenceDeclarationConstraint",
1747                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(), r.getName() );
1748
1749            }
1750        }
1751
1752        if ( available != null )
1753        {
1754            for ( int i = 0, s0 = available.getImplementation().size(); i < s0; i++ )
1755            {
1756                final Implementation a = available.getImplementation().get( i );
1757
1758                if ( dependency.getImplementationName() != null
1759                     && !dependency.getImplementationName().equals( a.getName() ) )
1760                {
1761                    continue;
1762                }
1763
1764                final InheritanceModel imodel = validationContext.getInheritanceModel();
1765                final Module moduleOfA = validationContext.getModules().getModuleOfImplementation( a.getIdentifier() );
1766
1767                if ( dependency.getDependencies() != null )
1768                {
1769                    for ( int j = 0, s1 = dependency.getDependencies().getDependency().size(); j < s1; j++ )
1770                    {
1771                        final Dependency override = dependency.getDependencies().getDependency().get( j );
1772
1773                        final Set<InheritanceModel.Node<Dependency>> effDependencies =
1774                            imodel.getDependencyNodes( a.getIdentifier(), override.getName() );
1775
1776                        final Set<InheritanceModel.Node<Dependency>> overriddenDependencies =
1777                            modifiableSet( effDependencies );
1778
1779                        final boolean effectiveDependencyOverridden = !overriddenDependencies.isEmpty();
1780
1781                        if ( override.isOverride() && overriddenDependencies.isEmpty() )
1782                        {
1783                            addDetail( validationContext.getReport(),
1784                                       "IMPLEMENTATION_DEPENDENCY_OVERRIDE_DEPENDENCY_CONSTRAINT",
1785                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1786                                       "implementationDependencyOverrideDependencyConstraint",
1787                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1788                                       override.getName(), a.getIdentifier(), moduleOfA.getName() );
1789
1790                        }
1791
1792                        if ( !( override.isOverride() || overriddenDependencies.isEmpty() ) )
1793                        {
1794                            for ( final InheritanceModel.Node<Dependency> overriddenDependency :
1795                                  overriddenDependencies )
1796                            {
1797                                addDetail( validationContext.getReport(),
1798                                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_DEPENDENCY_WARNING",
1799                                           Level.WARNING, new ObjectFactory().createImplementation( implementation ),
1800                                           "implementationDependencyOverrideDependencyWarning",
1801                                           implementation.getIdentifier(), moduleOfImpl.getName(),
1802                                           dependency.getName(), override.getName(), a.getIdentifier(),
1803                                           moduleOfA.getName(), getNodePathString( overriddenDependency ) );
1804
1805                            }
1806                        }
1807
1808                        retainFinalNodes( overriddenDependencies );
1809
1810                        for ( final InheritanceModel.Node<Dependency> overriddenDependency :
1811                              overriddenDependencies )
1812                        {
1813                            addDetail( validationContext.getReport(),
1814                                       "IMPLEMENTATION_DEPENDENCY_FINAL_DEPENDENCY_CONSTRAINT",
1815                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
1816                                       "implementationDependencyFinalDependencyConstraint",
1817                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1818                                       override.getName(), a.getIdentifier(), moduleOfA.getName(),
1819                                       getNodePathString( overriddenDependency ) );
1820
1821                        }
1822
1823                        if ( effectiveDependencyOverridden )
1824                        {
1825                            for ( InheritanceModel.Node<Dependency> node : effDependencies )
1826                            {
1827                                final Dependency overridden = node.getModelObject();
1828
1829                                final Specification overrideSpecification =
1830                                    validationContext.getModules().getSpecification( override.getIdentifier() );
1831
1832                                final Specification overriddenSpecification =
1833                                    validationContext.getModules().getSpecification( overridden.getIdentifier() );
1834
1835                                if ( overrideSpecification != null && overriddenSpecification != null )
1836                                {
1837                                    if ( overrideSpecification.getMultiplicity()
1838                                         != overriddenSpecification.getMultiplicity() )
1839                                    {
1840                                        addDetail( validationContext.getReport(),
1841                                                   "IMPLEMENTATION_DEPENDENCY_MULTIPLICITY_CONSTRAINT",
1842                                                   Level.SEVERE,
1843                                                   new ObjectFactory().createImplementation( implementation ),
1844                                                   "implementationDependencyMultiplicityConstraint",
1845                                                   implementation.getIdentifier(), moduleOfImpl.getName(),
1846                                                   dependency.getName(), overridden.getName(),
1847                                                   a.getIdentifier(), moduleOfA.getName(),
1848                                                   overrideSpecification.getMultiplicity().value(),
1849                                                   overriddenSpecification.getMultiplicity().value() );
1850
1851                                    }
1852
1853                                    if ( overrideSpecification.getScope() != null
1854                                         ? !overrideSpecification.getScope().equals(
1855                                        overriddenSpecification.getScope() )
1856                                         : overriddenSpecification.getScope() != null )
1857                                    {
1858                                        addDetail( validationContext.getReport(),
1859                                                   "IMPLEMENTATION_DEPENDENCY_SCOPE_CONSTRAINT", Level.SEVERE,
1860                                                   new ObjectFactory().createImplementation( implementation ),
1861                                                   "implementationDependencyScopeConstraint",
1862                                                   implementation.getIdentifier(), moduleOfImpl.getName(),
1863                                                   dependency.getName(), override.getName(),
1864                                                   a.getIdentifier(), moduleOfA.getName(),
1865                                                   overrideSpecification.getScope() == null
1866                                                   ? "Multiton" : overrideSpecification.getScope(),
1867                                                   overriddenSpecification.getScope() == null
1868                                                   ? "Multiton" : overriddenSpecification.getScope() );
1869
1870                                    }
1871
1872                                    if ( overriddenSpecification.getMultiplicity() == Multiplicity.MANY )
1873                                    {
1874                                        if ( override.getImplementationName() == null
1875                                             && overridden.getImplementationName() != null )
1876                                        {
1877                                            addDetail( validationContext.getReport(),
1878                                                       "IMPLEMENTATION_DEPENDENCY_NO_IMPLEMENTATION_NAME_CONSTRAINT",
1879                                                       Level.SEVERE,
1880                                                       new ObjectFactory().createImplementation( implementation ),
1881                                                       "implementationDependencyNoImplementationNameConstraint",
1882                                                       implementation.getIdentifier(), moduleOfImpl.getName(),
1883                                                       dependency.getName(), override.getName(),
1884                                                       a.getIdentifier(), moduleOfA.getName() );
1885
1886                                        }
1887
1888                                        if ( override.getImplementationName() != null
1889                                             && overridden.getImplementationName() == null )
1890                                        {
1891                                            addDetail( validationContext.getReport(),
1892                                                       "IMPLEMENTATION_DEPENDENCY_IMPLEMENTATION_NAME_CONSTRAINT",
1893                                                       Level.SEVERE,
1894                                                       new ObjectFactory().createImplementation( implementation ),
1895                                                       "implementationDependencyImplementationNameConstraint",
1896                                                       implementation.getIdentifier(), moduleOfImpl.getName(),
1897                                                       dependency.getName(), overridden.getName(),
1898                                                       a.getIdentifier(), moduleOfA.getName(),
1899                                                       override.getImplementationName() );
1900
1901                                        }
1902                                    }
1903                                }
1904
1905                                if ( override.isOptional() != overridden.isOptional() )
1906                                {
1907                                    addDetail( validationContext.getReport(),
1908                                               "IMPLEMENTATION_DEPENDENCY_OPTIONALITY_CONSTRAINT", Level.SEVERE,
1909                                               new ObjectFactory().createImplementation( implementation ),
1910                                               "implementationDependencyOptonalityConstraint",
1911                                               implementation.getIdentifier(), moduleOfImpl.getName(),
1912                                               dependency.getName(), overridden.getName(),
1913                                               a.getIdentifier(), moduleOfA.getName() );
1914
1915                                }
1916                            }
1917                        }
1918                    }
1919                }
1920
1921                if ( dependency.getMessages() != null )
1922                {
1923                    for ( int j = 0, s1 = dependency.getMessages().getMessage().size(); j < s1; j++ )
1924                    {
1925                        final Message override = dependency.getMessages().getMessage().get( j );
1926
1927                        final Set<InheritanceModel.Node<Message>> overriddenMessages =
1928                            modifiableSet( imodel.getMessageNodes( a.getIdentifier(), override.getName() ) );
1929
1930                        if ( override.isOverride() && overriddenMessages.isEmpty() )
1931                        {
1932                            addDetail( validationContext.getReport(),
1933                                       "IMPLEMENTATION_DEPENDENCY_OVERRIDE_MESSAGE_CONSTRAINT", Level.SEVERE,
1934                                       new ObjectFactory().createImplementation( implementation ),
1935                                       "implementationDependencyOverrideMessageConstraint",
1936                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1937                                       override.getName(), a.getIdentifier(), moduleOfA.getName() );
1938
1939                        }
1940
1941                        if ( !( override.isOverride() || overriddenMessages.isEmpty() ) )
1942                        {
1943                            for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
1944                            {
1945                                addDetail( validationContext.getReport(),
1946                                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_MESSAGE_WARNING", Level.WARNING,
1947                                           new ObjectFactory().createImplementation( implementation ),
1948                                           "implementationDependencyOverrideMessageWarning",
1949                                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1950                                           override.getName(), a.getIdentifier(), moduleOfA.getName(),
1951                                           getNodePathString( overriddenMessage ) );
1952
1953                            }
1954                        }
1955
1956                        retainFinalNodes( overriddenMessages );
1957
1958                        for ( final InheritanceModel.Node<Message> overriddenMessage : overriddenMessages )
1959                        {
1960                            addDetail( validationContext.getReport(),
1961                                       "IMPLEMENTATION_DEPENDENCY_FINAL_MESSAGE_CONSTRAINT", Level.SEVERE,
1962                                       new ObjectFactory().createImplementation( implementation ),
1963                                       "implementationDependencyFinalMessageConstraint",
1964                                       implementation.getIdentifier(), moduleOfImpl.getName(),
1965                                       dependency.getName(), override.getName(), a.getIdentifier(),
1966                                       moduleOfA.getName(), getNodePathString( overriddenMessage ) );
1967
1968                        }
1969                    }
1970                }
1971
1972                if ( dependency.getProperties() != null )
1973                {
1974                    for ( int j = 0, s1 = dependency.getProperties().getProperty().size(); j < s1; j++ )
1975                    {
1976                        final Property override = dependency.getProperties().getProperty().get( j );
1977
1978                        final Set<InheritanceModel.Node<Property>> overriddenProperties =
1979                            modifiableSet( imodel.getPropertyNodes( a.getIdentifier(), override.getName() ) );
1980
1981                        if ( override.isOverride() && overriddenProperties.isEmpty() )
1982                        {
1983                            addDetail( validationContext.getReport(),
1984                                       "IMPLEMENTATION_DEPENDENCY_OVERRIDE_PROPERTY_CONSTRAINT", Level.SEVERE,
1985                                       new ObjectFactory().createImplementation( implementation ),
1986                                       "implementationDependencyOverridePropertyConstraint",
1987                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
1988                                       override.getName(), a.getIdentifier(), moduleOfA.getName() );
1989
1990                        }
1991
1992                        if ( !( override.isOverride() || overriddenProperties.isEmpty() ) )
1993                        {
1994                            for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
1995                            {
1996                                addDetail( validationContext.getReport(),
1997                                           "IMPLEMENTATION_DEPENDENCY_OVERRIDE_PROPERTY_WARNING", Level.WARNING,
1998                                           new ObjectFactory().createImplementation( implementation ),
1999                                           "implementationDependencyOverridePropertyWarning",
2000                                           implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
2001                                           override.getName(), a.getIdentifier(), moduleOfA.getName(),
2002                                           getNodePathString( overriddenProperty ) );
2003
2004                            }
2005                        }
2006
2007                        retainFinalNodes( overriddenProperties );
2008
2009                        for ( final InheritanceModel.Node<Property> overriddenProperty : overriddenProperties )
2010                        {
2011                            addDetail( validationContext.getReport(),
2012                                       "IMPLEMENTATION_DEPENDENCY_FINAL_PROPERTY_CONSTRAINT", Level.SEVERE,
2013                                       new ObjectFactory().createImplementation( implementation ),
2014                                       "implementationDependencyFinalPropertyConstraint",
2015                                       implementation.getIdentifier(), moduleOfImpl.getName(), dependency.getName(),
2016                                       override.getName(), a.getIdentifier(), moduleOfA.getName(),
2017                                       getNodePathString( overriddenProperty ) );
2018
2019                        }
2020                    }
2021                }
2022            }
2023        }
2024
2025        if ( dependency.getDependencies() != null )
2026        {
2027            for ( int i = 0, s0 = dependency.getDependencies().getDependency().size(); i < s0; i++ )
2028            {
2029                final Dependency d = dependency.getDependencies().getDependency().get( i );
2030                assertDependencyValid( validationContext, implementation, d );
2031            }
2032        }
2033    }
2034
2035    private static void assertImplementationSpecificationCompatibility(
2036        final ValidationContext validationContext, final Implementation implementation )
2037    {
2038        final Specifications specs = validationContext.getModules().getSpecifications( implementation.getIdentifier() );
2039        final Module moduleOfImpl =
2040            validationContext.getModules().getModuleOfImplementation( implementation.getIdentifier() );
2041
2042        if ( specs != null )
2043        {
2044            for ( int i = 0, s0 = specs.getReference().size(); i < s0; i++ )
2045            {
2046                final SpecificationReference r = specs.getReference().get( i );
2047                final Specification s = specs.getSpecification( r.getIdentifier() );
2048
2049                if ( s != null && r.getVersion() != null )
2050                {
2051                    final Module moduleOfS =
2052                        validationContext.getModules().getModuleOfSpecification( s.getIdentifier() );
2053
2054                    if ( s.getVersion() == null )
2055                    {
2056                        addDetail( validationContext.getReport(),
2057                                   "IMPLEMENTATION_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
2058                                   new ObjectFactory().createImplementation( implementation ),
2059                                   "implementationSpecificationVersioningConstraint", implementation.getIdentifier(),
2060                                   moduleOfImpl.getName(), s.getIdentifier(), moduleOfS.getName() );
2061
2062                    }
2063                    else
2064                    {
2065                        try
2066                        {
2067                            if ( VersionParser.compare( r.getVersion(), s.getVersion() ) != 0 )
2068                            {
2069                                addDetail( validationContext.getReport(),
2070                                           "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
2071                                           new ObjectFactory().createImplementation( implementation ),
2072                                           "implementationSpecificationCompatibilityConstraint",
2073                                           implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
2074                                           moduleOfS.getName(), r.getVersion(), s.getVersion() );
2075
2076                            }
2077                        }
2078                        catch ( final ParseException e )
2079                        {
2080                            final String message = getMessage( e );
2081
2082                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2083                            {
2084                                validationContext.getModelContext().log( Level.FINE, message, e );
2085                            }
2086
2087                            addDetail( validationContext.getReport(),
2088                                       "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_VERSIONING_PARSE_EXCEPTION",
2089                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
2090                                       "implementationSpecificationCompatibilityVersioningParseException",
2091                                       implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
2092                                       moduleOfS.getName(), r.getVersion(),
2093                                       message != null && message.length() > 0 ? " " + message : "" );
2094
2095                        }
2096                        catch ( final TokenMgrError e )
2097                        {
2098                            final String message = getMessage( e );
2099
2100                            if ( validationContext.getModelContext().isLoggable( Level.FINE ) )
2101                            {
2102                                validationContext.getModelContext().log( Level.FINE, message, e );
2103                            }
2104
2105                            addDetail( validationContext.getReport(),
2106                                       "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_VERSIONING_TOKEN_MANAGER_ERROR",
2107                                       Level.SEVERE, new ObjectFactory().createImplementation( implementation ),
2108                                       "implementationSpecificationCompatibilityVersioningTokenManagerError",
2109                                       implementation.getIdentifier(), moduleOfImpl.getName(), s.getIdentifier(),
2110                                       moduleOfS.getName(), r.getVersion(),
2111                                       message != null && message.length() > 0 ? " " + message : "" );
2112
2113                        }
2114                    }
2115                }
2116            }
2117        }
2118    }
2119
2120    private static boolean isInheritanceCycle( final ValidationContext validationContext, final Implementation current,
2121                                               Map<String, Implementation> implementations, final List<String> path )
2122    {
2123        if ( implementations == null )
2124        {
2125            implementations = new HashMap<String, Implementation>();
2126        }
2127
2128        if ( current != null )
2129        {
2130            path.add( current.getIdentifier() );
2131
2132            if ( implementations.containsKey( current.getIdentifier() ) )
2133            {
2134                return true;
2135            }
2136
2137            implementations.put( current.getIdentifier(), current );
2138
2139            if ( current.getImplementations() != null )
2140            {
2141                for ( int i = 0, s0 = current.getImplementations().getReference().size(); i < s0; i++ )
2142                {
2143                    final ImplementationReference r = current.getImplementations().getReference().get( i );
2144                    return isInheritanceCycle(
2145                        validationContext, validationContext.getModules().getImplementation( r.getIdentifier() ),
2146                        implementations, path );
2147
2148                }
2149            }
2150
2151            path.remove( current.getIdentifier() );
2152        }
2153
2154        return false;
2155    }
2156
2157    private static <T> String getNodePathString( final InheritanceModel.Node<T> node )
2158    {
2159        final StringBuilder b = new StringBuilder( node.getPath().size() * 50 );
2160
2161        for ( int i = 0, s0 = node.getPath().size(); i < s0; i++ )
2162        {
2163            final InheritanceModel.Node<Implementation> pathNode = node.getPath().get( i );
2164
2165            if ( pathNode.getClassDeclaration() != null )
2166            {
2167                b.append( " -> [" ).append( pathNode.getClassDeclaration().getClazz() ).append( "] @ '" ).
2168                    append( pathNode.getImplementation().getIdentifier() ).append( "'" );
2169
2170            }
2171            if ( pathNode.getSpecification() != null )
2172            {
2173                b.append( " -> <" ).append( pathNode.getSpecification().getIdentifier() ).append( "> @ '" ).
2174                    append( pathNode.getImplementation().getIdentifier() ).append( "'" );
2175
2176            }
2177            else
2178            {
2179                b.append( " -> '" ).append( pathNode.getImplementation().getIdentifier() ).append( "'" );
2180            }
2181        }
2182
2183        if ( node.getClassDeclaration() != null )
2184        {
2185            b.append( " -> [" ).append( node.getClassDeclaration().getClazz() ).append( "] @ '" ).
2186                append( node.getImplementation().getIdentifier() ).append( "'" );
2187
2188        }
2189        if ( node.getSpecification() != null )
2190        {
2191            b.append( " -> <" ).append( node.getSpecification().getIdentifier() ).append( "> @ '" ).
2192                append( node.getImplementation().getIdentifier() ).append( "'" );
2193
2194        }
2195
2196        return b.length() > 0 ? b.substring( " -> ".length() ) : b.toString();
2197    }
2198
2199    private static <T> String getNodeListPathString( final Collection<? extends InheritanceModel.Node<T>> nodes )
2200    {
2201        final StringBuilder path = new StringBuilder( nodes.size() * 255 );
2202
2203        for ( final InheritanceModel.Node<T> node : nodes )
2204        {
2205            path.append( ", " ).append( getNodePathString( node ) );
2206        }
2207
2208        return path.length() > 1 ? path.substring( 2 ) : path.toString();
2209    }
2210
2211    private static <T> Set<InheritanceModel.Node<T>> retainFinalNodes( final Set<InheritanceModel.Node<T>> set )
2212    {
2213        if ( set != null )
2214        {
2215            for ( final Iterator<InheritanceModel.Node<T>> it = set.iterator(); it.hasNext(); )
2216            {
2217                if ( !it.next().isFinal() )
2218                {
2219                    it.remove();
2220                }
2221            }
2222        }
2223
2224        return set;
2225    }
2226
2227    private static void addDetail(
2228        final ModelValidationReport report, final String identifier, final Level level,
2229        final JAXBElement<? extends ModelObject> element, final String messageKey, final Object... messageArguments )
2230    {
2231        report.getDetails().add( new ModelValidationReport.Detail(
2232            identifier, level, getMessage( messageKey, messageArguments ), element ) );
2233
2234    }
2235
2236    private static <T> Set<T> modifiableSet( final Collection<? extends T> col )
2237    {
2238        Set<T> set = Collections.emptySet();
2239
2240        if ( col != null )
2241        {
2242            set = new HashSet<T>( col );
2243        }
2244
2245        return set;
2246    }
2247
2248    private static String getMessage( final String key, final Object... messageArguments )
2249    {
2250        return MessageFormat.format( ResourceBundle.getBundle(
2251            DefaultModelValidator.class.getName().replace( '.', '/' ),
2252            Locale.getDefault() ).getString( key ), messageArguments );
2253
2254    }
2255
2256    private static String getMessage( final Throwable t )
2257    {
2258        return t != null ? t.getMessage() != null ? t.getMessage() : getMessage( t.getCause() ) : null;
2259    }
2260
2261    /** @since 1.2 */
2262    private static final class ValidationContext
2263    {
2264
2265        private final ModelContext modelContext;
2266
2267        private final Modules modules;
2268
2269        private final ModelValidationReport report;
2270
2271        private final InheritanceModel inheritanceModel;
2272
2273        private ValidationContext( final ModelContext modelContext, final Modules modules,
2274                                   final ModelValidationReport report )
2275        {
2276            super();
2277            this.modelContext = modelContext;
2278            this.modules = modules;
2279            this.report = report;
2280            this.inheritanceModel = new InheritanceModel( modules );
2281        }
2282
2283        private ModelContext getModelContext()
2284        {
2285            return modelContext;
2286        }
2287
2288        private Modules getModules()
2289        {
2290            return modules;
2291        }
2292
2293        private ModelValidationReport getReport()
2294        {
2295            return report;
2296        }
2297
2298        private InheritanceModel getInheritanceModel()
2299        {
2300            return this.inheritanceModel;
2301        }
2302
2303    }
2304
2305}