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 4425 2012-03-14 09:03:36Z schulte2005 $
029     *
030     */
031    package org.jomc.model.modlet;
032    
033    import java.text.MessageFormat;
034    import java.util.Collection;
035    import java.util.Collections;
036    import java.util.HashMap;
037    import java.util.HashSet;
038    import java.util.Iterator;
039    import java.util.LinkedList;
040    import java.util.List;
041    import java.util.Locale;
042    import java.util.Map;
043    import java.util.ResourceBundle;
044    import java.util.Set;
045    import java.util.logging.Level;
046    import javax.xml.bind.JAXBElement;
047    import javax.xml.bind.JAXBException;
048    import javax.xml.bind.util.JAXBSource;
049    import javax.xml.namespace.QName;
050    import javax.xml.transform.Source;
051    import org.jomc.model.Dependency;
052    import org.jomc.model.Implementation;
053    import org.jomc.model.ImplementationReference;
054    import org.jomc.model.Implementations;
055    import org.jomc.model.Inheritable;
056    import org.jomc.model.InheritanceModel;
057    import org.jomc.model.Message;
058    import org.jomc.model.MessageReference;
059    import org.jomc.model.ModelObject;
060    import org.jomc.model.Module;
061    import org.jomc.model.Modules;
062    import org.jomc.model.Multiplicity;
063    import org.jomc.model.ObjectFactory;
064    import org.jomc.model.Property;
065    import org.jomc.model.PropertyException;
066    import org.jomc.model.PropertyReference;
067    import org.jomc.model.Specification;
068    import org.jomc.model.SpecificationReference;
069    import org.jomc.model.Specifications;
070    import org.jomc.model.Text;
071    import org.jomc.modlet.Model;
072    import org.jomc.modlet.ModelContext;
073    import org.jomc.modlet.ModelException;
074    import org.jomc.modlet.ModelValidationReport;
075    import org.jomc.modlet.ModelValidator;
076    import org.jomc.util.ParseException;
077    import org.jomc.util.TokenMgrError;
078    import org.jomc.util.VersionParser;
079    import 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 4425 2012-03-14 09:03:36Z schulte2005 $
086     * @see ModelContext#validateModel(org.jomc.modlet.Model)
087     */
088    public 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    }