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 903 2009-11-03 05:58:11Z 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 903 2009-11-03 05:58:11Z 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.assertNoInheritanceCycle( modules.getValue(), i, report );
158                        this.assertNoInheritanceClashes( modules.getValue(), i, report );
159                        this.assertNoOverridenDependencyPropertiesWhenNotMultiton( modules.getValue(), i, report );
160                        this.assertImplementationOverrideConstraints( modules.getValue(), i, report );
161                        this.assertSpecificationOverrideConstraints( modules.getValue(), i, report );
162                        this.assertDependencyOverrideConstraints( modules.getValue(), i, report );
163                        this.assertMessageOverrideConstraints( modules.getValue(), i, report );
164                        this.assertPropertyOverrideConstraints( modules.getValue(), i, report );
165                    }
166                }
167    
168                if ( m.getSpecifications() != null )
169                {
170                    for ( Specification s : m.getSpecifications().getSpecification() )
171                    {
172                        this.assertNoSpecificationPropertyReferenceDeclarations( s, report );
173                        this.assertSpecificationImplementationNameUniqueness( modules.getValue(), s, report );
174                        this.assertSpecificationMultiplicityConstraint( modules.getValue(), s, report );
175                    }
176                }
177            }
178    
179            return report;
180        }
181    
182        private void assertNoSpecificationReferenceDeclarations( final Module module,
183                                                                 final ModelObjectValidationReport report )
184        {
185            if ( module.getSpecifications() != null )
186            {
187                for ( SpecificationReference r : module.getSpecifications().getReference() )
188                {
189                    report.getDetails().add( this.createDetail(
190                        "MODULE_SPECIFICATION_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
191                        "moduleSpecificationReferenceDeclarationConstraint", new Object[]
192                        {
193                            module.getName(), r.getIdentifier()
194                        }, new ObjectFactory().createModule( module ) ) );
195    
196                }
197            }
198        }
199    
200        private void assertNoImplementationReferenceDeclarations( final Module module,
201                                                                  final ModelObjectValidationReport report )
202        {
203            if ( module.getImplementations() != null )
204            {
205                for ( ImplementationReference r : module.getImplementations().getReference() )
206                {
207                    report.getDetails().add( this.createDetail(
208                        "MODULE_IMPLEMENTATION_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
209                        "moduleImplementationReferenceDeclarationConstraint", new Object[]
210                        {
211                            module.getName(), r.getIdentifier()
212                        }, new ObjectFactory().createModule( module ) ) );
213    
214                }
215            }
216        }
217    
218        private void assertNoMessageReferenceDeclarations( final Module module,
219                                                           final ModelObjectValidationReport report )
220        {
221            if ( module.getMessages() != null )
222            {
223                for ( MessageReference r : module.getMessages().getReference() )
224                {
225                    report.getDetails().add( this.createDetail(
226                        "MODULE_MESSAGE_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
227                        "moduleMessageReferenceDeclarationConstraint", new Object[]
228                        {
229                            module.getName(), r.getName()
230                        }, new ObjectFactory().createModule( module ) ) );
231    
232                }
233            }
234        }
235    
236        private void assertNoFinalMessageDeclarations( final Module module,
237                                                       final ModelObjectValidationReport report )
238        {
239            if ( module.getMessages() != null )
240            {
241                for ( Message m : module.getMessages().getMessage() )
242                {
243                    if ( m.isFinal() )
244                    {
245                        report.getDetails().add( this.createDetail(
246                            "MODULE_FINAL_MESSAGE_DECLARATION_CONSTRAINT", Level.SEVERE,
247                            "moduleFinalMessageConstraint", new Object[]
248                            {
249                                module.getName(), m.getName()
250                            }, new ObjectFactory().createModule( module ) ) );
251    
252                    }
253                }
254            }
255        }
256    
257        private void assertNoOverrideMessageDeclarations( final Module module,
258                                                          final ModelObjectValidationReport report )
259        {
260            if ( module.getMessages() != null )
261            {
262                for ( Message m : module.getMessages().getMessage() )
263                {
264                    if ( m.isOverride() )
265                    {
266                        report.getDetails().add( this.createDetail(
267                            "MODULE_OVERRIDE_MESSAGE_DECLARATION_CONSTRAINT", Level.SEVERE,
268                            "moduleOverrideMessageConstraint", new Object[]
269                            {
270                                module.getName(), m.getName()
271                            }, new ObjectFactory().createModule( module ) ) );
272    
273                    }
274                }
275            }
276        }
277    
278        private void assertNoPropertyReferenceDeclarations( final Module module,
279                                                            final ModelObjectValidationReport report )
280        {
281            if ( module.getProperties() != null )
282            {
283                for ( PropertyReference r : module.getProperties().getReference() )
284                {
285                    report.getDetails().add( this.createDetail(
286                        "MODULE_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
287                        "modulePropertyReferenceDeclarationConstraint", new Object[]
288                        {
289                            module.getName(), r.getName()
290                        }, new ObjectFactory().createModule( module ) ) );
291    
292                }
293            }
294        }
295    
296        private void assertNoFinalPropertyDeclarations( final Module module,
297                                                        final ModelObjectValidationReport report )
298        {
299            if ( module.getProperties() != null )
300            {
301                for ( Property p : module.getProperties().getProperty() )
302                {
303                    if ( p.isFinal() )
304                    {
305                        report.getDetails().add( this.createDetail(
306                            "MODULE_FINAL_PROPERTY_DECLARATION_CONSTRAINT", Level.SEVERE,
307                            "moduleFinalPropertyConstraint", new Object[]
308                            {
309                                module.getName(), p.getName()
310                            }, new ObjectFactory().createModule( module ) ) );
311    
312                    }
313                }
314            }
315        }
316    
317        private void assertNoOverridePropertyDeclarations( final Module module,
318                                                           final ModelObjectValidationReport report )
319        {
320            if ( module.getProperties() != null )
321            {
322                for ( Property p : module.getProperties().getProperty() )
323                {
324                    if ( p.isOverride() )
325                    {
326                        report.getDetails().add( this.createDetail(
327                            "MODULE_OVERRIDE_PROPERTY_DECLARATION_CONSTRAINT", Level.SEVERE,
328                            "moduleOverridePropertyConstraint", new Object[]
329                            {
330                                module.getName(), p.getName()
331                            }, new ObjectFactory().createModule( module ) ) );
332    
333                    }
334                }
335            }
336        }
337    
338        private void assertNoSpecificationDeclarations( final Implementation implementation,
339                                                        final ModelObjectValidationReport report )
340        {
341            if ( implementation.getSpecifications() != null )
342            {
343                for ( Specification s : implementation.getSpecifications().getSpecification() )
344                {
345                    report.getDetails().add( this.createDetail(
346                        "IMPLEMENTATION_SPECIFICATION_DECLARATION_CONSTRAINT", Level.SEVERE,
347                        "implementationSpecificationDeclarationConstraint", new Object[]
348                        {
349                            implementation.getIdentifier(), s.getIdentifier()
350                        }, new ObjectFactory().createImplementation( implementation ) ) );
351    
352                }
353            }
354        }
355    
356        private void assertNoImplementationDeclarations( final Implementation implementation,
357                                                         final ModelObjectValidationReport report )
358        {
359            if ( implementation.getImplementations() != null )
360            {
361                for ( Implementation i : implementation.getImplementations().getImplementation() )
362                {
363                    report.getDetails().add( this.createDetail(
364                        "IMPLEMENTATION_IMPLEMENTATION_DECLARATION_CONSTRAINT", Level.SEVERE,
365                        "implementationImplementationDeclarationConstraint", new Object[]
366                        {
367                            implementation.getIdentifier(), i.getIdentifier()
368                        }, new ObjectFactory().createImplementation( implementation ) ) );
369    
370                }
371            }
372        }
373    
374        private void assertNoLocationWhenAbstract( final Implementation implementation,
375                                                   final ModelObjectValidationReport report )
376        {
377            if ( implementation.isAbstract() && implementation.getLocation() != null )
378            {
379                report.getDetails().add( this.createDetail(
380                    "IMPLEMENTATION_ABSTRACT_LOCATION_DECLARATION_CONSTRAINT", Level.SEVERE,
381                    "implementationAbstractLocationDeclarationConstraint", new Object[]
382                    {
383                        implementation.getIdentifier(), implementation.getLocation()
384                    }, new ObjectFactory().createImplementation( implementation ) ) );
385    
386            }
387        }
388    
389        private void assertNoInheritanceCycle( final Modules modules,
390                                               final Implementation implementation,
391                                               final ModelObjectValidationReport report )
392        {
393            final Implementation cycle =
394                this.findInheritanceCycle( modules, implementation, implementation, new Implementations() );
395    
396            if ( cycle != null )
397            {
398                report.getDetails().add( this.createDetail(
399                    "IMPLEMENTATION_INHERITANCE_CYCLE_CONSTRAINT", Level.SEVERE,
400                    "implementationInheritanceCycleConstraint", new Object[]
401                    {
402                        implementation.getIdentifier(), cycle.getIdentifier()
403                    }, new ObjectFactory().createImplementation( implementation ) ) );
404    
405            }
406        }
407    
408        private void assertImplementationSpecificationCompatibility( final Modules modules,
409                                                                     final Implementation implementation,
410                                                                     final ModelObjectValidationReport report )
411        {
412            final Specifications specs = modules.getSpecifications( implementation.getIdentifier() );
413    
414            if ( specs != null )
415            {
416                for ( SpecificationReference r : specs.getReference() )
417                {
418                    final Specification s = specs.getSpecification( r.getIdentifier() );
419    
420                    if ( s != null && r.getVersion() != null )
421                    {
422                        if ( s.getVersion() == null )
423                        {
424                            report.getDetails().add( this.createDetail(
425                                "IMPLEMENTATION_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
426                                "implementationSpecificationVersioningConstraint", new Object[]
427                                {
428                                    implementation.getIdentifier(), s.getIdentifier()
429                                }, new ObjectFactory().createImplementation( implementation ) ) );
430    
431                        }
432                        else
433                        {
434                            try
435                            {
436                                if ( VersionParser.compare( r.getVersion(), s.getVersion() ) != 0 )
437                                {
438                                    final Module moduleOfImplementation =
439                                        modules.getModuleOfImplementation( implementation.getIdentifier() );
440    
441                                    final Module moduleOfSpecification =
442                                        modules.getModuleOfSpecification( s.getIdentifier() );
443    
444                                    report.getDetails().add( this.createDetail(
445                                        "IMPLEMENTATION_SPECIFICATION_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
446                                        "implementationSpecificationCompatibilityConstraint", new Object[]
447                                        {
448                                            implementation.getIdentifier(),
449                                            moduleOfImplementation != null ? moduleOfImplementation.getName() : "<>",
450                                            s.getIdentifier(),
451                                            moduleOfSpecification != null ? moduleOfSpecification.getName() : "<>",
452                                            r.getVersion(), s.getVersion()
453                                        }, new ObjectFactory().createImplementation( implementation ) ) );
454    
455                                }
456                            }
457                            catch ( final ParseException e )
458                            {
459                                final ModelObjectValidationReport.Detail d = new ModelObjectValidationReport.Detail(
460                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
461    
462                                d.setElement( new ObjectFactory().createImplementation( implementation ) );
463                                report.getDetails().add( d );
464                            }
465                            catch ( final TokenMgrError e )
466                            {
467                                final ModelObjectValidationReport.Detail d = new ModelObjectValidationReport.Detail(
468                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
469    
470                                d.setElement( new ObjectFactory().createImplementation( implementation ) );
471                                report.getDetails().add( d );
472                            }
473                        }
474                    }
475                }
476            }
477        }
478    
479        private void assertImplementationDependencyCompatibility( final Modules modules,
480                                                                  final Implementation implementation,
481                                                                  final ModelObjectValidationReport report )
482        {
483            final Dependencies dependencies = modules.getDependencies( implementation.getIdentifier() );
484            if ( dependencies != null )
485            {
486                for ( Dependency d : dependencies.getDependency() )
487                {
488                    final Specification s = modules.getSpecification( d.getIdentifier() );
489                    if ( s != null && d.getVersion() != null )
490                    {
491                        if ( s.getVersion() == null )
492                        {
493                            report.getDetails().add( this.createDetail(
494                                "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
495                                "implementationDependencySpecificationVersioningConstraint", new Object[]
496                                {
497                                    implementation.getIdentifier(), d.getName(), s.getIdentifier()
498                                }, new ObjectFactory().createImplementation( implementation ) ) );
499    
500                        }
501                        else
502                        {
503                            try
504                            {
505                                if ( VersionParser.compare( d.getVersion(), s.getVersion() ) > 0 )
506                                {
507                                    final Module moduleOfImplementation =
508                                        modules.getModuleOfImplementation( implementation.getIdentifier() );
509    
510                                    final Module moduleOfSpecification =
511                                        modules.getModuleOfSpecification( s.getIdentifier() );
512    
513                                    report.getDetails().add( this.createDetail(
514                                        "IMPLEMENTATION_DEPENDENCY_SPECIFICATION_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
515                                        "implementationDependencySpecificationCompatibilityConstraint", new Object[]
516                                        {
517                                            implementation.getIdentifier(),
518                                            moduleOfImplementation != null ? moduleOfImplementation.getName() : "<>",
519                                            s.getIdentifier(),
520                                            moduleOfSpecification != null ? moduleOfSpecification.getName() : "<>",
521                                            d.getVersion(), s.getVersion()
522                                        }, new ObjectFactory().createImplementation( implementation ) ) );
523    
524                                }
525                            }
526                            catch ( final ParseException e )
527                            {
528                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
529                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
530    
531                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
532                                report.getDetails().add( detail );
533                            }
534                            catch ( final TokenMgrError e )
535                            {
536                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
537                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
538    
539                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
540                                report.getDetails().add( detail );
541                            }
542                        }
543                    }
544                }
545            }
546        }
547    
548        private void assertNoDependencyPropertyReferenceDeclarations( final Implementation implementation,
549                                                                      final ModelObjectValidationReport report )
550        {
551            if ( implementation.getDependencies() != null )
552            {
553                for ( Dependency d : implementation.getDependencies().getDependency() )
554                {
555                    if ( d.getProperties() != null )
556                    {
557                        for ( PropertyReference r : d.getProperties().getReference() )
558                        {
559                            report.getDetails().add( this.createDetail(
560                                "IMPLEMENTATION_DEPENDENCY_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
561                                "implementationDependencyPropertyReferenceDeclarationConstraint", new Object[]
562                                {
563                                    implementation.getIdentifier(), d.getName(), r.getName()
564                                }, new ObjectFactory().createImplementation( implementation ) ) );
565    
566                        }
567                    }
568                }
569            }
570        }
571    
572        private void assertNoOverridenDependencyPropertiesWhenNotMultiton( final Modules modules,
573                                                                           final Implementation implementation,
574                                                                           final ModelObjectValidationReport report )
575        {
576            if ( implementation.getDependencies() != null )
577            {
578                for ( Dependency d : implementation.getDependencies().getDependency() )
579                {
580                    final Specification s = modules.getSpecification( d.getIdentifier() );
581    
582                    if ( s != null && s.getScope() != null && d.getProperties() != null )
583                    {
584                        for ( Property p : d.getProperties().getProperty() )
585                        {
586                            report.getDetails().add( this.createDetail(
587                                "IMPLEMENTATION_DEPENDENCY_PROPERTIES_OVERRIDE_CONSTRAINT", Level.SEVERE,
588                                "implementationDependencyPropertiesOverrideConstraint", new Object[]
589                                {
590                                    implementation.getIdentifier(), d.getName(), s.getIdentifier(), s.getScope(),
591                                    p.getName()
592                                }, new ObjectFactory().createImplementation( implementation ) ) );
593    
594                        }
595                    }
596                }
597            }
598        }
599    
600        private void assertNoMissingMandatoryDependencies( final Modules modules, final Implementation implementation,
601                                                           final ModelObjectValidationReport report )
602        {
603            if ( implementation.getDependencies() != null )
604            {
605                for ( Dependency d : implementation.getDependencies().getDependency() )
606                {
607                    final Implementations available = modules.getImplementations( d.getIdentifier() );
608    
609                    if ( !d.isOptional() )
610                    {
611                        boolean missing = false;
612    
613                        if ( available == null )
614                        {
615                            missing = true;
616                        }
617                        else if ( available.getImplementation().isEmpty() )
618                        {
619                            missing = true;
620                        }
621                        else if ( d.getImplementationName() != null &&
622                                  available.getImplementationByName( d.getImplementationName() ) == null )
623                        {
624                            missing = true;
625                        }
626    
627                        if ( missing )
628                        {
629                            report.getDetails().add( this.createDetail(
630                                "IMPLEMENTATION_MANDATORY_DEPENDENCY_CONSTRAINT", Level.SEVERE,
631                                "implementationMandatoryDependencyConstraint", new Object[]
632                                {
633                                    implementation.getIdentifier(), d.getName()
634                                }, new ObjectFactory().createImplementation( implementation ) ) );
635    
636                        }
637                    }
638                }
639            }
640        }
641    
642        private void assertImplementationInheritanceCompatibility( final Modules modules,
643                                                                   final Implementation implementation,
644                                                                   final ModelObjectValidationReport report )
645        {
646            if ( implementation.getImplementations() != null )
647            {
648                for ( ImplementationReference r : implementation.getImplementations().getReference() )
649                {
650                    final Implementation referenced = modules.getImplementation( r.getIdentifier() );
651                    if ( referenced != null && r.getVersion() != null )
652                    {
653                        if ( referenced.getVersion() == null )
654                        {
655                            report.getDetails().add( this.createDetail(
656                                "IMPLEMENTATION_IMPLEMENTATION_VERSIONING_CONSTRAINT", Level.SEVERE,
657                                "implementationImplementationVersioningConstraint", new Object[]
658                                {
659                                    implementation.getIdentifier(), referenced.getIdentifier()
660                                }, new ObjectFactory().createImplementation( implementation ) ) );
661    
662                        }
663                        else
664                        {
665                            try
666                            {
667                                if ( VersionParser.compare( r.getVersion(), referenced.getVersion() ) > 0 )
668                                {
669                                    report.getDetails().add( this.createDetail(
670                                        "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
671                                        "implementationInheritanceCompatibilityConstraint", new Object[]
672                                        {
673                                            implementation.getIdentifier(), referenced.getIdentifier(),
674                                            r.getVersion(), referenced.getVersion()
675                                        }, new ObjectFactory().createImplementation( implementation ) ) );
676    
677                                }
678                            }
679                            catch ( final ParseException e )
680                            {
681                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
682                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
683    
684                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
685                                report.getDetails().add( detail );
686                            }
687                            catch ( final TokenMgrError e )
688                            {
689                                final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
690                                    e.getClass().getSimpleName(), Level.SEVERE, e.getMessage() );
691    
692                                detail.setElement( new ObjectFactory().createImplementation( implementation ) );
693                                report.getDetails().add( detail );
694                            }
695                        }
696                    }
697                }
698            }
699        }
700    
701        private void assertImplementationOverrideConstraints( final Modules modules,
702                                                              final Implementation implementation,
703                                                              final ModelObjectValidationReport report )
704        {
705            final Implementations parentImplementations = new Implementations();
706            this.collectParentImplementations(
707                modules, implementation, parentImplementations, new Implementations(), false );
708    
709            if ( implementation.getImplementations() != null )
710            {
711                for ( ImplementationReference r : implementation.getImplementations().getReference() )
712                {
713                    final Implementation referenced = modules.getImplementation( r.getIdentifier() );
714                    final ImplementationReference parentReference = parentImplementations.getReference( r.getIdentifier() );
715    
716                    if ( referenced.isFinal() )
717                    {
718                        report.getDetails().add( this.createDetail(
719                            "IMPLEMENTATION_IMPLEMENTATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
720                            "implementationFinalImplementationConstraint", new Object[]
721                            {
722                                implementation.getIdentifier(), referenced.getIdentifier(),
723                            }, new ObjectFactory().createImplementation( implementation ) ) );
724    
725                    }
726                    if ( parentReference != null && parentReference.isFinal() )
727                    {
728                        report.getDetails().add( this.createDetail(
729                            "IMPLEMENTATION_IMPLEMENTATION_REFERENCE_INHERITANCE_CONSTRAINT", Level.SEVERE,
730                            "implementationFinalImplementatioReferenceConstraint", new Object[]
731                            {
732                                implementation.getIdentifier(), parentReference.getIdentifier(),
733                            }, new ObjectFactory().createImplementation( implementation ) ) );
734    
735                    }
736                    if ( r.isOverride() && parentReference == null )
737                    {
738                        report.getDetails().add( this.createDetail(
739                            "IMPLEMENTATION_IMPLEMENTATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
740                            "implementationImplementationOverrideConstraint", new Object[]
741                            {
742                                implementation.getIdentifier(), r.getIdentifier(),
743                            }, new ObjectFactory().createImplementation( implementation ) ) );
744    
745                    }
746                }
747            }
748        }
749    
750        private void assertSpecificationOverrideConstraints( final Modules modules,
751                                                             final Implementation implementation,
752                                                             final ModelObjectValidationReport report )
753        {
754            final Specifications parentSpecifications = new Specifications();
755            this.collectParentSpecifications( modules, implementation, parentSpecifications, new Implementations(), false );
756    
757            if ( implementation.getSpecifications() != null )
758            {
759                for ( SpecificationReference r : implementation.getSpecifications().getReference() )
760                {
761                    final SpecificationReference parent = parentSpecifications.getReference( r.getIdentifier() );
762    
763                    if ( r.isOverride() && parent == null )
764                    {
765                        report.getDetails().add( this.createDetail(
766                            "IMPLEMENTATION_SPECIFICATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
767                            "implementationSpecificationOverrideConstraint", new Object[]
768                            {
769                                implementation.getIdentifier(), r.getIdentifier(),
770                            }, new ObjectFactory().createImplementation( implementation ) ) );
771    
772                    }
773                    if ( parent != null && parent.isFinal() )
774                    {
775                        report.getDetails().add( this.createDetail(
776                            "IMPLEMENTATION_SPECIFICATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
777                            "implementationSpecificationFinalConstraint", new Object[]
778                            {
779                                implementation.getIdentifier(), r.getIdentifier(),
780                            }, new ObjectFactory().createImplementation( implementation ) ) );
781    
782                    }
783                }
784            }
785        }
786    
787        private void assertDependencyOverrideConstraints( final Modules modules,
788                                                          final Implementation implementation,
789                                                          final ModelObjectValidationReport report )
790        {
791            final Dependencies parentDependencies = new Dependencies();
792            this.collectParentDependencies( modules, implementation, parentDependencies, new Implementations(), false );
793    
794            if ( implementation.getDependencies() != null )
795            {
796                for ( Dependency d : implementation.getDependencies().getDependency() )
797                {
798                    final Dependency parent = parentDependencies.getDependency( d.getName() );
799                    if ( d.isOverride() && parent == null )
800                    {
801                        report.getDetails().add( this.createDetail(
802                            "IMPLEMENTATION_DEPENDENCY_OVERRIDE_CONSTRAINT", Level.SEVERE,
803                            "implementationDependencyOverrideConstraint", new Object[]
804                            {
805                                implementation.getIdentifier(), d.getName(),
806                            }, new ObjectFactory().createImplementation( implementation ) ) );
807    
808                    }
809                    if ( parent != null && parent.isFinal() )
810                    {
811                        report.getDetails().add( this.createDetail(
812                            "IMPLEMENTATION_DEPENDENCY_INHERITANCE_CONSTRAINT", Level.SEVERE,
813                            "implementationDependencyFinalConstraint", new Object[]
814                            {
815                                implementation.getIdentifier(), d.getName(),
816                            }, new ObjectFactory().createImplementation( implementation ) ) );
817    
818                    }
819                }
820            }
821        }
822    
823        private void assertMessageOverrideConstraints( final Modules modules,
824                                                       final Implementation implementation,
825                                                       final ModelObjectValidationReport report )
826        {
827            final Messages parentMessages = new Messages();
828            this.collectParentMessages( modules, implementation, parentMessages, new Implementations(), false );
829    
830            if ( implementation.getMessages() != null )
831            {
832                for ( Message m : implementation.getMessages().getMessage() )
833                {
834                    final Message parentMessage = parentMessages.getMessage( m.getName() );
835                    final MessageReference parentReference = parentMessages.getReference( m.getName() );
836    
837                    if ( m.isOverride() && parentMessage == null && parentReference == null )
838                    {
839                        report.getDetails().add( this.createDetail(
840                            "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT", Level.SEVERE,
841                            "implementationMessageOverrideConstraint", new Object[]
842                            {
843                                implementation.getIdentifier(), m.getName(),
844                            }, new ObjectFactory().createImplementation( implementation ) ) );
845    
846                    }
847                    if ( ( parentMessage != null && parentMessage.isFinal() ) ||
848                         ( parentReference != null && parentReference.isFinal() ) )
849                    {
850                        report.getDetails().add( this.createDetail(
851                            "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT", Level.SEVERE,
852                            "implementationMessageFinalConstraint", new Object[]
853                            {
854                                implementation.getIdentifier(), m.getName(),
855                            }, new ObjectFactory().createImplementation( implementation ) ) );
856    
857                    }
858                }
859                for ( MessageReference r : implementation.getMessages().getReference() )
860                {
861                    final Message parentMessage = parentMessages.getMessage( r.getName() );
862                    final MessageReference parentReference = parentMessages.getReference( r.getName() );
863    
864                    if ( r.isOverride() && parentMessage == null && parentReference == null )
865                    {
866                        report.getDetails().add( this.createDetail(
867                            "IMPLEMENTATION_MESSAGE_OVERRIDE_CONSTRAINT", Level.SEVERE,
868                            "implementationMessageOverrideConstraint", new Object[]
869                            {
870                                implementation.getIdentifier(), r.getName(),
871                            }, new ObjectFactory().createImplementation( implementation ) ) );
872    
873                    }
874                    if ( ( parentMessage != null && parentMessage.isFinal() ) ||
875                         ( parentReference != null && parentReference.isFinal() ) )
876                    {
877                        report.getDetails().add( this.createDetail(
878                            "IMPLEMENTATION_MESSAGE_INHERITANCE_CONSTRAINT", Level.SEVERE,
879                            "implementationMessageFinalConstraint", new Object[]
880                            {
881                                implementation.getIdentifier(), r.getName(),
882                            }, new ObjectFactory().createImplementation( implementation ) ) );
883    
884                    }
885                }
886            }
887        }
888    
889        private void assertPropertyOverrideConstraints( final Modules modules,
890                                                        final Implementation implementation,
891                                                        final ModelObjectValidationReport report )
892        {
893            final Properties parentProperties = new Properties();
894            this.collectParentProperties( modules, implementation, parentProperties, new Implementations(), false );
895    
896            if ( implementation.getProperties() != null )
897            {
898                for ( Property p : implementation.getProperties().getProperty() )
899                {
900                    final Property parentProperty = parentProperties.getProperty( p.getName() );
901                    final PropertyReference parentReference = parentProperties.getReference( p.getName() );
902    
903                    if ( p.isOverride() && parentProperty == null && parentReference == null )
904                    {
905                        report.getDetails().add( this.createDetail(
906                            "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT", Level.SEVERE,
907                            "implementationPropertyOverrideConstraint", new Object[]
908                            {
909                                implementation.getIdentifier(), p.getName(),
910                            }, new ObjectFactory().createImplementation( implementation ) ) );
911    
912                    }
913                    if ( ( parentProperty != null && parentProperty.isFinal() ) ||
914                         ( parentReference != null && parentReference.isFinal() ) )
915                    {
916                        report.getDetails().add( this.createDetail(
917                            "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT", Level.SEVERE,
918                            "implementationPropertyFinalConstraint", new Object[]
919                            {
920                                implementation.getIdentifier(), p.getName(),
921                            }, new ObjectFactory().createImplementation( implementation ) ) );
922    
923                    }
924                }
925                for ( PropertyReference r : implementation.getProperties().getReference() )
926                {
927                    final Property parentProperty = parentProperties.getProperty( r.getName() );
928                    final PropertyReference parentReference = parentProperties.getReference( r.getName() );
929    
930                    if ( r.isOverride() && parentProperty == null && parentReference == null )
931                    {
932                        report.getDetails().add( this.createDetail(
933                            "IMPLEMENTATION_PROPERTY_OVERRIDE_CONSTRAINT", Level.SEVERE,
934                            "implementationPropertyOverrideConstraint", new Object[]
935                            {
936                                implementation.getIdentifier(), r.getName(),
937                            }, new ObjectFactory().createImplementation( implementation ) ) );
938    
939                    }
940                    if ( ( parentProperty != null && parentProperty.isFinal() ) ||
941                         ( parentReference != null && parentReference.isFinal() ) )
942                    {
943                        report.getDetails().add( this.createDetail(
944                            "IMPLEMENTATION_PROPERTY_INHERITANCE_CONSTRAINT", Level.SEVERE,
945                            "implementationPropertyFinalConstraint", new Object[]
946                            {
947                                implementation.getIdentifier(), r.getName(),
948                            }, new ObjectFactory().createImplementation( implementation ) ) );
949    
950                    }
951                }
952            }
953        }
954    
955        private void assertImplementationMessagesUniqueness(
956            final Implementation implementation, final ModelObjectValidationReport report )
957        {
958            if ( implementation.getMessages() != null )
959            {
960                for ( Message m : implementation.getMessages().getMessage() )
961                {
962                    if ( implementation.getMessages().getReference( m.getName() ) != null )
963                    {
964                        report.getDetails().add( this.createDetail(
965                            "IMPLEMENTATION_MESSAGES_UNIQUENESS_CONSTRAINT", Level.SEVERE,
966                            "implementationMessagesUniquenessConstraint", new Object[]
967                            {
968                                implementation.getIdentifier(), m.getName(),
969                            }, new ObjectFactory().createImplementation( implementation ) ) );
970    
971                    }
972                }
973            }
974        }
975    
976        private void assertImplementationPropertiesUniqueness(
977            final Implementation implementation, final ModelObjectValidationReport report )
978        {
979            if ( implementation.getProperties() != null )
980            {
981                for ( Property p : implementation.getProperties().getProperty() )
982                {
983                    if ( implementation.getProperties().getReference( p.getName() ) != null )
984                    {
985                        report.getDetails().add( this.createDetail(
986                            "IMPLEMENTATION_PROPERTIES_UNIQUENESS_CONSTRAINT", Level.SEVERE,
987                            "implementationPropertiesUniquenessConstraint", new Object[]
988                            {
989                                implementation.getIdentifier(), p.getName(),
990                            }, new ObjectFactory().createImplementation( implementation ) ) );
991    
992                    }
993                }
994            }
995        }
996    
997        private void assertNoInheritanceClashes( final Modules modules,
998                                                 final Implementation implementation,
999                                                 final ModelObjectValidationReport report )
1000        {
1001            if ( implementation.getImplementations() != null )
1002            {
1003                final Map<String, List<Dependency>> dependencyMap = new HashMap<String, List<Dependency>>();
1004                final Map<String, List<Message>> messageMap = new HashMap<String, List<Message>>();
1005                final Map<String, List<Property>> propertyMap = new HashMap<String, List<Property>>();
1006                final Map<String, List<SpecificationReference>> specMap =
1007                    new HashMap<String, List<SpecificationReference>>();
1008    
1009                for ( ImplementationReference r : implementation.getImplementations().getReference() )
1010                {
1011                    final Specifications currentSpecs = new Specifications();
1012                    final Dependencies currentDependencies = new Dependencies();
1013                    final Properties currentProperties = new Properties();
1014                    final Messages currentMessages = new Messages();
1015                    final Implementation current = modules.getImplementation( r.getIdentifier() );
1016    
1017                    modules.collectSpecifications( current, currentSpecs, new Implementations(), true );
1018                    modules.collectDependencies( current, currentDependencies, new Implementations(), true );
1019                    modules.collectMessages( current, currentMessages, new Implementations(), true );
1020                    modules.collectProperties( current, currentProperties, new Implementations(), true );
1021    
1022                    for ( SpecificationReference ref : currentSpecs.getReference() )
1023                    {
1024                        List<SpecificationReference> list = specMap.get( ref.getIdentifier() );
1025                        if ( list == null )
1026                        {
1027                            list = new LinkedList<SpecificationReference>();
1028                            specMap.put( ref.getIdentifier(), list );
1029                        }
1030    
1031                        list.add( ref );
1032                    }
1033    
1034                    for ( Dependency d : currentDependencies.getDependency() )
1035                    {
1036                        List<Dependency> list = dependencyMap.get( d.getName() );
1037                        if ( list == null )
1038                        {
1039                            list = new LinkedList<Dependency>();
1040                            dependencyMap.put( d.getName(), list );
1041                        }
1042    
1043                        list.add( d );
1044                    }
1045    
1046                    for ( Message msg : currentMessages.getMessage() )
1047                    {
1048                        List<Message> list = messageMap.get( msg.getName() );
1049                        if ( list == null )
1050                        {
1051                            list = new LinkedList<Message>();
1052                            messageMap.put( msg.getName(), list );
1053                        }
1054    
1055                        list.add( msg );
1056                    }
1057    
1058                    for ( Property p : currentProperties.getProperty() )
1059                    {
1060                        List<Property> list = propertyMap.get( p.getName() );
1061                        if ( list == null )
1062                        {
1063                            list = new LinkedList<Property>();
1064                            propertyMap.put( p.getName(), list );
1065                        }
1066    
1067                        list.add( p );
1068                    }
1069                }
1070    
1071                for ( Map.Entry<String, List<SpecificationReference>> e : specMap.entrySet() )
1072                {
1073                    if ( e.getValue().size() > 1 &&
1074                         ( implementation.getSpecifications() == null ||
1075                           implementation.getSpecifications().getReference( e.getKey() ) == null ) )
1076                    {
1077                        report.getDetails().add( this.createDetail(
1078                            "IMPLEMENTATION_SPECIFICATION_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1079                            "implementationMultipleInheritanceSpecificationConstraint", new Object[]
1080                            {
1081                                implementation.getIdentifier(), e.getKey()
1082                            }, new ObjectFactory().createImplementation( implementation ) ) );
1083    
1084                    }
1085                }
1086    
1087                for ( Map.Entry<String, List<Dependency>> e : dependencyMap.entrySet() )
1088                {
1089                    if ( e.getValue().size() > 1 &&
1090                         ( implementation.getDependencies() == null ||
1091                           implementation.getDependencies().getDependency( e.getKey() ) == null ) )
1092                    {
1093                        report.getDetails().add( this.createDetail(
1094                            "IMPLEMENTATION_DEPENDENCY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1095                            "implementationMultipleInheritanceDependencyConstraint", new Object[]
1096                            {
1097                                implementation.getIdentifier(), e.getKey()
1098                            }, new ObjectFactory().createImplementation( implementation ) ) );
1099    
1100                    }
1101                }
1102    
1103                for ( Map.Entry<String, List<Message>> e : messageMap.entrySet() )
1104                {
1105                    if ( e.getValue().size() > 1 &&
1106                         ( implementation.getMessages() == null ||
1107                           ( implementation.getMessages().getMessage( e.getKey() ) == null &&
1108                             implementation.getMessages().getReference( e.getKey() ) == null ) ) )
1109                    {
1110                        report.getDetails().add( this.createDetail(
1111                            "IMPLEMENTATION_MESSAGE_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1112                            "implementationMultipleInheritanceMessageConstraint", new Object[]
1113                            {
1114                                implementation.getIdentifier(), e.getKey()
1115                            }, new ObjectFactory().createImplementation( implementation ) ) );
1116    
1117                    }
1118                }
1119    
1120                for ( Map.Entry<String, List<Property>> e : propertyMap.entrySet() )
1121                {
1122                    if ( e.getValue().size() > 1 &&
1123                         ( implementation.getProperties() == null ||
1124                           ( implementation.getProperties().getProperty( e.getKey() ) == null &&
1125                             implementation.getProperties().getReference( e.getKey() ) == null ) ) )
1126                    {
1127                        report.getDetails().add( this.createDetail(
1128                            "IMPLEMENTATION_PROPERTY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
1129                            "implementationMultipleInheritancePropertyConstraint", new Object[]
1130                            {
1131                                implementation.getIdentifier(), e.getKey()
1132                            }, new ObjectFactory().createImplementation( implementation ) ) );
1133    
1134                    }
1135                }
1136            }
1137        }
1138    
1139        private void assertSpecificationImplementationNameUniqueness( final Modules modules,
1140                                                                      final Specification specification,
1141                                                                      final ModelObjectValidationReport report )
1142        {
1143            final Implementations impls = modules.getImplementations( specification.getIdentifier() );
1144    
1145            if ( impls != null )
1146            {
1147                final Map<String, Implementations> map = new HashMap<String, Implementations>();
1148    
1149                for ( Implementation i : impls.getImplementation() )
1150                {
1151                    Implementations implementations = map.get( i.getName() );
1152                    if ( implementations == null )
1153                    {
1154                        implementations = new Implementations();
1155                        map.put( i.getName(), implementations );
1156                    }
1157    
1158                    implementations.getImplementation().add( i );
1159                }
1160    
1161                for ( Map.Entry<String, Implementations> e : map.entrySet() )
1162                {
1163                    if ( e.getValue().getImplementation().size() > 1 )
1164                    {
1165                        for ( Implementation i : e.getValue().getImplementation() )
1166                        {
1167                            report.getDetails().add( this.createDetail(
1168                                "SPECIFICATION_IMPLEMENTATION_NAME_UNIQUENESS_CONSTRAINT", Level.SEVERE,
1169                                "specificationImplementationNameConstraint", new Object[]
1170                                {
1171                                    i.getIdentifier(), specification.getIdentifier(), i.getName()
1172                                }, new ObjectFactory().createImplementation( i ) ) );
1173    
1174                        }
1175                    }
1176                }
1177            }
1178        }
1179    
1180        private void assertSpecificationMultiplicityConstraint( final Modules modules, final Specification specification,
1181                                                                final ModelObjectValidationReport report )
1182        {
1183            final Implementations impls = modules.getImplementations( specification.getIdentifier() );
1184    
1185            if ( specification.getMultiplicity() == Multiplicity.ONE &&
1186                 impls != null && impls.getImplementation().size() > 1 )
1187            {
1188                for ( Implementation i : impls.getImplementation() )
1189                {
1190                    report.getDetails().add( this.createDetail(
1191                        "SPECIFICATION_IMPLEMENTATION_MULTIPLICITY_CONSTRAINT", Level.SEVERE,
1192                        "specificationMultiplicityConstraint", new Object[]
1193                        {
1194                            i.getIdentifier(), specification.getIdentifier(), specification.getMultiplicity()
1195                        }, new ObjectFactory().createImplementation( i ) ) );
1196    
1197                }
1198            }
1199        }
1200    
1201        private void assertNoSpecificationPropertyReferenceDeclarations( final Specification specification,
1202                                                                         final ModelObjectValidationReport report )
1203        {
1204            if ( specification.getProperties() != null )
1205            {
1206                for ( PropertyReference r : specification.getProperties().getReference() )
1207                {
1208                    report.getDetails().add( this.createDetail(
1209                        "SPECIFICATION_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
1210                        "specificationPropertyReferenceDeclarationConstraint", new Object[]
1211                        {
1212                            specification.getIdentifier(), r.getName()
1213                        }, new ObjectFactory().createSpecification( specification ) ) );
1214    
1215                }
1216            }
1217        }
1218    
1219        private Implementation findInheritanceCycle( final Modules modules, final Implementation current,
1220                                                     final Implementation report, final Implementations implementations )
1221        {
1222            if ( current != null )
1223            {
1224                if ( implementations.getImplementation( current.getIdentifier() ) != null )
1225                {
1226                    return report;
1227                }
1228    
1229                implementations.getImplementation().add( current );
1230    
1231                if ( current.getImplementations() != null )
1232                {
1233                    for ( ImplementationReference r : current.getImplementations().getReference() )
1234                    {
1235                        return this.findInheritanceCycle( modules, modules.getImplementation( r.getIdentifier() ),
1236                                                          current, implementations );
1237    
1238                    }
1239    
1240                }
1241            }
1242    
1243            return null;
1244        }
1245    
1246        private void collectParentImplementations( final Modules modules, final Implementation implementation,
1247                                                   final Implementations implementations, final Implementations seen,
1248                                                   final boolean includeImplementation )
1249        {
1250            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1251            {
1252                seen.getImplementation().add( implementation );
1253    
1254                if ( includeImplementation &&
1255                     implementations.getImplementation( implementation.getIdentifier() ) == null )
1256                {
1257                    implementations.getImplementation().add( implementation );
1258                }
1259    
1260                if ( implementation.getImplementations() != null )
1261                {
1262                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1263                    {
1264                        if ( includeImplementation && implementations.getReference( r.getIdentifier() ) == null )
1265                        {
1266                            implementations.getReference().add( r );
1267                        }
1268    
1269                        this.collectParentImplementations( modules, modules.getImplementation( r.getIdentifier() ),
1270                                                           implementations, seen, true );
1271    
1272                    }
1273                }
1274            }
1275        }
1276    
1277        private void collectParentSpecifications( final Modules modules, final Implementation implementation,
1278                                                  final Specifications specifications, final Implementations seen,
1279                                                  final boolean includeImplementation )
1280        {
1281            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1282            {
1283                seen.getImplementation().add( implementation );
1284    
1285                if ( includeImplementation && implementation.getSpecifications() != null )
1286                {
1287                    for ( SpecificationReference r : implementation.getSpecifications().getReference() )
1288                    {
1289                        if ( specifications.getReference( r.getIdentifier() ) == null )
1290                        {
1291                            specifications.getReference().add( r );
1292                        }
1293                    }
1294                }
1295    
1296                if ( implementation.getImplementations() != null )
1297                {
1298                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1299                    {
1300                        this.collectParentSpecifications( modules, modules.getImplementation( r.getIdentifier() ),
1301                                                          specifications, seen, true );
1302    
1303                    }
1304                }
1305            }
1306        }
1307    
1308        private void collectParentDependencies( final Modules modules, final Implementation implementation,
1309                                                final Dependencies dependencies, final Implementations seen,
1310                                                final boolean includeImplementation )
1311        {
1312            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1313            {
1314                seen.getImplementation().add( implementation );
1315    
1316                if ( includeImplementation && implementation.getDependencies() != null )
1317                {
1318                    for ( Dependency d : implementation.getDependencies().getDependency() )
1319                    {
1320                        if ( dependencies.getDependency( d.getName() ) == null )
1321                        {
1322                            dependencies.getDependency().add( d );
1323                        }
1324                    }
1325                }
1326    
1327                if ( implementation.getImplementations() != null )
1328                {
1329                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1330                    {
1331                        this.collectParentDependencies( modules, modules.getImplementation( r.getIdentifier() ),
1332                                                        dependencies, seen, true );
1333    
1334                    }
1335                }
1336            }
1337        }
1338    
1339        private void collectParentMessages( final Modules modules, final Implementation implementation,
1340                                            final Messages messages, final Implementations seen,
1341                                            final boolean includeImplementation )
1342        {
1343            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1344            {
1345                seen.getImplementation().add( implementation );
1346    
1347                if ( includeImplementation && implementation.getMessages() != null )
1348                {
1349                    for ( Message m : implementation.getMessages().getMessage() )
1350                    {
1351                        if ( messages.getMessage( m.getName() ) == null )
1352                        {
1353                            messages.getMessage().add( m );
1354                        }
1355                    }
1356                    for ( MessageReference r : implementation.getMessages().getReference() )
1357                    {
1358                        if ( messages.getReference( r.getName() ) == null )
1359                        {
1360                            messages.getReference().add( r );
1361                        }
1362                    }
1363                }
1364    
1365                if ( implementation.getImplementations() != null )
1366                {
1367                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1368                    {
1369                        this.collectParentMessages( modules, modules.getImplementation( r.getIdentifier() ),
1370                                                    messages, seen, true );
1371    
1372                    }
1373                }
1374            }
1375        }
1376    
1377        private void collectParentProperties( final Modules modules, final Implementation implementation,
1378                                              final Properties properties, final Implementations seen,
1379                                              final boolean includeImplementation )
1380        {
1381            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
1382            {
1383                seen.getImplementation().add( implementation );
1384    
1385                if ( includeImplementation && implementation.getProperties() != null )
1386                {
1387                    for ( Property p : implementation.getProperties().getProperty() )
1388                    {
1389                        if ( properties.getProperty( p.getName() ) == null )
1390                        {
1391                            properties.getProperty().add( p );
1392                        }
1393                    }
1394                    for ( PropertyReference r : implementation.getProperties().getReference() )
1395                    {
1396                        if ( properties.getReference( r.getName() ) == null )
1397                        {
1398                            properties.getReference().add( r );
1399                        }
1400                    }
1401                }
1402    
1403                if ( implementation.getImplementations() != null )
1404                {
1405                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
1406                    {
1407                        this.collectParentProperties( modules, modules.getImplementation( r.getIdentifier() ),
1408                                                      properties, seen, true );
1409    
1410                    }
1411                }
1412            }
1413        }
1414    
1415        private ModelObjectValidationReport.Detail createDetail( final String identifier, final Level level,
1416                                                                 final String messageKey, final Object messageArguments,
1417                                                                 final JAXBElement<? extends ModelObject> element )
1418        {
1419            final ModelObjectValidationReport.Detail detail = new ModelObjectValidationReport.Detail(
1420                identifier, level, this.getMessage( messageKey, messageArguments ) );
1421    
1422            detail.setElement( element );
1423            return detail;
1424        }
1425    
1426        private String getMessage( final String key, final Object args )
1427        {
1428            return new MessageFormat( ResourceBundle.getBundle(
1429                DefaultModelObjectValidator.class.getName().replace( '.', '/' ),
1430                Locale.getDefault() ).getString( key ) ).format( args );
1431    
1432        }
1433    
1434    }
1435    
1436    /**
1437     * {@code ValidationEventHandler} collecting {@code ModelObjectValidationReport} details.
1438     *
1439     * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
1440     * @version $Id: DefaultModelObjectValidator.java 903 2009-11-03 05:58:11Z schulte2005 $
1441     */
1442    class ModelObjectValidationEventHandler implements ValidationEventHandler
1443    {
1444    
1445        /** The report events are collected with. */
1446        private final ModelObjectValidationReport report;
1447    
1448        /**
1449         * Creates a new {@code ModelObjectValidationEventHandler} taking a {@code ModelObjectValidationReport} instance to
1450         * collect events with.
1451         *
1452         * @param report The report to use for collecting events.
1453         */
1454        ModelObjectValidationEventHandler( final ModelObjectValidationReport report )
1455        {
1456            this.report = report;
1457        }
1458    
1459        public boolean handleEvent( final ValidationEvent event )
1460        {
1461            if ( event == null )
1462            {
1463                throw new IllegalArgumentException( "event" );
1464            }
1465    
1466            switch ( event.getSeverity() )
1467            {
1468                case ValidationEvent.WARNING:
1469                    this.report.getDetails().add( new ModelObjectValidationReport.Detail(
1470                        "W3C XML 1.0 Recommendation - Warning condition", Level.WARNING, event.getMessage() ) );
1471    
1472                    return true;
1473    
1474                case ValidationEvent.ERROR:
1475                    this.report.getDetails().add( new ModelObjectValidationReport.Detail(
1476                        "W3C XML 1.0 Recommendation - Section 1.2 - Error", Level.SEVERE, event.getMessage() ) );
1477    
1478                    return false;
1479    
1480                case ValidationEvent.FATAL_ERROR:
1481                    this.report.getDetails().add( new ModelObjectValidationReport.Detail(
1482                        "W3C XML 1.0 Recommendation - Section 1.2 - Fatal Error", Level.SEVERE, event.getMessage() ) );
1483    
1484                    return false;
1485    
1486                default:
1487                    throw new AssertionError( event.getSeverity() );
1488    
1489            }
1490        }
1491    
1492    }