001    /*
002     *   Copyright (c) 2009 The JOMC Project
003     *   Copyright (c) 2005 Christian Schulte <cs@jomc.org>
004     *   All rights reserved.
005     *
006     *   Redistribution and use in source and binary forms, with or without
007     *   modification, are permitted provided that the following conditions
008     *   are met:
009     *
010     *     o Redistributions of source code must retain the above copyright
011     *       notice, this list of conditions and the following disclaimer.
012     *
013     *     o Redistributions in binary form must reproduce the above copyright
014     *       notice, this list of conditions and the following disclaimer in
015     *       the documentation and/or other materials provided with the
016     *       distribution.
017     *
018     *   THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
019     *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020     *   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021     *   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
022     *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023     *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024     *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025     *   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026     *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
027     *   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
028     *   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029     *
030     *   $Id: DefaultModelObjectValidator.java 1093 2009-12-06 17:24:40Z schulte2005 $
031     *
032     */
033    package org.jomc.model;
034    
035    import java.io.StringWriter;
036    import java.text.MessageFormat;
037    import java.util.HashMap;
038    import java.util.LinkedList;
039    import java.util.List;
040    import java.util.Locale;
041    import java.util.Map;
042    import java.util.ResourceBundle;
043    import java.util.logging.Level;
044    import javax.xml.bind.JAXBContext;
045    import javax.xml.bind.JAXBElement;
046    import javax.xml.bind.JAXBException;
047    import javax.xml.bind.Marshaller;
048    import javax.xml.bind.ValidationEvent;
049    import javax.xml.bind.ValidationEventHandler;
050    import javax.xml.validation.Schema;
051    import org.jomc.util.ParseException;
052    import org.jomc.util.TokenMgrError;
053    import org.jomc.util.VersionParser;
054    
055    /**
056     * Default {@code ModelObjectValidator} implementation.
057     *
058     * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
059     * @version $Id: DefaultModelObjectValidator.java 1093 2009-12-06 17:24:40Z schulte2005 $
060     */
061    public class DefaultModelObjectValidator implements ModelObjectValidator
062    {
063    
064        /** Creates a new {@code DefaultModelObjectValidator} instance. */
065        public DefaultModelObjectValidator()
066        {
067            super();
068        }
069    
070        public ModelObjectValidationReport validateModelObject(
071            final JAXBElement modelObject, final JAXBContext context, final Schema schema ) throws JAXBException
072        {
073            if ( modelObject == null )
074            {
075                throw new NullPointerException( "modelObject" );
076            }
077            if ( modelObject.getValue() == null )
078            {
079                throw new NullPointerException( "modelObject" );
080            }
081            if ( context == null )
082            {
083                throw new NullPointerException( "context" );
084            }
085            if ( schema == null )
086            {
087                throw new NullPointerException( "schema" );
088            }
089    
090            final Marshaller marshaller = context.createMarshaller();
091            final ModelObjectValidationReport report = new ModelObjectValidationReport( modelObject );
092            marshaller.setSchema( schema );
093            marshaller.setEventHandler( new ModelObjectValidationEventHandler( report ) );
094    
095            try
096            {
097                marshaller.marshal( modelObject, new StringWriter() );
098            }
099            catch ( final JAXBException e )
100            {
101                if ( report.getDetails().isEmpty() )
102                {
103                    throw e;
104                }
105            }
106    
107            return report;
108        }
109    
110        public ModelObjectValidationReport validateModules(
111            final JAXBElement<Modules> modules, final JAXBContext context, final Schema schema ) throws JAXBException
112        {
113            if ( modules == null )
114            {
115                throw new NullPointerException( "modules" );
116            }
117            if ( modules.getValue() == null )
118            {
119                throw new NullPointerException( "modules" );
120            }
121            if ( context == null )
122            {
123                throw new NullPointerException( "context" );
124            }
125            if ( schema == null )
126            {
127                throw new NullPointerException( "schema" );
128            }
129    
130            final ModelObjectValidationReport report = this.validateModelObject( modules, context, schema );
131    
132            for ( Module m : modules.getValue().getModule() )
133            {
134                this.assertNoSpecificationReferenceDeclarations( m, report );
135                this.assertNoImplementationReferenceDeclarations( m, report );
136                this.assertNoMessageReferenceDeclarations( m, report );
137                this.assertNoFinalMessageDeclarations( m, report );
138                this.assertNoOverrideMessageDeclarations( m, report );
139                this.assertNoPropertyReferenceDeclarations( m, report );
140                this.assertNoFinalPropertyDeclarations( m, report );
141                this.assertNoOverridePropertyDeclarations( m, report );
142    
143                if ( m.getImplementations() != null )
144                {
145                    for ( Implementation i : m.getImplementations().getImplementation() )
146                    {
147                        this.assertNoDependencyPropertyReferenceDeclarations( i, report );
148                        this.assertNoImplementationDeclarations( i, report );
149                        this.assertNoLocationWhenAbstract( i, report );
150                        this.assertNoSpecificationDeclarations( i, report );
151                        this.assertImplementationMessagesUniqueness( i, report );
152                        this.assertImplementationPropertiesUniqueness( i, report );
153                        this.assertImplementationDependencyCompatibility( modules.getValue(), i, report );
154                        this.assertImplementationInheritanceCompatibility( modules.getValue(), i, report );
155                        this.assertImplementationSpecificationCompatibility( modules.getValue(), i, report );
156                        this.assertNoMissingMandatoryDependencies( modules.getValue(), i, report );
157                        this.assertNoDependenciesWithoutSpecificationClass( modules.getValue(), i, report );
158                        this.assertNoInheritanceCycle( modules.getValue(), i, report );
159                        this.assertNoInheritanceClashes( modules.getValue(), i, report );
160                        this.assertNoOverridenDependencyPropertiesWhenNotMultiton( modules.getValue(), i, report );
161                        this.assertImplementationOverrideConstraints( modules.getValue(), i, report );
162                        this.assertSpecificationOverrideConstraints( modules.getValue(), i, report );
163                        this.assertDependencyOverrideConstraints( modules.getValue(), i, report );
164                        this.assertMessageOverrideConstraints( modules.getValue(), i, report );
165                        this.assertPropertyOverrideConstraints( modules.getValue(), i, report );
166                        this.assertDependencyPropertiesOverrideConstraints( modules.getValue(), i, report );
167                    }
168                }
169    
170                if ( m.getSpecifications() != null )
171                {
172                    for ( Specification s : m.getSpecifications().getSpecification() )
173                    {
174                        this.assertNoSpecificationPropertyReferenceDeclarations( s, report );
175                        this.assertSpecificationImplementationNameUniqueness( modules.getValue(), s, report );
176                        this.assertSpecificationMultiplicityConstraint( modules.getValue(), s, report );
177                    }
178                }
179            }
180    
181            return report;
182        }
183    
184        private void assertNoSpecificationReferenceDeclarations( final Module module,
185                                                                 final ModelObjectValidationReport report )
186        {
187            if ( module.getSpecifications() != null )
188            {
189                for ( SpecificationReference r : module.getSpecifications().getReference() )
190                {
191                    report.getDetails().add( this.createDetail(
192                        "MODULE_SPECIFICATION_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
193                        "moduleSpecificationReferenceDeclarationConstraint", new Object[]
194                        {
195                            module.getName(), r.getIdentifier()
196                        }, new ObjectFactory().createModule( module ) ) );
197    
198                }
199            }
200        }
201    
202        private void assertNoImplementationReferenceDeclarations( final Module module,
203                                                                  final ModelObjectValidationReport report )
204        {
205            if ( module.getImplementations() != null )
206            {
207                for ( ImplementationReference r : module.getImplementations().getReference() )
208                {
209                    report.getDetails().add( this.createDetail(
210                        "MODULE_IMPLEMENTATION_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
211                        "moduleImplementationReferenceDeclarationConstraint", new Object[]
212                        {
213                            module.getName(), r.getIdentifier()
214                        }, new ObjectFactory().createModule( module ) ) );
215    
216                }
217            }
218        }
219    
220        private void assertNoMessageReferenceDeclarations( final Module module,
221                                                           final ModelObjectValidationReport report )
222        {
223            if ( module.getMessages() != null )
224            {
225                for ( MessageReference r : module.getMessages().getReference() )
226                {
227                    report.getDetails().add( this.createDetail(
228                        "MODULE_MESSAGE_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
229                        "moduleMessageReferenceDeclarationConstraint", new Object[]
230                        {
231                            module.getName(), r.getName()
232                        }, new ObjectFactory().createModule( module ) ) );
233    
234                }
235            }
236        }
237    
238        private void assertNoFinalMessageDeclarations( final Module module,
239                                                       final ModelObjectValidationReport report )
240        {
241            if ( module.getMessages() != null )
242            {
243                for ( Message m : module.getMessages().getMessage() )
244                {
245                    if ( m.isFinal() )
246                    {
247                        report.getDetails().add( this.createDetail(
248                            "MODULE_FINAL_MESSAGE_DECLARATION_CONSTRAINT", Level.SEVERE,
249                            "moduleFinalMessageConstraint", new Object[]
250                            {
251                                module.getName(), m.getName()
252                            }, new ObjectFactory().createModule( module ) ) );
253    
254                    }
255                }
256            }
257        }
258    
259        private void assertNoOverrideMessageDeclarations( final Module module,
260                                                          final ModelObjectValidationReport report )
261        {
262            if ( module.getMessages() != null )
263            {
264                for ( Message m : module.getMessages().getMessage() )
265                {
266                    if ( m.isOverride() )
267                    {
268                        report.getDetails().add( this.createDetail(
269                            "MODULE_OVERRIDE_MESSAGE_DECLARATION_CONSTRAINT", Level.SEVERE,
270                            "moduleOverrideMessageConstraint", new Object[]
271                            {
272                                module.getName(), m.getName()
273                            }, new ObjectFactory().createModule( module ) ) );
274    
275                    }
276                }
277            }
278        }
279    
280        private void assertNoPropertyReferenceDeclarations( final Module module,
281                                                            final ModelObjectValidationReport report )
282        {
283            if ( module.getProperties() != null )
284            {
285                for ( PropertyReference r : module.getProperties().getReference() )
286                {
287                    report.getDetails().add( this.createDetail(
288                        "MODULE_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
289                        "modulePropertyReferenceDeclarationConstraint", new Object[]
290                        {
291                            module.getName(), r.getName()
292                        }, new ObjectFactory().createModule( module ) ) );
293    
294                }
295            }
296        }
297    
298        private void assertNoFinalPropertyDeclarations( final Module module,
299                                                        final ModelObjectValidationReport report )
300        {
301            if ( module.getProperties() != null )
302            {
303                for ( Property p : module.getProperties().getProperty() )
304                {
305                    if ( p.isFinal() )
306                    {
307                        report.getDetails().add( this.createDetail(
308                            "MODULE_FINAL_PROPERTY_DECLARATION_CONSTRAINT", Level.SEVERE,
309                            "moduleFinalPropertyConstraint", new Object[]
310                            {
311                                module.getName(), p.getName()
312                            }, new ObjectFactory().createModule( module ) ) );
313    
314                    }
315                }
316            }
317        }
318    
319        private void assertNoOverridePropertyDeclarations( final Module module,
320                                                           final ModelObjectValidationReport report )
321        {
322            if ( module.getProperties() != null )
323            {
324                for ( Property p : module.getProperties().getProperty() )
325                {
326                    if ( p.isOverride() )
327                    {
328                        report.getDetails().add( this.createDetail(
329                            "MODULE_OVERRIDE_PROPERTY_DECLARATION_CONSTRAINT", Level.SEVERE,
330                            "moduleOverridePropertyConstraint", new Object[]
331                            {
332                                module.getName(), p.getName()
333                            }, new ObjectFactory().createModule( module ) ) );
334    
335                    }
336                }
337            }
338        }
339    
340        private void assertNoSpecificationDeclarations( final Implementation implementation,
341                                                        final ModelObjectValidationReport report )
342        {
343            if ( implementation.getSpecifications() != null )
344            {
345                for ( Specification s : implementation.getSpecifications().getSpecification() )
346                {
347                    report.getDetails().add( this.createDetail(
348                        "IMPLEMENTATION_SPECIFICATION_DECLARATION_CONSTRAINT", Level.SEVERE,
349                        "implementationSpecificationDeclarationConstraint", new Object[]
350                        {
351                            implementation.getIdentifier(), s.getIdentifier()
352                        }, new ObjectFactory().createImplementation( implementation ) ) );
353    
354                }
355            }
356        }
357    
358        private void assertNoImplementationDeclarations( final Implementation implementation,
359                                                         final ModelObjectValidationReport report )
360        {
361            if ( implementation.getImplementations() != null )
362            {
363                for ( Implementation i : implementation.getImplementations().getImplementation() )
364                {
365                    report.getDetails().add( this.createDetail(
366                        "IMPLEMENTATION_IMPLEMENTATION_DECLARATION_CONSTRAINT", Level.SEVERE,
367                        "implementationImplementationDeclarationConstraint", new Object[]
368                        {
369                            implementation.getIdentifier(), i.getIdentifier()
370                        }, new ObjectFactory().createImplementation( implementation ) ) );
371    
372                }
373            }
374        }
375    
376        private void assertNoLocationWhenAbstract( final Implementation implementation,
377                                                   final ModelObjectValidationReport report )
378        {
379            if ( implementation.isAbstract() && implementation.getLocation() != null )
380            {
381                report.getDetails().add( this.createDetail(
382                    "IMPLEMENTATION_ABSTRACT_LOCATION_DECLARATION_CONSTRAINT", Level.SEVERE,
383                    "implementationAbstractLocationDeclarationConstraint", new Object[]
384                    {
385                        implementation.getIdentifier(), implementation.getLocation()
386                    }, new ObjectFactory().createImplementation( implementation ) ) );
387    
388            }
389        }
390    
391        private void assertNoInheritanceCycle( final Modules modules,
392                                               final Implementation implementation,
393                                               final ModelObjectValidationReport report )
394        {
395            final Implementation cycle =
396                this.findInheritanceCycle( modules, implementation, implementation, new Implementations() );
397    
398            if ( cycle != null )
399            {
400                report.getDetails().add( this.createDetail(
401                    "IMPLEMENTATION_INHERITANCE_CYCLE_CONSTRAINT", Level.SEVERE,
402                    "implementationInheritanceCycleConstraint", new Object[]
403                    {
404                        implementation.getIdentifier(), cycle.getIdentifier()
405                    }, new ObjectFactory().createImplementation( implementation ) ) );
406    
407            }
408        }
409    
410        private void assertImplementationSpecificationCompatibility( final Modules modules,
411                                                                     final Implementation implementation,
412                                                                     final ModelObjectValidationReport report )
413        {
414            final Specifications specs = modules.getSpecifications( implementation.getIdentifier() );
415    
416            if ( specs != null )
417            {
418                for ( SpecificationReference r : specs.getReference() )
419                {
420                    final Specification s = specs.getSpecification( r.getIdentifier() );
421    
422                    if ( s != null && r.getVersion() != null )
423                    {
424                        if ( s.getVersion() == null )
425                        {
426                            report.getDetails().add( this.createDetail(
427                                "IMPLEMENTATION_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
428                                "implementationSpecificationVersioningConstraint", new Object[]
429                                {
430                                    implementation.getIdentifier(), s.getIdentifier()
431                                }, new ObjectFactory().createImplementation( implementation ) ) );
432    
433                        }
434                        else
435                        {
436                            try
437                            {
438                                if ( VersionParser.compare( r.getVersion(), s.getVersion() ) != 0 )
439                                {
440                                    final Module moduleOfImplementation =
441                                        modules.getModuleOfImplementation( implementation.getIdentifier() );
442    
443                                    final Module moduleOfSpecification =
444                                        modules.getModuleOfSpecification( s.getIdentifier() );
445    
446                                    report.getDetails().add( this.createDetail(
447                                        "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
448                                        "implementationSpecificationCompatibilityConstraint", new Object[]
449                                        {
450                                            implementation.getIdentifier(),
451                                            moduleOfImplementation != null ? moduleOfImplementation.getName() : "<>",
452                                            s.getIdentifier(),
453                                            moduleOfSpecification != null ? moduleOfSpecification.getName() : "<>",
454                                            r.getVersion(), s.getVersion()
455                                        }, new ObjectFactory().createImplementation( implementation ) ) );
456    
457                                }
458                            }
459                            catch ( final ParseException e )
460                            {
461                                final ModelObjectValidationReport.Detail d = new ModelObjectValidationReport.Detail(
462                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
463    
464                                d.setElement( new ObjectFactory().createImplementation( implementation ) );
465                                report.getDetails().add( d );
466                            }
467                            catch ( final TokenMgrError e )
468                            {
469                                final ModelObjectValidationReport.Detail d = new ModelObjectValidationReport.Detail(
470                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
471    
472                                d.setElement( new ObjectFactory().createImplementation( implementation ) );
473                                report.getDetails().add( d );
474                            }
475                        }
476                    }
477                }
478            }
479        }
480    
481        private void assertImplementationDependencyCompatibility( final Modules modules,
482                                                                  final Implementation implementation,
483                                                                  final ModelObjectValidationReport report )
484        {
485            final Dependencies dependencies = modules.getDependencies( implementation.getIdentifier() );
486            if ( dependencies != null )
487            {
488                for ( Dependency d : dependencies.getDependency() )
489                {
490                    final Specification s = modules.getSpecification( d.getIdentifier() );
491                    if ( s != null && d.getVersion() != null )
492                    {
493                        if ( s.getVersion() == null )
494                        {
495                            report.getDetails().add( this.createDetail(
496                                "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
497                                "implementationDependencySpecificationVersioningConstraint", new Object[]
498                                {
499                                    implementation.getIdentifier(), d.getName(), s.getIdentifier()
500                                }, new ObjectFactory().createImplementation( implementation ) ) );
501    
502                        }
503                        else
504                        {
505                            try
506                            {
507                                if ( VersionParser.compare( d.getVersion(), s.getVersion() ) > 0 )
508                                {
509                                    final Module moduleOfImplementation =
510                                        modules.getModuleOfImplementation( implementation.getIdentifier() );
511    
512                                    final Module moduleOfSpecification =
513                                        modules.getModuleOfSpecification( s.getIdentifier() );
514    
515                                    report.getDetails().add( this.createDetail(
516                                        "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
517                                        "implementationDependencySpecificationCompatibilityConstraint", new Object[]
518                                        {
519                                            implementation.getIdentifier(),
520                                            moduleOfImplementation != null ? moduleOfImplementation.getName() : "<>",
521                                            s.getIdentifier(),
522                                            moduleOfSpecification != null ? moduleOfSpecification.getName() : "<>",
523                                            d.getVersion(), s.getVersion()
524                                        }, new ObjectFactory().createImplementation( implementation ) ) );
525    
526                                }
527                            }
528                            catch ( final ParseException e )
529                            {
530                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
531                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
532    
533                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
534                                report.getDetails().add( detail );
535                            }
536                            catch ( final TokenMgrError e )
537                            {
538                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
539                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
540    
541                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
542                                report.getDetails().add( detail );
543                            }
544                        }
545                    }
546                }
547            }
548        }
549    
550        private void assertNoDependencyPropertyReferenceDeclarations( final Implementation implementation,
551                                                                      final ModelObjectValidationReport report )
552        {
553            if ( implementation.getDependencies() != null )
554            {
555                for ( Dependency d : implementation.getDependencies().getDependency() )
556                {
557                    if ( d.getProperties() != null )
558                    {
559                        for ( PropertyReference r : d.getProperties().getReference() )
560                        {
561                            report.getDetails().add( this.createDetail(
562                                "IMPLEMENTATION_DEPENDENCY_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
563                                "implementationDependencyPropertyReferenceDeclarationConstraint", new Object[]
564                                {
565                                    implementation.getIdentifier(), d.getName(), r.getName()
566                                }, new ObjectFactory().createImplementation( implementation ) ) );
567    
568                        }
569                    }
570                }
571            }
572        }
573    
574        private void assertNoOverridenDependencyPropertiesWhenNotMultiton( final Modules modules,
575                                                                           final Implementation implementation,
576                                                                           final ModelObjectValidationReport report )
577        {
578            if ( implementation.getDependencies() != null )
579            {
580                for ( Dependency d : implementation.getDependencies().getDependency() )
581                {
582                    final Specification s = modules.getSpecification( d.getIdentifier() );
583    
584                    if ( s != null && s.getScope() != null && d.getProperties() != null )
585                    {
586                        for ( Property p : d.getProperties().getProperty() )
587                        {
588                            report.getDetails().add( this.createDetail(
589                                "IMPLEMENTATION_DEPENDENCY_PROPERTIES_OVERRIDE_CONSTRAINT", Level.SEVERE,
590                                "implementationDependencyPropertiesOverrideConstraint", new Object[]
591                                {
592                                    implementation.getIdentifier(), d.getName(), s.getIdentifier(), s.getScope(),
593                                    p.getName()
594                                }, new ObjectFactory().createImplementation( implementation ) ) );
595    
596                        }
597                    }
598                }
599            }
600        }
601    
602        private void assertDependencyPropertiesOverrideConstraints( final Modules modules,
603                                                                    final Implementation implementation,
604                                                                    final ModelObjectValidationReport report )
605        {
606            if ( implementation.getDependencies() != null )
607            {
608                for ( Dependency d : implementation.getDependencies().getDependency() )
609                {
610                    final Implementations available = modules.getImplementations( d.getIdentifier() );
611                    if ( available != null )
612                    {
613                        if ( d.getImplementationName() != null )
614                        {
615                            final Implementation i = available.getImplementationByName( d.getImplementationName() );
616                            if ( i != null )
617                            {
618                                this.assertDependencyDoesNotOverrideFinalPropertyAndDoesNotFlagNonOverridenPropertyOverride(
619                                    modules, implementation, d, i, report );
620    
621                            }
622                        }
623                        else
624                        {
625                            for ( Implementation i : available.getImplementation() )
626                            {
627                                this.assertDependencyDoesNotOverrideFinalPropertyAndDoesNotFlagNonOverridenPropertyOverride(
628                                    modules, implementation, d, i, report );
629    
630                            }
631                        }
632                    }
633                }
634            }
635        }
636    
637        private void assertDependencyDoesNotOverrideFinalPropertyAndDoesNotFlagNonOverridenPropertyOverride(
638            final Modules modules, final Implementation implementation, final Dependency dependency,
639            final Implementation dependencyImplementation, final ModelObjectValidationReport report )
640        {
641            if ( dependency.getProperties() != null )
642            {
643                final Properties properties = modules.getProperties( dependencyImplementation.getIdentifier() );
644    
645                if ( properties != null )
646                {
647                    for ( Property override : dependency.getProperties().getProperty() )
648                    {
649                        final Property overriden = properties.getProperty( override.getName() );
650                        if ( overriden != null && overriden.isFinal() )
651                        {
652                            report.getDetails().add( this.createDetail(
653                                "IMPLEMENTATION_DEPENDENCY_FINAL_PROPERTY_CONSTRAINT", Level.SEVERE,
654                                "implementationDependencyFinalPropertyConstraint", new Object[]
655                                {
656                                    implementation.getIdentifier(), dependency.getName(),
657                                    dependencyImplementation.getIdentifier(), override.getName()
658                                }, new ObjectFactory().createImplementation( implementation ) ) );
659    
660                        }
661                        if ( overriden == null && override.isOverride() )
662                        {
663                            report.getDetails().add( this.createDetail(
664                                "IMPLEMENTATION_DEPENDENCY_OVERRIDE_PROPERTY_CONSTRAINT", Level.SEVERE,
665                                "implementationDependencyOverridePropertyConstraint", new Object[]
666                                {
667                                    implementation.getIdentifier(), dependency.getName(),
668                                    dependencyImplementation.getIdentifier(), override.getName()
669                                }, new ObjectFactory().createImplementation( implementation ) ) );
670    
671                        }
672                    }
673                }
674            }
675        }
676    
677        private void assertNoMissingMandatoryDependencies( final Modules modules, final Implementation implementation,
678                                                           final ModelObjectValidationReport report )
679        {
680            if ( implementation.getDependencies() != null )
681            {
682                for ( Dependency d : implementation.getDependencies().getDependency() )
683                {
684                    final Implementations available = modules.getImplementations( d.getIdentifier() );
685    
686                    if ( !d.isOptional() )
687                    {
688                        boolean missing = false;
689    
690                        if ( available == null )
691                        {
692                            missing = true;
693                        }
694                        else if ( available.getImplementation().isEmpty() )
695                        {
696                            missing = true;
697                        }
698                        else if ( d.getImplementationName() != null &&
699                                  available.getImplementationByName( d.getImplementationName() ) == null )
700                        {
701                            missing = true;
702                        }
703    
704                        if ( missing )
705                        {
706                            report.getDetails().add( this.createDetail(
707                                "IMPLEMENTATION_MANDATORY_DEPENDENCY_CONSTRAINT", Level.SEVERE,
708                                "implementationMandatoryDependencyConstraint", new Object[]
709                                {
710                                    implementation.getIdentifier(), d.getName()
711                                }, new ObjectFactory().createImplementation( implementation ) ) );
712    
713                        }
714                    }
715                }
716            }
717        }
718    
719        private void assertNoDependenciesWithoutSpecificationClass( final Modules modules,
720                                                                    final Implementation implementation,
721                                                                    final ModelObjectValidationReport report )
722        {
723            if ( implementation.getDependencies() != null )
724            {
725                for ( Dependency d : implementation.getDependencies().getDependency() )
726                {
727                    final Specification s = modules.getSpecification( d.getIdentifier() );
728    
729                    if ( s != null && s.getClazz() == null )
730                    {
731                        report.getDetails().add( this.createDetail(
732                            "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_CLASS_CONSTRAINT", Level.SEVERE,
733                            "implementationDependencySpecificationClassConstraint", new Object[]
734                            {
735                                implementation.getIdentifier(), d.getName(), d.getIdentifier()
736                            }, new ObjectFactory().createImplementation( implementation ) ) );
737    
738                    }
739                }
740            }
741        }
742    
743        private void assertImplementationInheritanceCompatibility( final Modules modules,
744                                                                   final Implementation implementation,
745                                                                   final ModelObjectValidationReport report )
746        {
747            if ( implementation.getImplementations() != null )
748            {
749                for ( ImplementationReference r : implementation.getImplementations().getReference() )
750                {
751                    final Implementation referenced = modules.getImplementation( r.getIdentifier() );
752                    if ( referenced != null && r.getVersion() != null )
753                    {
754                        if ( referenced.getVersion() == null )
755                        {
756                            report.getDetails().add( this.createDetail(
757                                "IMPLEMENTATION_IMPLEMENTATION_VERSIONING_CONSTRAINT", Level.SEVERE,
758                                "implementationImplementationVersioningConstraint", new Object[]
759                                {
760                                    implementation.getIdentifier(), referenced.getIdentifier()
761                                }, new ObjectFactory().createImplementation( implementation ) ) );
762    
763                        }
764                        else
765                        {
766                            try
767                            {
768                                if ( VersionParser.compare( r.getVersion(), referenced.getVersion() ) > 0 )
769                                {
770                                    report.getDetails().add( this.createDetail(
771                                        "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
772                                        "implementationInheritanceCompatibilityConstraint", new Object[]
773                                        {
774                                            implementation.getIdentifier(), referenced.getIdentifier(),
775                                            r.getVersion(), referenced.getVersion()
776                                        }, new ObjectFactory().createImplementation( implementation ) ) );
777    
778                                }
779                            }
780                            catch ( final ParseException e )
781                            {
782                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
783                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
784    
785                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
786                                report.getDetails().add( detail );
787                            }
788                            catch ( final TokenMgrError e )
789                            {
790                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
791                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
792    
793                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
794                                report.getDetails().add( detail );
795                            }
796                        }
797                    }
798                }
799            }
800        }
801    
802        private void assertImplementationOverrideConstraints( final Modules modules,
803                                                              final Implementation implementation,
804                                                              final ModelObjectValidationReport report )
805        {
806            final Implementations parentImplementations = new Implementations();
807            this.collectParentImplementations(
808                modules, implementation, parentImplementations, new Implementations(), false );
809    
810            if ( implementation.getImplementations() != null )
811            {
812                for ( ImplementationReference r : implementation.getImplementations().getReference() )
813                {
814                    final Implementation referenced = modules.getImplementation( r.getIdentifier() );
815                    final ImplementationReference parentReference = parentImplementations.getReference( r.getIdentifier() );
816    
817                    if ( referenced.isFinal() )
818                    {
819                        report.getDetails().add( this.createDetail(
820                            "IMPLEMENTATION_IMPLEMENTATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
821                            "implementationFinalImplementationConstraint", new Object[]
822                            {
823                                implementation.getIdentifier(), referenced.getIdentifier(),
824                            }, new ObjectFactory().createImplementation( implementation ) ) );
825    
826                    }
827                    if ( parentReference != null && parentReference.isFinal() )
828                    {
829                        report.getDetails().add( this.createDetail(
830                            "IMPLEMENTATION_IMPLEMENTATION_REFERENCE_INHERITANCE_CONSTRAINT", Level.SEVERE,
831                            "implementationFinalImplementatioReferenceConstraint", new Object[]
832                            {
833                                implementation.getIdentifier(), parentReference.getIdentifier(),
834                            }, new ObjectFactory().createImplementation( implementation ) ) );
835    
836                    }
837                    if ( r.isOverride() && parentReference == null )
838                    {
839                        report.getDetails().add( this.createDetail(
840                            "IMPLEMENTATION_IMPLEMENTATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
841                            "implementationImplementationOverrideConstraint", new Object[]
842                            {
843                                implementation.getIdentifier(), r.getIdentifier(),
844                            }, new ObjectFactory().createImplementation( implementation ) ) );
845    
846                    }
847                }
848            }
849        }
850    
851        private void assertSpecificationOverrideConstraints( final Modules modules,
852                                                             final Implementation implementation,
853                                                             final ModelObjectValidationReport report )
854        {
855            final Specifications parentSpecifications = new Specifications();
856            this.collectParentSpecifications( modules, implementation, parentSpecifications, new Implementations(), false );
857    
858            if ( implementation.getSpecifications() != null )
859            {
860                for ( SpecificationReference r : implementation.getSpecifications().getReference() )
861                {
862                    final SpecificationReference parent = parentSpecifications.getReference( r.getIdentifier() );
863    
864                    if ( r.isOverride() && parent == null )
865                    {
866                        report.getDetails().add( this.createDetail(
867                            "IMPLEMENTATION_SPECIFICATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
868                            "implementationSpecificationOverrideConstraint", new Object[]
869                            {
870                                implementation.getIdentifier(), r.getIdentifier(),
871                            }, new ObjectFactory().createImplementation( implementation ) ) );
872    
873                    }
874                    if ( parent != null && parent.isFinal() )
875                    {
876                        report.getDetails().add( this.createDetail(
877                            "IMPLEMENTATION_SPECIFICATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
878                            "implementationSpecificationFinalConstraint", new Object[]
879                            {
880                                implementation.getIdentifier(), r.getIdentifier(),
881                            }, new ObjectFactory().createImplementation( implementation ) ) );
882    
883                    }
884                }
885            }
886        }
887    
888        private void assertDependencyOverrideConstraints( final Modules modules,
889                                                          final Implementation implementation,
890                                                          final ModelObjectValidationReport report )
891        {
892            final Dependencies parentDependencies = new Dependencies();
893            this.collectParentDependencies( modules, implementation, parentDependencies, new Implementations(), false );
894    
895            if ( implementation.getDependencies() != null )
896            {
897                for ( Dependency d : implementation.getDependencies().getDependency() )
898                {
899                    final Dependency parent = parentDependencies.getDependency( d.getName() );
900                    if ( d.isOverride() && parent == null )
901                    {
902                        report.getDetails().add( this.createDetail(
903                            "IMPLEMENTATION_DEPENDENCY_OVERRIDE_CONSTRAINT", Level.SEVERE,
904                            "implementationDependencyOverrideConstraint", new Object[]
905                            {
906                                implementation.getIdentifier(), d.getName(),
907                            }, new ObjectFactory().createImplementation( implementation ) ) );
908    
909                    }
910                    if ( parent != null && parent.isFinal() )
911                    {
912                        report.getDetails().add( this.createDetail(
913                            "IMPLEMENTATION_DEPENDENCY_INHERITANCE_CONSTRAINT", Level.SEVERE,
914                            "implementationDependencyFinalConstraint", new Object[]
915                            {
916                                implementation.getIdentifier(), d.getName(),
917                            }, new ObjectFactory().createImplementation( implementation ) ) );
918    
919                    }
920                }
921            }
922        }
923    
924        private void assertMessageOverrideConstraints( final Modules modules,
925                                                       final Implementation implementation,
926                                                       final ModelObjectValidationReport report )
927        {
928            final Messages parentMessages = new Messages();
929            this.collectParentMessages( modules, implementation, parentMessages, new Implementations(), false );
930    
931            if ( implementation.getMessages() != null )
932            {
933                for ( Message m : implementation.getMessages().getMessage() )
934                {
935                    final Message parentMessage = parentMessages.getMessage( m.getName() );
936                    final MessageReference parentReference = parentMessages.getReference( m.getName() );
937    
938                    if ( m.isOverride() && parentMessage == null && parentReference == null )
939                    {
940                        report.getDetails().add( this.createDetail(
941                            "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT", Level.SEVERE,
942                            "implementationMessageOverrideConstraint", new Object[]
943                            {
944                                implementation.getIdentifier(), m.getName(),
945                            }, new ObjectFactory().createImplementation( implementation ) ) );
946    
947                    }
948                    if ( ( parentMessage != null && parentMessage.isFinal() ) ||
949                         ( parentReference != null && parentReference.isFinal() ) )
950                    {
951                        report.getDetails().add( this.createDetail(
952                            "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT", Level.SEVERE,
953                            "implementationMessageFinalConstraint", new Object[]
954                            {
955                                implementation.getIdentifier(), m.getName(),
956                            }, new ObjectFactory().createImplementation( implementation ) ) );
957    
958                    }
959                }
960                for ( MessageReference r : implementation.getMessages().getReference() )
961                {
962                    final Message parentMessage = parentMessages.getMessage( r.getName() );
963                    final MessageReference parentReference = parentMessages.getReference( r.getName() );
964    
965                    if ( r.isOverride() && parentMessage == null && parentReference == null )
966                    {
967                        report.getDetails().add( this.createDetail(
968                            "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT", Level.SEVERE,
969                            "implementationMessageOverrideConstraint", new Object[]
970                            {
971                                implementation.getIdentifier(), r.getName(),
972                            }, new ObjectFactory().createImplementation( implementation ) ) );
973    
974                    }
975                    if ( ( parentMessage != null && parentMessage.isFinal() ) ||
976                         ( parentReference != null && parentReference.isFinal() ) )
977                    {
978                        report.getDetails().add( this.createDetail(
979                            "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT", Level.SEVERE,
980                            "implementationMessageFinalConstraint", new Object[]
981                            {
982                                implementation.getIdentifier(), r.getName(),
983                            }, new ObjectFactory().createImplementation( implementation ) ) );
984    
985                    }
986                }
987            }
988        }
989    
990        private void assertPropertyOverrideConstraints( final Modules modules,
991                                                        final Implementation implementation,
992                                                        final ModelObjectValidationReport report )
993        {
994            final Properties parentProperties = new Properties();
995            this.collectParentProperties( modules, implementation, parentProperties, new Implementations(), false );
996    
997            if ( implementation.getProperties() != null )
998            {
999                for ( Property p : implementation.getProperties().getProperty() )
1000                {
1001                    final Property parentProperty = parentProperties.getProperty( p.getName() );
1002                    final PropertyReference parentReference = parentProperties.getReference( p.getName() );
1003    
1004                    if ( p.isOverride() && parentProperty == null && parentReference == null )
1005                    {
1006                        report.getDetails().add( this.createDetail(
1007                            "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT", Level.SEVERE,
1008                            "implementationPropertyOverrideConstraint", new Object[]
1009                            {
1010                                implementation.getIdentifier(), p.getName(),
1011                            }, new ObjectFactory().createImplementation( implementation ) ) );
1012    
1013                    }
1014                    if ( ( parentProperty != null && parentProperty.isFinal() ) ||
1015                         ( parentReference != null && parentReference.isFinal() ) )
1016                    {
1017                        report.getDetails().add( this.createDetail(
1018                            "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT", Level.SEVERE,
1019                            "implementationPropertyFinalConstraint", new Object[]
1020                            {
1021                                implementation.getIdentifier(), p.getName(),
1022                            }, new ObjectFactory().createImplementation( implementation ) ) );
1023    
1024                    }
1025                }
1026                for ( PropertyReference r : implementation.getProperties().getReference() )
1027                {
1028                    final Property parentProperty = parentProperties.getProperty( r.getName() );
1029                    final PropertyReference parentReference = parentProperties.getReference( r.getName() );
1030    
1031                    if ( r.isOverride() && parentProperty == null && parentReference == null )
1032                    {
1033                        report.getDetails().add( this.createDetail(
1034                            "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT", Level.SEVERE,
1035                            "implementationPropertyOverrideConstraint", new Object[]
1036                            {
1037                                implementation.getIdentifier(), r.getName(),
1038                            }, new ObjectFactory().createImplementation( implementation ) ) );
1039    
1040                    }
1041                    if ( ( parentProperty != null && parentProperty.isFinal() ) ||
1042                         ( parentReference != null && parentReference.isFinal() ) )
1043                    {
1044                        report.getDetails().add( this.createDetail(
1045                            "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT", Level.SEVERE,
1046                            "implementationPropertyFinalConstraint", new Object[]
1047                            {
1048                                implementation.getIdentifier(), r.getName(),
1049                            }, new ObjectFactory().createImplementation( implementation ) ) );
1050    
1051                    }
1052                }
1053            }
1054        }
1055    
1056        private void assertImplementationMessagesUniqueness(
1057            final Implementation implementation, final ModelObjectValidationReport report )
1058        {
1059            if ( implementation.getMessages() != null )
1060            {
1061                for ( Message m : implementation.getMessages().getMessage() )
1062                {
1063                    if ( implementation.getMessages().getReference( m.getName() ) != null )
1064                    {
1065                        report.getDetails().add( this.createDetail(
1066                            "IMPLEMENTATION_MESSAGES_UNIQUENESS_CONSTRAINT", Level.SEVERE,
1067                            "implementationMessagesUniquenessConstraint", new Object[]
1068                            {
1069                                implementation.getIdentifier(), m.getName(),
1070                            }, new ObjectFactory().createImplementation( implementation ) ) );
1071    
1072                    }
1073                }
1074            }
1075        }
1076    
1077        private void assertImplementationPropertiesUniqueness(
1078            final Implementation implementation, final ModelObjectValidationReport report )
1079        {
1080            if ( implementation.getProperties() != null )
1081            {
1082                for ( Property p : implementation.getProperties().getProperty() )
1083                {
1084                    if ( implementation.getProperties().getReference( p.getName() ) != null )
1085                    {
1086                        report.getDetails().add( this.createDetail(
1087                            "IMPLEMENTATION_PROPERTIES_UNIQUENESS_CONSTRAINT", Level.SEVERE,
1088                            "implementationPropertiesUniquenessConstraint", new Object[]
1089                            {
1090                                implementation.getIdentifier(), p.getName(),
1091                            }, new ObjectFactory().createImplementation( implementation ) ) );
1092    
1093                    }
1094                }
1095            }
1096        }
1097    
1098        private void assertNoInheritanceClashes( final Modules modules,
1099                                                 final Implementation implementation,
1100                                                 final ModelObjectValidationReport report )
1101        {
1102            if ( implementation.getImplementations() != null )
1103            {
1104                final Map<String, List<Dependency>> dependencyMap = new HashMap<String, List<Dependency>>();
1105                final Map<String, List<Message>> messageMap = new HashMap<String, List<Message>>();
1106                final Map<String, List<Property>> propertyMap = new HashMap<String, List<Property>>();
1107                final Map<String, List<SpecificationReference>> specMap =
1108                    new HashMap<String, List<SpecificationReference>>();
1109    
1110                for ( ImplementationReference r : implementation.getImplementations().getReference() )
1111                {
1112                    final Specifications currentSpecs = new Specifications();
1113                    final Dependencies currentDependencies = new Dependencies();
1114                    final Properties currentProperties = new Properties();
1115                    final Messages currentMessages = new Messages();
1116                    final Implementation current = modules.getImplementation( r.getIdentifier() );
1117    
1118                    modules.collectSpecifications( current, currentSpecs, new Implementations(), true );
1119                    modules.collectDependencies( current, currentDependencies, new Implementations(), true );
1120                    modules.collectMessages( current, currentMessages, new Implementations(), true );
1121                    modules.collectProperties( current, currentProperties, new Implementations(), true );
1122    
1123                    for ( SpecificationReference ref : currentSpecs.getReference() )
1124                    {
1125                        List<SpecificationReference> list = specMap.get( ref.getIdentifier() );
1126                        if ( list == null )
1127                        {
1128                            list = new LinkedList<SpecificationReference>();
1129                            specMap.put( ref.getIdentifier(), list );
1130                        }
1131    
1132                        list.add( ref );
1133                    }
1134    
1135                    for ( Dependency d : currentDependencies.getDependency() )
1136                    {
1137                        List<Dependency> list = dependencyMap.get( d.getName() );
1138                        if ( list == null )
1139                        {
1140                            list = new LinkedList<Dependency>();
1141                            dependencyMap.put( d.getName(), list );
1142                        }
1143    
1144                        list.add( d );
1145                    }
1146    
1147                    for ( Message msg : currentMessages.getMessage() )
1148                    {
1149                        List<Message> list = messageMap.get( msg.getName() );
1150                        if ( list == null )
1151                        {
1152                            list = new LinkedList<Message>();
1153                            messageMap.put( msg.getName(), list );
1154                        }
1155    
1156                        list.add( msg );
1157                    }
1158    
1159                    for ( Property p : currentProperties.getProperty() )
1160                    {
1161                        List<Property> list = propertyMap.get( p.getName() );
1162                        if ( list == null )
1163                        {
1164                            list = new LinkedList<Property>();
1165                            propertyMap.put( p.getName(), list );
1166                        }
1167    
1168                        list.add( p );
1169                    }
1170                }
1171    
1172                for ( Map.Entry<String, List<SpecificationReference>> e : specMap.entrySet() )
1173                {
1174                    if ( e.getValue().size() > 1 &&
1175                         ( implementation.getSpecifications() == null ||
1176                           implementation.getSpecifications().getReference( e.getKey() ) == null ) )
1177                    {
1178                        report.getDetails().add( this.createDetail(
1179                            "IMPLEMENTATION_SPECIFICATION_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1180                            "implementationMultipleInheritanceSpecificationConstraint", new Object[]
1181                            {
1182                                implementation.getIdentifier(), e.getKey()
1183                            }, new ObjectFactory().createImplementation( implementation ) ) );
1184    
1185                    }
1186                }
1187    
1188                for ( Map.Entry<String, List<Dependency>> e : dependencyMap.entrySet() )
1189                {
1190                    if ( e.getValue().size() > 1 &&
1191                         ( implementation.getDependencies() == null ||
1192                           implementation.getDependencies().getDependency( e.getKey() ) == null ) )
1193                    {
1194                        report.getDetails().add( this.createDetail(
1195                            "IMPLEMENTATION_DEPENDENCY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1196                            "implementationMultipleInheritanceDependencyConstraint", new Object[]
1197                            {
1198                                implementation.getIdentifier(), e.getKey()
1199                            }, new ObjectFactory().createImplementation( implementation ) ) );
1200    
1201                    }
1202                }
1203    
1204                for ( Map.Entry<String, List<Message>> e : messageMap.entrySet() )
1205                {
1206                    if ( e.getValue().size() > 1 &&
1207                         ( implementation.getMessages() == null ||
1208                           ( implementation.getMessages().getMessage( e.getKey() ) == null &&
1209                             implementation.getMessages().getReference( e.getKey() ) == null ) ) )
1210                    {
1211                        report.getDetails().add( this.createDetail(
1212                            "IMPLEMENTATION_MESSAGE_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1213                            "implementationMultipleInheritanceMessageConstraint", new Object[]
1214                            {
1215                                implementation.getIdentifier(), e.getKey()
1216                            }, new ObjectFactory().createImplementation( implementation ) ) );
1217    
1218                    }
1219                }
1220    
1221                for ( Map.Entry<String, List<Property>> e : propertyMap.entrySet() )
1222                {
1223                    if ( e.getValue().size() > 1 &&
1224                         ( implementation.getProperties() == null ||
1225                           ( implementation.getProperties().getProperty( e.getKey() ) == null &&
1226                             implementation.getProperties().getReference( e.getKey() ) == null ) ) )
1227                    {
1228                        report.getDetails().add( this.createDetail(
1229                            "IMPLEMENTATION_PROPERTY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1230                            "implementationMultipleInheritancePropertyConstraint", new Object[]
1231                            {
1232                                implementation.getIdentifier(), e.getKey()
1233                            }, new ObjectFactory().createImplementation( implementation ) ) );
1234    
1235                    }
1236                }
1237            }
1238        }
1239    
1240        private void assertSpecificationImplementationNameUniqueness( final Modules modules,
1241                                                                      final Specification specification,
1242                                                                      final ModelObjectValidationReport report )
1243        {
1244            final Implementations impls = modules.getImplementations( specification.getIdentifier() );
1245    
1246            if ( impls != null )
1247            {
1248                final Map<String, Implementations> map = new HashMap<String, Implementations>();
1249    
1250                for ( Implementation i : impls.getImplementation() )
1251                {
1252                    Implementations implementations = map.get( i.getName() );
1253                    if ( implementations == null )
1254                    {
1255                        implementations = new Implementations();
1256                        map.put( i.getName(), implementations );
1257                    }
1258    
1259                    implementations.getImplementation().add( i );
1260                }
1261    
1262                for ( Map.Entry<String, Implementations> e : map.entrySet() )
1263                {
1264                    if ( e.getValue().getImplementation().size() > 1 )
1265                    {
1266                        for ( Implementation i : e.getValue().getImplementation() )
1267                        {
1268                            report.getDetails().add( this.createDetail(
1269                                "SPECIFICATION_IMPLEMENTATION_NAME_UNIQUENESS_CONSTRAINT", Level.SEVERE,
1270                                "specificationImplementationNameConstraint", new Object[]
1271                                {
1272                                    i.getIdentifier(), specification.getIdentifier(), i.getName()
1273                                }, new ObjectFactory().createImplementation( i ) ) );
1274    
1275                        }
1276                    }
1277                }
1278            }
1279        }
1280    
1281        private void assertSpecificationMultiplicityConstraint( final Modules modules, final Specification specification,
1282                                                                final ModelObjectValidationReport report )
1283        {
1284            final Implementations impls = modules.getImplementations( specification.getIdentifier() );
1285    
1286            if ( specification.getMultiplicity() == Multiplicity.ONE &&
1287                 impls != null && impls.getImplementation().size() > 1 )
1288            {
1289                for ( Implementation i : impls.getImplementation() )
1290                {
1291                    report.getDetails().add( this.createDetail(
1292                        "SPECIFICATION_IMPLEMENTATION_MULTIPLICITY_CONSTRAINT", Level.SEVERE,
1293                        "specificationMultiplicityConstraint", new Object[]
1294                        {
1295                            i.getIdentifier(), specification.getIdentifier(), specification.getMultiplicity()
1296                        }, new ObjectFactory().createImplementation( i ) ) );
1297    
1298                }
1299            }
1300        }
1301    
1302        private void assertNoSpecificationPropertyReferenceDeclarations( final Specification specification,
1303                                                                         final ModelObjectValidationReport report )
1304        {
1305            if ( specification.getProperties() != null )
1306            {
1307                for ( PropertyReference r : specification.getProperties().getReference() )
1308                {
1309                    report.getDetails().add( this.createDetail(
1310                        "SPECIFICATION_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
1311                        "specificationPropertyReferenceDeclarationConstraint", new Object[]
1312                        {
1313                            specification.getIdentifier(), r.getName()
1314                        }, new ObjectFactory().createSpecification( specification ) ) );
1315    
1316                }
1317            }
1318        }
1319    
1320        private Implementation findInheritanceCycle( final Modules modules, final Implementation current,
1321                                                     final Implementation report, final Implementations implementations )
1322        {
1323            if ( current != null )
1324            {
1325                if ( implementations.getImplementation( current.getIdentifier() ) != null )
1326                {
1327                    return report;
1328                }
1329    
1330                implementations.getImplementation().add( current );
1331    
1332                if ( current.getImplementations() != null )
1333                {
1334                    for ( ImplementationReference r : current.getImplementations().getReference() )
1335                    {
1336                        return this.findInheritanceCycle( modules, modules.getImplementation( r.getIdentifier() ),
1337                                                          current, implementations );
1338    
1339                    }
1340    
1341                }
1342            }
1343    
1344            return null;
1345        }
1346    
1347        private void collectParentImplementations( final Modules modules, final Implementation implementation,
1348                                                   final Implementations implementations, final Implementations seen,
1349                                                   final boolean includeImplementation )
1350        {
1351            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1352            {
1353                seen.getImplementation().add( implementation );
1354    
1355                if ( includeImplementation &&
1356                     implementations.getImplementation( implementation.getIdentifier() ) == null )
1357                {
1358                    implementations.getImplementation().add( implementation );
1359                }
1360    
1361                if ( implementation.getImplementations() != null )
1362                {
1363                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1364                    {
1365                        if ( includeImplementation && implementations.getReference( r.getIdentifier() ) == null )
1366                        {
1367                            implementations.getReference().add( r );
1368                        }
1369    
1370                        this.collectParentImplementations( modules, modules.getImplementation( r.getIdentifier() ),
1371                                                           implementations, seen, true );
1372    
1373                    }
1374                }
1375            }
1376        }
1377    
1378        private void collectParentSpecifications( final Modules modules, final Implementation implementation,
1379                                                  final Specifications specifications, final Implementations seen,
1380                                                  final boolean includeImplementation )
1381        {
1382            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1383            {
1384                seen.getImplementation().add( implementation );
1385    
1386                if ( includeImplementation && implementation.getSpecifications() != null )
1387                {
1388                    for ( SpecificationReference r : implementation.getSpecifications().getReference() )
1389                    {
1390                        if ( specifications.getReference( r.getIdentifier() ) == null )
1391                        {
1392                            specifications.getReference().add( r );
1393                        }
1394                    }
1395                }
1396    
1397                if ( implementation.getImplementations() != null )
1398                {
1399                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1400                    {
1401                        this.collectParentSpecifications( modules, modules.getImplementation( r.getIdentifier() ),
1402                                                          specifications, seen, true );
1403    
1404                    }
1405                }
1406            }
1407        }
1408    
1409        private void collectParentDependencies( final Modules modules, final Implementation implementation,
1410                                                final Dependencies dependencies, final Implementations seen,
1411                                                final boolean includeImplementation )
1412        {
1413            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1414            {
1415                seen.getImplementation().add( implementation );
1416    
1417                if ( includeImplementation && implementation.getDependencies() != null )
1418                {
1419                    for ( Dependency d : implementation.getDependencies().getDependency() )
1420                    {
1421                        if ( dependencies.getDependency( d.getName() ) == null )
1422                        {
1423                            dependencies.getDependency().add( d );
1424                        }
1425                    }
1426                }
1427    
1428                if ( implementation.getImplementations() != null )
1429                {
1430                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1431                    {
1432                        this.collectParentDependencies( modules, modules.getImplementation( r.getIdentifier() ),
1433                                                        dependencies, seen, true );
1434    
1435                    }
1436                }
1437            }
1438        }
1439    
1440        private void collectParentMessages( final Modules modules, final Implementation implementation,
1441                                            final Messages messages, final Implementations seen,
1442                                            final boolean includeImplementation )
1443        {
1444            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1445            {
1446                seen.getImplementation().add( implementation );
1447    
1448                if ( includeImplementation && implementation.getMessages() != null )
1449                {
1450                    for ( Message m : implementation.getMessages().getMessage() )
1451                    {
1452                        if ( messages.getMessage( m.getName() ) == null )
1453                        {
1454                            messages.getMessage().add( m );
1455                        }
1456                    }
1457                    for ( MessageReference r : implementation.getMessages().getReference() )
1458                    {
1459                        if ( messages.getReference( r.getName() ) == null )
1460                        {
1461                            messages.getReference().add( r );
1462                        }
1463                    }
1464                }
1465    
1466                if ( implementation.getImplementations() != null )
1467                {
1468                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1469                    {
1470                        this.collectParentMessages( modules, modules.getImplementation( r.getIdentifier() ),
1471                                                    messages, seen, true );
1472    
1473                    }
1474                }
1475            }
1476        }
1477    
1478        private void collectParentProperties( final Modules modules, final Implementation implementation,
1479                                              final Properties properties, final Implementations seen,
1480                                              final boolean includeImplementation )
1481        {
1482            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1483            {
1484                seen.getImplementation().add( implementation );
1485    
1486                if ( includeImplementation && implementation.getProperties() != null )
1487                {
1488                    for ( Property p : implementation.getProperties().getProperty() )
1489                    {
1490                        if ( properties.getProperty( p.getName() ) == null )
1491                        {
1492                            properties.getProperty().add( p );
1493                        }
1494                    }
1495                    for ( PropertyReference r : implementation.getProperties().getReference() )
1496                    {
1497                        if ( properties.getReference( r.getName() ) == null )
1498                        {
1499                            properties.getReference().add( r );
1500                        }
1501                    }
1502                }
1503    
1504                if ( implementation.getImplementations() != null )
1505                {
1506                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1507                    {
1508                        this.collectParentProperties( modules, modules.getImplementation( r.getIdentifier() ),
1509                                                      properties, seen, true );
1510    
1511                    }
1512                }
1513            }
1514        }
1515    
1516        private ModelObjectValidationReport.Detail createDetail( final String identifier, final Level level,
1517                                                                 final String messageKey, final Object messageArguments,
1518                                                                 final JAXBElement<? extends ModelObject> element )
1519        {
1520            final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
1521                identifier, level, this.getMessage( messageKey, messageArguments ) );
1522    
1523            detail.setElement( element );
1524            return detail;
1525        }
1526    
1527        private String getMessage( final String key, final Object args )
1528        {
1529            return new MessageFormat( ResourceBundle.getBundle(
1530                DefaultModelObjectValidator.class.getName().replace( '.', '/' ),
1531                Locale.getDefault() ).getString( key ) ).format( args );
1532    
1533        }
1534    
1535    }
1536    
1537    /**
1538     * {@code ValidationEventHandler} collecting {@code ModelObjectValidationReport} details.
1539     *
1540     * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
1541     * @version $Id: DefaultModelObjectValidator.java 1093 2009-12-06 17:24:40Z schulte2005 $
1542     */
1543    class ModelObjectValidationEventHandler implements ValidationEventHandler
1544    {
1545    
1546        /** The report events are collected with. */
1547        private final ModelObjectValidationReport report;
1548    
1549        /**
1550         * Creates a new {@code ModelObjectValidationEventHandler} taking a {@code ModelObjectValidationReport} instance to
1551         * collect events with.
1552         *
1553         * @param report The report to use for collecting events.
1554         */
1555        ModelObjectValidationEventHandler( final ModelObjectValidationReport report )
1556        {
1557            this.report = report;
1558        }
1559    
1560        public boolean handleEvent( final ValidationEvent event )
1561        {
1562            if ( event == null )
1563            {
1564                throw new IllegalArgumentException( "event" );
1565            }
1566    
1567            switch ( event.getSeverity() )
1568            {
1569                case ValidationEvent.WARNING:
1570                    this.report.getDetails().add( new ModelObjectValidationReport.Detail(
1571                        "W3C XML 1.0 Recommendation - Warning condition", Level.WARNING, event.getMessage() ) );
1572    
1573                    return true;
1574    
1575                case ValidationEvent.ERROR:
1576                    this.report.getDetails().add( new ModelObjectValidationReport.Detail(
1577                        "W3C XML 1.0 Recommendation - Section 1.2 - Error", Level.SEVERE, event.getMessage() ) );
1578    
1579                    return false;
1580    
1581                case ValidationEvent.FATAL_ERROR:
1582                    this.report.getDetails().add( new ModelObjectValidationReport.Detail(
1583                        "W3C XML 1.0 Recommendation - Section 1.2 - Fatal Error", Level.SEVERE, event.getMessage() ) );
1584    
1585                    return false;
1586    
1587                default:
1588                    throw new AssertionError( event.getSeverity() );
1589    
1590            }
1591        }
1592    
1593    }