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: DefaultModelManager.java 597 2009-09-25 23:33:29Z schulte2005 $
031     *
032     */
033    package org.jomc.model;
034    
035    import java.io.IOException;
036    import java.io.InputStream;
037    import java.io.Reader;
038    import java.io.StringReader;
039    import java.io.StringWriter;
040    import java.lang.reflect.Constructor;
041    import java.lang.reflect.InvocationTargetException;
042    import java.lang.reflect.Method;
043    import java.lang.reflect.Modifier;
044    import java.net.URI;
045    import java.net.URISyntaxException;
046    import java.net.URL;
047    import java.text.MessageFormat;
048    import java.util.ArrayList;
049    import java.util.Enumeration;
050    import java.util.HashMap;
051    import java.util.HashSet;
052    import java.util.Iterator;
053    import java.util.LinkedList;
054    import java.util.List;
055    import java.util.Locale;
056    import java.util.Map;
057    import java.util.ResourceBundle;
058    import java.util.Set;
059    import java.util.jar.Attributes;
060    import java.util.jar.Manifest;
061    import java.util.logging.Level;
062    import javax.xml.XMLConstants;
063    import javax.xml.bind.JAXBContext;
064    import javax.xml.bind.JAXBElement;
065    import javax.xml.bind.JAXBException;
066    import javax.xml.bind.Marshaller;
067    import javax.xml.bind.Unmarshaller;
068    import javax.xml.bind.util.JAXBResult;
069    import javax.xml.bind.util.JAXBSource;
070    import javax.xml.transform.ErrorListener;
071    import javax.xml.transform.Source;
072    import javax.xml.transform.Transformer;
073    import javax.xml.transform.TransformerConfigurationException;
074    import javax.xml.transform.TransformerException;
075    import javax.xml.transform.TransformerFactory;
076    import javax.xml.transform.URIResolver;
077    import javax.xml.transform.sax.SAXSource;
078    import javax.xml.transform.stream.StreamSource;
079    import javax.xml.validation.SchemaFactory;
080    import javax.xml.validation.Validator;
081    import org.jomc.model.bootstrap.BootstrapObject;
082    import org.jomc.model.bootstrap.Schema;
083    import org.jomc.model.bootstrap.Schemas;
084    import org.jomc.util.ParseException;
085    import org.jomc.util.TokenMgrError;
086    import org.jomc.util.VersionParser;
087    import org.jomc.util.WeakIdentityHashMap;
088    import org.w3c.dom.ls.LSInput;
089    import org.w3c.dom.ls.LSResourceResolver;
090    import org.xml.sax.EntityResolver;
091    import org.xml.sax.InputSource;
092    import org.xml.sax.SAXException;
093    
094    /**
095     * Default {@code ModelManager} implementation.
096     *
097     * <p><b>Classpath support</b><ul>
098     * <li>{@link #getClassLoader() }</li>
099     * <li>{@link #setClassLoader(java.lang.ClassLoader) }</li>
100     * <li>{@link #getDefaultDocumentLocation() }</li>
101     * <li>{@link #getClasspathModule(org.jomc.model.Modules) }</li>
102     * <li>{@link #getClasspathModules(java.lang.String) }</li>
103     * <li>{@link #getDefaultStylesheetLocation() }</li>
104     * <li>{@link #getClasspathTransformers(java.lang.String) }</li>
105     * </ul></p>
106     *
107     * <p><b>Logging</b><ul>
108     * <li>{@link #getListeners() }</li>
109     * <li>{@link #log(java.util.logging.Level, java.lang.String, java.lang.Throwable) }</li>
110     * </ul></p>
111     *
112     * <p><b>Model bootstrapping</b><ul>
113     * <li>{@link #getBootstrapContext() }</li>
114     * <li>{@link #getBootstrapDocumentLocation() }</li>
115     * <li>{@link #getBootstrapMarshaller(boolean, boolean) }</li>
116     * <li>{@link #getBootstrapObjectFactory() }</li>
117     * <li>{@link #getBootstrapSchema() }</li>
118     * <li>{@link #getBootstrapUnmarshaller(boolean) }</li>
119     * <li>{@link #validateBootstrapObject(javax.xml.bind.JAXBElement) }</li>
120     * <li>{@link #transformBootstrapObject(javax.xml.bind.JAXBElement, javax.xml.transform.Transformer) }</li>
121     * </ul></p>
122     *
123     * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
124     * @version $Id: DefaultModelManager.java 597 2009-09-25 23:33:29Z schulte2005 $
125     */
126    public class DefaultModelManager implements ModelManager
127    {
128        // SECTION-START[ModelManager]
129    
130        public ObjectFactory getObjectFactory()
131        {
132            if ( this.objectFactory == null )
133            {
134                this.objectFactory = new ObjectFactory();
135            }
136    
137            return this.objectFactory;
138        }
139    
140        public EntityResolver getEntityResolver()
141        {
142            if ( this.entityResolver == null )
143            {
144                this.entityResolver = new EntityResolver()
145                {
146    
147                    public InputSource resolveEntity( final String publicId, final String systemId )
148                        throws SAXException, IOException
149                    {
150                        if ( systemId == null )
151                        {
152                            throw new NullPointerException( "systemId" );
153                        }
154    
155                        InputSource schemaSource = null;
156    
157                        try
158                        {
159                            final Schema s = getSchemas().getSchema( publicId );
160                            if ( s != null )
161                            {
162                                schemaSource = new InputSource();
163                                schemaSource.setPublicId( publicId );
164    
165                                if ( s.getClasspathId() != null )
166                                {
167                                    schemaSource.setSystemId( getClassLoader().getResource( s.getClasspathId() ).
168                                        toExternalForm() );
169    
170                                }
171                                else
172                                {
173                                    schemaSource.setSystemId( s.getSystemId() );
174                                }
175                            }
176    
177                            if ( schemaSource == null )
178                            {
179                                final URI systemUri = new URI( systemId );
180                                String schemaName = systemUri.getPath();
181                                if ( schemaName != null )
182                                {
183                                    final int lastIndexOfSlash = schemaName.lastIndexOf( '/' );
184                                    if ( lastIndexOfSlash != -1 && lastIndexOfSlash < schemaName.length() )
185                                    {
186                                        schemaName = schemaName.substring( lastIndexOfSlash + 1 );
187                                    }
188    
189                                    for ( URL url : getSchemaResources() )
190                                    {
191                                        if ( url.getPath().endsWith( schemaName ) )
192                                        {
193                                            schemaSource = new InputSource();
194                                            schemaSource.setPublicId( publicId );
195                                            schemaSource.setSystemId( url.toExternalForm() );
196    
197                                            log( Level.FINE, getMessage( "resolvedSystemIdUri", new Object[]
198                                                {
199                                                    systemUri.toASCIIString(),
200                                                    schemaSource.getSystemId()
201                                                } ), null );
202    
203                                            break;
204                                        }
205                                    }
206                                }
207                                else
208                                {
209                                    log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
210                                        {
211                                            systemId, systemUri.toASCIIString()
212                                        } ), null );
213    
214                                    schemaSource = null;
215                                }
216                            }
217                        }
218                        catch ( final URISyntaxException e )
219                        {
220                            log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
221                                {
222                                    systemId, e.getMessage()
223                                } ), null );
224    
225                            schemaSource = null;
226                        }
227                        catch ( final JAXBException e )
228                        {
229                            throw (IOException) new IOException( e.getMessage() ).initCause( e );
230                        }
231    
232                        return schemaSource;
233                    }
234    
235                };
236            }
237    
238            return this.entityResolver;
239        }
240    
241        public LSResourceResolver getLSResourceResolver()
242        {
243            if ( this.resourceResolver == null )
244            {
245                this.resourceResolver = new LSResourceResolver()
246                {
247    
248                    public LSInput resolveResource( final String type, final String namespaceURI, final String publicId,
249                                                    final String systemId, final String baseURI )
250                    {
251                        LSInput input = null;
252                        try
253                        {
254                            final InputSource schemaSource = getEntityResolver().resolveEntity( publicId, systemId );
255    
256                            if ( schemaSource != null )
257                            {
258                                input = new LSInput()
259                                {
260    
261                                    public Reader getCharacterStream()
262                                    {
263                                        return schemaSource.getCharacterStream();
264                                    }
265    
266                                    public void setCharacterStream( final Reader characterStream )
267                                    {
268                                        throw new UnsupportedOperationException();
269                                    }
270    
271                                    public InputStream getByteStream()
272                                    {
273                                        return schemaSource.getByteStream();
274                                    }
275    
276                                    public void setByteStream( final InputStream byteStream )
277                                    {
278                                        throw new UnsupportedOperationException();
279                                    }
280    
281                                    public String getStringData()
282                                    {
283                                        return null;
284                                    }
285    
286                                    public void setStringData( final String stringData )
287                                    {
288                                        throw new UnsupportedOperationException();
289                                    }
290    
291                                    public String getSystemId()
292                                    {
293                                        return schemaSource.getSystemId();
294                                    }
295    
296                                    public void setSystemId( final String systemId )
297                                    {
298                                        throw new UnsupportedOperationException();
299                                    }
300    
301                                    public String getPublicId()
302                                    {
303                                        return schemaSource.getPublicId();
304                                    }
305    
306                                    public void setPublicId( final String publicId )
307                                    {
308                                        throw new UnsupportedOperationException();
309                                    }
310    
311                                    public String getBaseURI()
312                                    {
313                                        return null;
314                                    }
315    
316                                    public void setBaseURI( final String baseURI )
317                                    {
318                                        throw new UnsupportedOperationException();
319                                    }
320    
321                                    public String getEncoding()
322                                    {
323                                        return schemaSource.getEncoding();
324                                    }
325    
326                                    public void setEncoding( final String encoding )
327                                    {
328                                        throw new UnsupportedOperationException();
329                                    }
330    
331                                    public boolean getCertifiedText()
332                                    {
333                                        return false;
334                                    }
335    
336                                    public void setCertifiedText( final boolean certifiedText )
337                                    {
338                                        throw new UnsupportedOperationException();
339                                    }
340    
341                                };
342                            }
343    
344                        }
345                        catch ( final SAXException e )
346                        {
347                            log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
348                                {
349                                    systemId, e.getMessage()
350                                } ), null );
351    
352                            input = null;
353                        }
354                        catch ( final IOException e )
355                        {
356                            log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
357                                {
358                                    systemId, e.getMessage()
359                                } ), null );
360    
361                            input = null;
362                        }
363    
364                        return input;
365                    }
366    
367                };
368            }
369    
370            return this.resourceResolver;
371        }
372    
373        public javax.xml.validation.Schema getSchema() throws IOException, SAXException, JAXBException
374        {
375            if ( this.schema == null )
376            {
377                final SchemaFactory f = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
378                final List<Source> sources = new ArrayList<Source>( this.getSchemas().getSchema().size() );
379    
380                for ( Schema s : this.getSchemas().getSchema() )
381                {
382                    sources.add( new StreamSource( this.getClassLoader().getResourceAsStream( s.getClasspathId() ),
383                                                   s.getSystemId() ) );
384    
385                }
386    
387                this.schema = f.newSchema( sources.toArray( new Source[ sources.size() ] ) );
388            }
389    
390            return this.schema;
391        }
392    
393        public JAXBContext getContext() throws IOException, SAXException, JAXBException
394        {
395            if ( this.context == null )
396            {
397                final StringBuilder pkgs = new StringBuilder();
398    
399                for ( final Iterator<Schema> s = this.getSchemas().getSchema().iterator(); s.hasNext(); )
400                {
401                    pkgs.append( s.next().getContextId() );
402                    if ( s.hasNext() )
403                    {
404                        pkgs.append( ':' );
405                    }
406                }
407    
408                if ( pkgs.length() == 0 )
409                {
410                    throw new IOException( this.getMessage( "missingSchemas", new Object[]
411                        {
412                            this.getBootstrapDocumentLocation()
413                        } ) );
414    
415                }
416    
417                this.context = JAXBContext.newInstance( pkgs.toString(), this.getClassLoader() );
418            }
419    
420            return this.context;
421        }
422    
423        public Marshaller getMarshaller( final boolean validating, final boolean formattedOutput )
424            throws IOException, SAXException, JAXBException
425        {
426            final Marshaller m = this.getContext().createMarshaller();
427            final StringBuilder schemaLocation = new StringBuilder();
428    
429            for ( final Iterator<Schema> it = this.getSchemas().getSchema().iterator(); it.hasNext(); )
430            {
431                final Schema s = it.next();
432                schemaLocation.append( s.getPublicId() ).append( ' ' ).append( s.getSystemId() );
433                if ( it.hasNext() )
434                {
435                    schemaLocation.append( ' ' );
436                }
437            }
438    
439            m.setProperty( Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation.toString() );
440            m.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );
441            m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.valueOf( formattedOutput ) );
442    
443            if ( validating )
444            {
445                m.setSchema( this.getSchema() );
446            }
447    
448            return m;
449        }
450    
451        public Unmarshaller getUnmarshaller( final boolean validating ) throws IOException, SAXException, JAXBException
452        {
453            final Unmarshaller u = this.getContext().createUnmarshaller();
454    
455            if ( validating )
456            {
457                u.setSchema( this.getSchema() );
458            }
459    
460            return u;
461        }
462    
463        public void validateModelObject( final JAXBElement<? extends ModelObject> modelObject )
464            throws ModelException, IOException, SAXException, JAXBException
465        {
466            if ( modelObject == null )
467            {
468                throw new NullPointerException( "modelObject" );
469            }
470    
471            final StringWriter stringWriter = new StringWriter();
472            final Validator validator = this.getSchema().newValidator();
473            final ModelExceptionErrorHandler errorHandler = new ModelExceptionErrorHandler();
474            validator.setErrorHandler( errorHandler );
475            this.getMarshaller( false, false ).marshal( modelObject, stringWriter );
476    
477            try
478            {
479                validator.validate( new StreamSource( new StringReader( stringWriter.toString() ) ) );
480            }
481            catch ( final SAXException e )
482            {
483                final ModelException modelException = new ModelException( e.getMessage(), e );
484                modelException.getDetails().addAll( errorHandler.getDetails() );
485                throw modelException;
486            }
487        }
488    
489        public void validateModules( final Modules modules )
490            throws ModelException, IOException, SAXException, JAXBException
491        {
492            if ( modules == null )
493            {
494                throw new NullPointerException( "modules" );
495            }
496    
497            this.validateModelObject( this.getObjectFactory().createModules( modules ) );
498            final List<ModelException.Detail> details = new LinkedList<ModelException.Detail>();
499    
500            try
501            {
502                for ( Module m : modules.getModule() )
503                {
504                    if ( m.getSpecifications() != null )
505                    {
506                        for ( SpecificationReference r : m.getSpecifications().getReference() )
507                        {
508                            details.add( this.newModuleSpecificationReferenceDeclarationConstraintDetail(
509                                this.getObjectFactory().createModule( m ), m, r ) );
510    
511                        }
512                    }
513    
514                    if ( m.getImplementations() != null )
515                    {
516                        for ( ImplementationReference r : m.getImplementations().getReference() )
517                        {
518                            details.add( this.newModuleImplementationReferenceDeclarationConstraintDetail(
519                                this.getObjectFactory().createImplementations( m.getImplementations() ), m, r ) );
520    
521                        }
522                    }
523    
524                    if ( m.getMessages() != null )
525                    {
526                        for ( Message msg : m.getMessages().getMessage() )
527                        {
528                            if ( msg.isFinal() )
529                            {
530                                details.add( this.newFinalModuleMessageConstraintDetail(
531                                    this.getObjectFactory().createMessage( msg ), m, msg ) );
532    
533                            }
534                            if ( msg.isOverride() )
535                            {
536                                details.add( this.newOverrideModuleMessageConstraintDetail(
537                                    this.getObjectFactory().createMessage( msg ), m, msg ) );
538    
539                            }
540                        }
541                        for ( MessageReference r : m.getMessages().getReference() )
542                        {
543                            details.add( this.newModuleMessageReferenceDeclarationConstraintDetail(
544                                this.getObjectFactory().createMessages( m.getMessages() ), m, r ) );
545    
546                        }
547                    }
548    
549                    if ( m.getProperties() != null )
550                    {
551                        for ( Property p : m.getProperties().getProperty() )
552                        {
553                            if ( p.isFinal() )
554                            {
555                                details.add( this.newFinalModulePropertyConstraintDetail(
556                                    this.getObjectFactory().createProperty( p ), m, p ) );
557    
558                            }
559                            if ( p.isOverride() )
560                            {
561                                details.add( this.newOverrideModulePropertyConstraintDetail(
562                                    this.getObjectFactory().createProperty( p ), m, p ) );
563    
564                            }
565                        }
566                        for ( PropertyReference r : m.getProperties().getReference() )
567                        {
568                            details.add( this.newModulePropertyReferenceDeclarationConstraintDetail(
569                                this.getObjectFactory().createProperties( m.getProperties() ), m, r ) );
570    
571                        }
572                    }
573    
574                    if ( m.getImplementations() != null )
575                    {
576                        for ( Implementation i : m.getImplementations().getImplementation() )
577                        {
578                            this.assertImplementationMessagesUniqueness( i, details );
579                            this.assertImplementationPropertiesUniqueness( i, details );
580    
581                            if ( i.getImplementations() != null )
582                            {
583                                for ( Implementation decl : i.getImplementations().getImplementation() )
584                                {
585                                    details.add( this.newImplementationImplementationDeclarationConstraintDetail(
586                                        this.getObjectFactory().createImplementations( i.getImplementations() ), i, decl ) );
587    
588                                }
589                            }
590    
591                            if ( i.getSpecifications() != null )
592                            {
593                                for ( Specification s : i.getSpecifications().getSpecification() )
594                                {
595                                    details.add( this.newImplementationSpecificationDeclarationConstraintDetail(
596                                        this.getObjectFactory().createImplementation( i ), i, s ) );
597    
598                                }
599                            }
600    
601                            if ( i.isAbstract() && i.getLocation() != null )
602                            {
603                                details.add( this.newAbstractLocationConstraintDetail(
604                                    this.getObjectFactory().createImplementation( i ), i, i.getLocation() ) );
605    
606                            }
607    
608                            final Implementation cycle = this.findInheritanceCycle( modules, i, i, new Implementations() );
609                            if ( cycle != null )
610                            {
611                                details.add( this.newImplementationInheritanceCycleConstraintDetail(
612                                    this.getObjectFactory().createImplementation( i ), i, cycle ) );
613    
614                            }
615    
616                            final Specifications specs = modules.getSpecifications( i.getIdentifier() );
617                            final Dependencies deps = modules.getDependencies( i.getIdentifier() );
618    
619                            if ( specs != null )
620                            {
621                                for ( SpecificationReference r : specs.getReference() )
622                                {
623                                    final Specification s = specs.getSpecification( r.getIdentifier() );
624    
625                                    if ( s != null && r.getVersion() != null )
626                                    {
627                                        if ( s.getVersion() == null )
628                                        {
629                                            details.add( this.newSpecificationVersioningConstraintDetail(
630                                                this.getObjectFactory().createSpecifications( specs ), i, s ) );
631    
632                                        }
633                                        else if ( VersionParser.compare( r.getVersion(), s.getVersion() ) != 0 )
634                                        {
635                                            final Module moduleOfSpecification =
636                                                modules.getModuleOfSpecification( s.getIdentifier() );
637    
638                                            details.add( this.newIncompatibleImplementationDetail(
639                                                this.getObjectFactory().createImplementation( i ),
640                                                i.getIdentifier(), m.getName(),
641                                                r.getIdentifier(), moduleOfSpecification == null
642                                                                   ? "<>" : moduleOfSpecification.getName(),
643                                                r.getVersion(), s.getVersion() ) );
644    
645                                        }
646                                    }
647                                }
648                            }
649    
650                            if ( deps != null )
651                            {
652                                for ( Dependency d : deps.getDependency() )
653                                {
654                                    final Specification s = modules.getSpecification( d.getIdentifier() );
655    
656                                    if ( s != null )
657                                    {
658                                        if ( d.getVersion() != null )
659                                        {
660                                            if ( s.getVersion() == null )
661                                            {
662                                                details.add( this.newSpecificationVersioningConstraintDetail(
663                                                    this.getObjectFactory().createDependency( d ), i, s ) );
664    
665                                            }
666                                            else if ( VersionParser.compare( d.getVersion(), s.getVersion() ) > 0 )
667                                            {
668                                                final Module moduleOfSpecification =
669                                                    modules.getModuleOfSpecification( s.getIdentifier() );
670    
671                                                details.add( this.newIncompatibleDependencyDetail(
672                                                    this.getObjectFactory().createDependency( d ),
673                                                    i.getIdentifier(), m.getName(),
674                                                    d.getIdentifier(), moduleOfSpecification == null
675                                                                       ? "<>" : moduleOfSpecification.getName(),
676                                                    d.getVersion(), s.getVersion() ) );
677    
678                                            }
679                                        }
680    
681                                        if ( d.getProperties() != null )
682                                        {
683                                            for ( PropertyReference r : d.getProperties().getReference() )
684                                            {
685                                                details.add( this.newDependencyPropertyReferenceDeclarationConstraintDetail(
686                                                    this.getObjectFactory().createDependency( d ), i, d, r ) );
687    
688                                            }
689    
690                                            if ( s.getScope() != null )
691                                            {
692                                                for ( Property p : d.getProperties().getProperty() )
693                                                {
694                                                    details.add( this.newDependencyPropertiesOverrideConstraintDetail(
695                                                        this.getObjectFactory().createDependency( d ), i, d, s, p ) );
696    
697                                                }
698                                            }
699                                        }
700                                    }
701    
702                                    final Implementations available = modules.getImplementations( d.getIdentifier() );
703    
704                                    if ( !d.isOptional() )
705                                    {
706                                        boolean missing = false;
707    
708                                        if ( available == null )
709                                        {
710                                            missing = true;
711                                        }
712                                        else if ( available.getImplementation().isEmpty() )
713                                        {
714                                            missing = true;
715                                        }
716                                        else if ( d.getImplementationName() != null &&
717                                                  available.getImplementationByName( d.getImplementationName() ) == null )
718                                        {
719                                            missing = true;
720                                        }
721    
722                                        if ( missing )
723                                        {
724                                            details.add( this.newMandatoryDependencyConstraintDetail(
725                                                this.getObjectFactory().createDependency( d ), i.getIdentifier(),
726                                                d.getName() ) );
727    
728                                        }
729                                    }
730                                }
731                            }
732    
733                            if ( i.getImplementations() != null )
734                            {
735                                final Implementations finalSuperImplementations = new Implementations();
736                                this.collectFinalSuperImplementations( modules, i, finalSuperImplementations,
737                                                                       new Implementations(), false );
738    
739                                for ( Implementation finalSuper : finalSuperImplementations.getImplementation() )
740                                {
741                                    details.add( this.newImplementationInheritanceConstraintDetail(
742                                        this.getObjectFactory().createImplementation( i ), i, finalSuper ) );
743    
744                                }
745    
746                                for ( ImplementationReference r : i.getImplementations().getReference() )
747                                {
748                                    final Implementation referenced = modules.getImplementation( r.getIdentifier() );
749                                    if ( referenced != null && r.getVersion() != null )
750                                    {
751                                        if ( referenced.getVersion() == null )
752                                        {
753                                            details.add( this.newImplementationVersioningConstraintDetail(
754                                                this.getObjectFactory().createImplementations( i.getImplementations() ),
755                                                i, referenced ) );
756    
757                                        }
758                                        else if ( VersionParser.compare( r.getVersion(), referenced.getVersion() ) > 0 )
759                                        {
760                                            details.add( this.newImplementationInheritanceCompatibilityConstraintDetail(
761                                                this.getObjectFactory().createImplementation( i ), i, referenced,
762                                                r.getVersion() ) );
763    
764                                        }
765                                    }
766                                }
767                            }
768    
769                            if ( i.getSpecifications() != null )
770                            {
771                                final Specifications superSpecifications = new Specifications();
772                                modules.collectSpecifications( i, superSpecifications, new Implementations(), false );
773    
774                                for ( SpecificationReference r : i.getSpecifications().getReference() )
775                                {
776                                    boolean override = false;
777    
778                                    if ( i.getImplementations() != null )
779                                    {
780                                        final Implementations finalSuperSpecifications = new Implementations();
781                                        this.collectFinalSuperSpecifications( modules, i, r.getIdentifier(),
782                                                                              finalSuperSpecifications,
783                                                                              new Implementations(), false );
784    
785                                        for ( Implementation finalSuper : finalSuperSpecifications.getImplementation() )
786                                        {
787                                            details.add( this.newSpecificationInheritanceConstraintDetail(
788                                                this.getObjectFactory().createImplementation( i ), i, r, finalSuper ) );
789    
790                                        }
791    
792                                        override = superSpecifications.getReference( r.getIdentifier() ) != null;
793                                    }
794    
795                                    if ( r.isOverride() && !override )
796                                    {
797                                        details.add( this.newSpecificationOverrideConstraintDetail(
798                                            this.getObjectFactory().createSpecifications( i.getSpecifications() ), i, r ) );
799    
800                                    }
801                                    if ( !r.isOverride() && override )
802                                    {
803                                        this.log( Level.WARNING, this.getMessage( "specificationOverrideWarning",
804                                                                                  new Object[]
805                                            {
806                                                i.getIdentifier(), r.getIdentifier()
807                                            } ), null );
808    
809                                    }
810                                }
811                            }
812    
813                            if ( i.getDependencies() != null )
814                            {
815                                final Dependencies superDependencies = new Dependencies();
816                                modules.collectDependencies( i, superDependencies, new Implementations(), false );
817    
818                                for ( Dependency d : i.getDependencies().getDependency() )
819                                {
820                                    boolean override = false;
821    
822                                    if ( i.getImplementations() != null )
823                                    {
824                                        final Implementations finalSuperDependencies = new Implementations();
825                                        this.collectFinalSuperDependencies( modules, i, d.getName(), finalSuperDependencies,
826                                                                            new Implementations(), false );
827    
828                                        for ( Implementation finalSuper : finalSuperDependencies.getImplementation() )
829                                        {
830                                            details.add( this.newDependencyInheritanceConstraintDetail(
831                                                this.getObjectFactory().createImplementation( i ), i, d, finalSuper ) );
832    
833                                        }
834    
835                                        override = superDependencies.getDependency( d.getName() ) != null;
836                                    }
837    
838                                    if ( d.isOverride() && !override )
839                                    {
840                                        details.add( this.newDependencyOverrideConstraintDetail(
841                                            this.getObjectFactory().createDependency( d ), i, d ) );
842    
843                                    }
844                                    if ( !d.isOverride() && override )
845                                    {
846                                        this.log( Level.WARNING, this.getMessage( "dependencyOverrideWarning", new Object[]
847                                            {
848                                                i.getIdentifier(), d.getName()
849                                            } ), null );
850    
851                                    }
852                                }
853                            }
854    
855                            if ( i.getProperties() != null )
856                            {
857                                final Properties superProperties = new Properties();
858                                modules.collectProperties( i, superProperties, new Implementations(), false );
859    
860                                for ( Property p : i.getProperties().getProperty() )
861                                {
862                                    boolean override = false;
863    
864                                    if ( i.getImplementations() != null )
865                                    {
866                                        final Implementations finalSuperProperties = new Implementations();
867                                        this.collectFinalSuperProperties( modules, i, p.getName(), finalSuperProperties,
868                                                                          new Implementations(), false );
869    
870                                        for ( Implementation finalSuper : finalSuperProperties.getImplementation() )
871                                        {
872                                            details.add( this.newPropertyInheritanceConstraintDetail(
873                                                this.getObjectFactory().createImplementation( i ), i, p, finalSuper ) );
874    
875                                        }
876    
877                                        override = superProperties.getProperty( p.getName() ) != null;
878                                    }
879    
880                                    if ( p.isOverride() && !override )
881                                    {
882                                        details.add( this.newPropertyOverrideConstraintDetail(
883                                            this.getObjectFactory().createProperty( p ), i, p ) );
884    
885                                    }
886                                    if ( !p.isOverride() && override )
887                                    {
888                                        this.log( Level.WARNING, this.getMessage( "propertyOverrideWarning", new Object[]
889                                            {
890                                                i.getIdentifier(), p.getName()
891                                            } ), null );
892    
893                                    }
894                                }
895    
896                                for ( PropertyReference r : i.getProperties().getReference() )
897                                {
898                                    boolean override = false;
899    
900                                    if ( i.getImplementations() != null )
901                                    {
902                                        final Implementations finalSuperProperties = new Implementations();
903                                        this.collectFinalSuperProperties( modules, i, r.getName(), finalSuperProperties,
904                                                                          new Implementations(), false );
905    
906                                        for ( Implementation finalSuper : finalSuperProperties.getImplementation() )
907                                        {
908                                            details.add( this.newPropertyInheritanceConstraintDetail(
909                                                this.getObjectFactory().createImplementation( i ), i, r, finalSuper ) );
910    
911                                        }
912    
913                                        override = superProperties.getProperty( r.getName() ) != null;
914                                    }
915    
916                                    if ( r.isOverride() && !override )
917                                    {
918                                        details.add( this.newPropertyOverrideConstraintDetail(
919                                            this.getObjectFactory().createProperties( i.getProperties() ), i, r ) );
920    
921                                    }
922                                    if ( !r.isOverride() && override )
923                                    {
924                                        this.log( Level.WARNING, this.getMessage( "propertyOverrideWarning", new Object[]
925                                            {
926                                                i.getIdentifier(), r.getName()
927                                            } ), null );
928    
929                                    }
930                                }
931                            }
932    
933                            if ( i.getMessages() != null )
934                            {
935                                final Messages superMessages = new Messages();
936                                modules.collectMessages( i, superMessages, new Implementations(), false );
937    
938                                for ( Message msg : i.getMessages().getMessage() )
939                                {
940                                    boolean override = false;
941    
942                                    if ( i.getImplementations() != null )
943                                    {
944                                        final Implementations finalSuperMessages = new Implementations();
945                                        this.collectFinalSuperMessages( modules, i, msg.getName(), finalSuperMessages,
946                                                                        new Implementations(), false );
947    
948                                        for ( Implementation finalSuper : finalSuperMessages.getImplementation() )
949                                        {
950                                            details.add( this.newMessageInheritanceConstraintDetail(
951                                                this.getObjectFactory().createImplementation( i ), i, msg, finalSuper ) );
952    
953                                        }
954    
955                                        override = superMessages.getMessage( msg.getName() ) != null;
956                                    }
957    
958                                    if ( msg.isOverride() && !override )
959                                    {
960                                        details.add( this.newMessageOverrideConstraintDetail(
961                                            this.getObjectFactory().createMessage( msg ), i, msg ) );
962    
963                                    }
964                                    if ( !msg.isOverride() && override )
965                                    {
966                                        this.log( Level.WARNING, this.getMessage( "messageOverrideWarning", new Object[]
967                                            {
968                                                i.getIdentifier(), msg.getName()
969                                            } ), null );
970    
971                                    }
972                                }
973    
974                                for ( MessageReference r : i.getMessages().getReference() )
975                                {
976                                    boolean override = false;
977    
978                                    if ( i.getImplementations() != null )
979                                    {
980                                        final Implementations finalSuperMessages = new Implementations();
981                                        this.collectFinalSuperMessages( modules, i, r.getName(), finalSuperMessages,
982                                                                        new Implementations(), false );
983    
984                                        for ( Implementation finalSuper : finalSuperMessages.getImplementation() )
985                                        {
986                                            details.add( this.newMessageInheritanceConstraintDetail(
987                                                this.getObjectFactory().createImplementation( i ), i, r, finalSuper ) );
988    
989                                        }
990    
991                                        override = superMessages.getMessage( r.getName() ) != null;
992                                    }
993    
994                                    if ( r.isOverride() && !override )
995                                    {
996                                        details.add( this.newMessageOverrideConstraintDetail(
997                                            this.getObjectFactory().createMessages( i.getMessages() ), i, r ) );
998    
999                                    }
1000                                    if ( !r.isOverride() && override )
1001                                    {
1002                                        this.log( Level.WARNING, this.getMessage( "messageOverrideWarning", new Object[]
1003                                            {
1004                                                i.getIdentifier(), r.getName()
1005                                            } ), null );
1006    
1007                                    }
1008                                }
1009                            }
1010    
1011                            if ( i.getImplementations() != null )
1012                            {
1013                                final Map<String, List<SpecificationReference>> specMap =
1014                                    new HashMap<String, List<SpecificationReference>>();
1015    
1016                                final Map<String, List<Dependency>> dependencyMap =
1017                                    new HashMap<String, List<Dependency>>();
1018    
1019                                final Map<String, List<Message>> messageMap =
1020                                    new HashMap<String, List<Message>>();
1021    
1022                                final Map<String, List<Property>> propertyMap =
1023                                    new HashMap<String, List<Property>>();
1024    
1025                                for ( ImplementationReference r : i.getImplementations().getReference() )
1026                                {
1027                                    final Specifications currentSpecs = new Specifications();
1028                                    final Dependencies currentDependencies = new Dependencies();
1029                                    final Properties currentProperties = new Properties();
1030                                    final Messages currentMessages = new Messages();
1031                                    final Implementation current = modules.getImplementation( r.getIdentifier() );
1032    
1033                                    modules.collectSpecifications( current, currentSpecs, new Implementations(), true );
1034                                    modules.collectDependencies( current, currentDependencies, new Implementations(), true );
1035                                    modules.collectMessages( current, currentMessages, new Implementations(), true );
1036                                    modules.collectProperties( current, currentProperties, new Implementations(), true );
1037    
1038                                    for ( SpecificationReference ref : currentSpecs.getReference() )
1039                                    {
1040                                        List<SpecificationReference> list = specMap.get( ref.getIdentifier() );
1041                                        if ( list == null )
1042                                        {
1043                                            list = new LinkedList<SpecificationReference>();
1044                                            specMap.put( ref.getIdentifier(), list );
1045                                        }
1046    
1047                                        list.add( ref );
1048                                    }
1049    
1050                                    for ( Dependency d : currentDependencies.getDependency() )
1051                                    {
1052                                        List<Dependency> list = dependencyMap.get( d.getName() );
1053                                        if ( list == null )
1054                                        {
1055                                            list = new LinkedList<Dependency>();
1056                                            dependencyMap.put( d.getName(), list );
1057                                        }
1058    
1059                                        list.add( d );
1060                                    }
1061    
1062                                    for ( Message msg : currentMessages.getMessage() )
1063                                    {
1064                                        List<Message> list = messageMap.get( msg.getName() );
1065                                        if ( list == null )
1066                                        {
1067                                            list = new LinkedList<Message>();
1068                                            messageMap.put( msg.getName(), list );
1069                                        }
1070    
1071                                        list.add( msg );
1072                                    }
1073    
1074                                    for ( Property p : currentProperties.getProperty() )
1075                                    {
1076                                        List<Property> list = propertyMap.get( p.getName() );
1077                                        if ( list == null )
1078                                        {
1079                                            list = new LinkedList<Property>();
1080                                            propertyMap.put( p.getName(), list );
1081                                        }
1082    
1083                                        list.add( p );
1084                                    }
1085                                }
1086    
1087                                for ( Map.Entry<String, List<SpecificationReference>> e : specMap.entrySet() )
1088                                {
1089                                    if ( e.getValue().size() > 1 &&
1090                                         ( i.getSpecifications() == null ||
1091                                           i.getSpecifications().getReference( e.getKey() ) == null ) )
1092                                    {
1093                                        details.add(
1094                                            this.newSpecificationMultipleInheritanceContraintDetail(
1095                                            this.getObjectFactory().createImplementation( i ), i, e.getValue().get( 0 ) ) );
1096    
1097                                    }
1098                                }
1099    
1100                                for ( Map.Entry<String, List<Dependency>> e : dependencyMap.entrySet() )
1101                                {
1102                                    if ( e.getValue().size() > 1 &&
1103                                         ( i.getDependencies() == null ||
1104                                           i.getDependencies().getDependency( e.getKey() ) == null ) )
1105                                    {
1106                                        details.add(
1107                                            this.newDependencyMultipleInheritanceContraintDetail(
1108                                            this.getObjectFactory().createImplementation( i ), i, e.getValue().get( 0 ) ) );
1109    
1110                                    }
1111                                }
1112    
1113                                for ( Map.Entry<String, List<Message>> e : messageMap.entrySet() )
1114                                {
1115                                    if ( e.getValue().size() > 1 &&
1116                                         ( i.getMessages() == null ||
1117                                           ( i.getMessages().getMessage( e.getKey() ) == null &&
1118                                             i.getMessages().getReference( e.getKey() ) == null ) ) )
1119                                    {
1120                                        details.add(
1121                                            this.newMessageMultipleInheritanceContraintDetail(
1122                                            this.getObjectFactory().createImplementation( i ), i, e.getValue().get( 0 ) ) );
1123    
1124                                    }
1125                                }
1126    
1127                                for ( Map.Entry<String, List<Property>> e : propertyMap.entrySet() )
1128                                {
1129                                    if ( e.getValue().size() > 1 &&
1130                                         ( i.getProperties() == null ||
1131                                           ( i.getProperties().getProperty( e.getKey() ) == null &&
1132                                             i.getProperties().getReference( e.getKey() ) == null ) ) )
1133                                    {
1134                                        details.add(
1135                                            this.newPropertyMultipleInheritanceContraintDetail(
1136                                            this.getObjectFactory().createImplementation( i ), i, e.getValue().get( 0 ) ) );
1137    
1138                                    }
1139                                }
1140                            }
1141                        }
1142                    }
1143    
1144                    if ( m.getSpecifications() != null )
1145                    {
1146                        for ( Specification s : m.getSpecifications().getSpecification() )
1147                        {
1148                            if ( s.getProperties() != null )
1149                            {
1150                                for ( PropertyReference r : s.getProperties().getReference() )
1151                                {
1152                                    details.add( this.newSpecificationPropertyReferenceDeclarationConstraintDetail(
1153                                        this.getObjectFactory().createSpecification( s ), s, r ) );
1154    
1155                                }
1156                            }
1157    
1158                            final Implementations impls = modules.getImplementations( s.getIdentifier() );
1159    
1160                            if ( impls != null )
1161                            {
1162                                final Map<String, Implementations> map = new HashMap<String, Implementations>();
1163    
1164                                for ( Implementation i : impls.getImplementation() )
1165                                {
1166                                    Implementations implementations = map.get( i.getName() );
1167                                    if ( implementations == null )
1168                                    {
1169                                        implementations = new Implementations();
1170                                        map.put( i.getName(), implementations );
1171                                    }
1172    
1173                                    implementations.getImplementation().add( i );
1174                                }
1175    
1176                                for ( Map.Entry<String, Implementations> e : map.entrySet() )
1177                                {
1178                                    if ( e.getValue().getImplementation().size() > 1 )
1179                                    {
1180                                        for ( Implementation i : e.getValue().getImplementation() )
1181                                        {
1182                                            details.add( this.newImplementationNameConstraintDetail(
1183                                                this.getObjectFactory().createSpecification( s ), s, i ) );
1184    
1185                                        }
1186                                    }
1187                                }
1188    
1189                                if ( s.getMultiplicity() == Multiplicity.ONE && impls.getImplementation().size() > 1 )
1190                                {
1191                                    for ( Implementation i : impls.getImplementation() )
1192                                    {
1193                                        details.add( this.newMultiplicityConstraintDetail(
1194                                            this.getObjectFactory().createImplementation( i ), s, i ) );
1195    
1196                                    }
1197                                }
1198                            }
1199                        }
1200                    }
1201                }
1202    
1203                if ( !details.isEmpty() )
1204                {
1205                    final ModelException modelException = new ModelException( this.getMessage( "validationFailed", null ) );
1206                    modelException.getDetails().addAll( details );
1207                    throw modelException;
1208                }
1209            }
1210            catch ( final TokenMgrError e )
1211            {
1212                throw new ModelException( e.getMessage(), e );
1213            }
1214            catch ( final ParseException e )
1215            {
1216                throw new ModelException( e.getMessage(), e );
1217            }
1218        }
1219    
1220        public <T extends ModelObject> T transformModelObject(
1221            final JAXBElement<T> modelObject, final Transformer transformer )
1222            throws IOException, SAXException, JAXBException, TransformerException
1223        {
1224            if ( modelObject == null )
1225            {
1226                throw new NullPointerException( "modelObject" );
1227            }
1228            if ( transformer == null )
1229            {
1230                throw new NullPointerException( "transformer" );
1231            }
1232    
1233            final JAXBContext ctx = this.getContext();
1234            final JAXBSource source = new JAXBSource( ctx, modelObject );
1235            final JAXBResult result = new JAXBResult( ctx );
1236            transformer.transform( source, result );
1237            return ( (JAXBElement<T>) result.getResult() ).getValue();
1238        }
1239    
1240        public Instance getInstance( final Modules modules, final Implementation implementation, final ClassLoader cl )
1241        {
1242            if ( modules == null )
1243            {
1244                throw new NullPointerException( "modules" );
1245            }
1246            if ( implementation == null )
1247            {
1248                throw new NullPointerException( "implementation" );
1249            }
1250            if ( cl == null )
1251            {
1252                throw new NullPointerException( "classLoader" );
1253            }
1254    
1255            final Instance instance = new Instance();
1256            instance.setIdentifier( implementation.getIdentifier() );
1257            instance.setImplementationName( implementation.getName() );
1258            instance.setClazz( implementation.getClazz() );
1259            instance.setClassLoader( cl );
1260            instance.setStateless( implementation.isStateless() );
1261            instance.setDependencies( modules.getDependencies( implementation.getIdentifier() ) );
1262            instance.setProperties( modules.getProperties( implementation.getIdentifier() ) );
1263            instance.setMessages( modules.getMessages( implementation.getIdentifier() ) );
1264            instance.setSpecifications( modules.getSpecifications( implementation.getIdentifier() ) );
1265            return instance;
1266        }
1267    
1268        public Instance getInstance( final Modules modules, final Implementation implementation,
1269                                     final Dependency dependency, final ClassLoader cl )
1270        {
1271            if ( modules == null )
1272            {
1273                throw new NullPointerException( "modules" );
1274            }
1275            if ( implementation == null )
1276            {
1277                throw new NullPointerException( "implementation" );
1278            }
1279            if ( dependency == null )
1280            {
1281                throw new NullPointerException( "dependency" );
1282            }
1283            if ( cl == null )
1284            {
1285                throw new NullPointerException( "cl" );
1286            }
1287    
1288            final Instance instance = this.getInstance( modules, implementation, cl );
1289            final Specification dependencySpecification = modules.getSpecification( dependency.getIdentifier() );
1290    
1291            if ( dependencySpecification != null && dependencySpecification.getScope() == null &&
1292                 dependency.getProperties() != null && !dependency.getProperties().getProperty().isEmpty() )
1293            {
1294                final Properties properties = new Properties();
1295                properties.getProperty().addAll( dependency.getProperties().getProperty() );
1296    
1297                if ( instance.getProperties() != null )
1298                {
1299                    for ( Property p : instance.getProperties().getProperty() )
1300                    {
1301                        if ( properties.getProperty( p.getName() ) == null )
1302                        {
1303                            properties.getProperty().add( p );
1304                        }
1305                    }
1306                }
1307    
1308                instance.setProperties( properties );
1309            }
1310    
1311            return instance;
1312        }
1313    
1314        public Instance getInstance( final Modules modules, final Object object )
1315        {
1316            if ( modules == null )
1317            {
1318                throw new NullPointerException( "modules" );
1319            }
1320            if ( object == null )
1321            {
1322                throw new NullPointerException( "object" );
1323            }
1324    
1325            synchronized ( this.objects )
1326            {
1327                Instance instance = (Instance) this.objects.get( object );
1328    
1329                if ( instance == null )
1330                {
1331                    final Implementation i = this.getImplementation( modules, object );
1332    
1333                    if ( i != null )
1334                    {
1335                        ClassLoader cl = object.getClass().getClassLoader();
1336                        if ( cl == null )
1337                        {
1338                            cl = ClassLoader.getSystemClassLoader();
1339                        }
1340    
1341                        instance = this.getInstance( modules, i, cl );
1342                        if ( instance != null )
1343                        {
1344                            this.objects.put( object, instance );
1345                        }
1346                    }
1347                }
1348    
1349                return instance;
1350            }
1351        }
1352    
1353        public Object getObject( final Modules modules, final Specification specification, final Instance instance )
1354            throws InstantiationException
1355        {
1356            if ( modules == null )
1357            {
1358                throw new NullPointerException( "modules" );
1359            }
1360            if ( specification == null )
1361            {
1362                throw new NullPointerException( "specification" );
1363            }
1364            if ( instance == null )
1365            {
1366                throw new NullPointerException( "instance" );
1367            }
1368    
1369            Object object = null;
1370    
1371            try
1372            {
1373                final Class specClass = Class.forName( specification.getClazz(), true, instance.getClassLoader() );
1374                final Class clazz = Class.forName( instance.getClazz(), true, instance.getClassLoader() );
1375    
1376                if ( Modifier.isPublic( clazz.getModifiers() ) )
1377                {
1378                    Constructor ctor = null;
1379    
1380                    try
1381                    {
1382                        ctor = clazz.getConstructor( NO_CLASSES );
1383                    }
1384                    catch ( final NoSuchMethodException e )
1385                    {
1386                        this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
1387                            {
1388                                e.getMessage()
1389                            } ), null );
1390    
1391                        ctor = null;
1392                    }
1393    
1394                    if ( ctor != null && specClass.isAssignableFrom( clazz ) )
1395                    {
1396                        synchronized ( this.objects )
1397                        {
1398                            object = clazz.newInstance();
1399                            this.objects.put( object, instance );
1400                        }
1401                    }
1402                    else
1403                    {
1404                        final StringBuilder methodNames = new StringBuilder().append( '[' );
1405                        Method factoryMethod = null;
1406                        String methodName = null;
1407    
1408                        char[] c = instance.getImplementationName().toCharArray();
1409                        c[0] = Character.toUpperCase( c[0] );
1410                        methodName = "get" + String.valueOf( c );
1411    
1412                        boolean javaIdentifier = Character.isJavaIdentifierStart( c[0] );
1413                        if ( javaIdentifier )
1414                        {
1415                            for ( int idx = c.length - 1; idx > 0; idx-- )
1416                            {
1417                                if ( !Character.isJavaIdentifierPart( c[idx] ) )
1418                                {
1419                                    javaIdentifier = false;
1420                                    break;
1421                                }
1422                            }
1423                        }
1424    
1425                        if ( javaIdentifier )
1426                        {
1427                            methodNames.append( methodName );
1428                            factoryMethod = this.getFactoryMethod( clazz, methodName );
1429                        }
1430    
1431                        if ( factoryMethod == null )
1432                        {
1433                            methodName = specification.getIdentifier().substring(
1434                                specification.getIdentifier().lastIndexOf( '.' ) + 1 );
1435    
1436                            c = methodName.toCharArray();
1437                            c[0] = Character.toUpperCase( c[0] );
1438    
1439                            javaIdentifier = Character.isJavaIdentifierStart( c[0] );
1440                            if ( javaIdentifier )
1441                            {
1442                                for ( int idx = c.length - 1; idx > 0; idx-- )
1443                                {
1444                                    if ( !Character.isJavaIdentifierPart( c[idx] ) )
1445                                    {
1446                                        javaIdentifier = false;
1447                                        break;
1448                                    }
1449                                }
1450                            }
1451    
1452                            if ( javaIdentifier )
1453                            {
1454                                methodName = "get" + String.valueOf( c );
1455                                methodNames.append( " " ).append( methodName );
1456                                factoryMethod = this.getFactoryMethod( clazz, methodName );
1457                            }
1458                        }
1459    
1460                        if ( factoryMethod == null )
1461                        {
1462                            methodName = "getObject";
1463                            methodNames.append( " " ).append( methodName );
1464                            factoryMethod = this.getFactoryMethod( clazz, methodName );
1465                        }
1466    
1467                        methodNames.append( ']' );
1468    
1469                        if ( factoryMethod == null )
1470                        {
1471                            throw new InstantiationException( this.getMessage( "missingFactoryMethod", new Object[]
1472                                {
1473                                    clazz.getName(), instance.getIdentifier(), methodNames.toString()
1474                                } ) );
1475    
1476                        }
1477    
1478                        if ( Modifier.isStatic( factoryMethod.getModifiers() ) )
1479                        {
1480                            object = factoryMethod.invoke( null, NO_OBJECTS );
1481                        }
1482                        else if ( ctor != null )
1483                        {
1484                            synchronized ( this.objects )
1485                            {
1486                                object = ctor.newInstance();
1487                                this.objects.put( object, instance );
1488                                object = factoryMethod.invoke( object, NO_OBJECTS );
1489                                this.objects.put( object, instance );
1490                            }
1491                        }
1492                        else
1493                        {
1494                            throw new InstantiationException( this.getMessage( "missingFactoryMethod", new Object[]
1495                                {
1496                                    clazz.getName(), instance.getIdentifier(), methodNames.toString()
1497                                } ) );
1498    
1499                        }
1500                    }
1501                }
1502    
1503                return object;
1504            }
1505            catch ( final InvocationTargetException e )
1506            {
1507                throw (InstantiationException) new InstantiationException().initCause(
1508                    e.getTargetException() != null ? e.getTargetException() : e );
1509    
1510            }
1511            catch ( final IllegalAccessException e )
1512            {
1513                throw (InstantiationException) new InstantiationException().initCause( e );
1514            }
1515            catch ( final ClassNotFoundException e )
1516            {
1517                throw (InstantiationException) new InstantiationException().initCause( e );
1518            }
1519        }
1520    
1521        // SECTION-END
1522        // SECTION-START[DefaultModelManager]
1523        /** Listener interface. */
1524        public interface Listener
1525        {
1526    
1527            /**
1528             * Get called on logging.
1529             *
1530             * @param level The level of the event.
1531             * @param message The message of the event or {@code null}.
1532             * @param t The throwable of the event or {@code null}.
1533             */
1534            void onLog( Level level, String message, Throwable t );
1535    
1536        }
1537    
1538        /**
1539         * Constant for the name of the classpath module.
1540         * @see #getClasspathModuleName()
1541         */
1542        private static final String DEFAULT_CLASSPATH_MODULE_NAME = "Java Classpath";
1543    
1544        /**
1545         * Classpath location searched for documents by default.
1546         * @see #getDefaultDocumentLocation()
1547         */
1548        private static final String DEFAULT_DOCUMENT_LOCATION = "META-INF/jomc.xml";
1549    
1550        /**
1551         * Classpath location searched for style sheets by default.
1552         * @see #getDefaultStylesheetLocation()
1553         */
1554        private static final String DEFAULT_STYLESHEET_LOCATION = "META-INF/jomc.xslt";
1555    
1556        /** Classpath location of the bootstrap schema. */
1557        private static final String BOOTSTRAP_SCHEMA_LOCATION =
1558            Schemas.class.getPackage().getName().replace( '.', '/' ) + "/jomc-bootstrap-1.0.xsd";
1559    
1560        /**
1561         * Classpath location searched for bootstrap documents by default.
1562         * @see #getBootstrapDocumentLocation()
1563         */
1564        private static final String DEFAULT_BOOTSTRAP_DOCUMENT_LOCATION = "META-INF/jomc-bootstrap.xml";
1565    
1566        /** JAXB context of the bootstrap schema. */
1567        private static final String BOOTSTRAP_CONTEXT = Schemas.class.getPackage().getName();
1568    
1569        /** Supported schema name extensions. */
1570        private static final String[] SCHEMA_EXTENSIONS = new String[]
1571        {
1572            "xsd"
1573        };
1574    
1575        /** Empty {@code Class} array. */
1576        private static final Class[] NO_CLASSES =
1577        {
1578        };
1579    
1580        /** Empty {@code Object} array. */
1581        private static final Object[] NO_OBJECTS =
1582        {
1583        };
1584    
1585        /** Class loader of the instance. */
1586        private ClassLoader classLoader;
1587    
1588        /** The entity resolver of the instance. */
1589        private EntityResolver entityResolver;
1590    
1591        /** The L/S resolver of the instance. */
1592        private LSResourceResolver resourceResolver;
1593    
1594        /** The context of the instance. */
1595        private JAXBContext context;
1596    
1597        /** The schema of the instance. */
1598        private javax.xml.validation.Schema schema;
1599    
1600        /** The bootstrap schema. */
1601        private javax.xml.validation.Schema bootstrapSchema;
1602    
1603        /** URLs of all available classpath schema resources. */
1604        private Set<URL> schemaResources;
1605    
1606        /** Schemas of the instance. */
1607        private Schemas schemas;
1608    
1609        /** Object factory of the instance. */
1610        private ObjectFactory objectFactory;
1611    
1612        /** Bootstrap object factory of the instance. */
1613        private org.jomc.model.bootstrap.ObjectFactory bootstrapObjectFactory;
1614    
1615        /** The listeners of the instance. */
1616        private List<Listener> listeners;
1617    
1618        /** Maps objects to {@code Instance}s. */
1619        private final Map objects = new WeakIdentityHashMap( 1024 );
1620    
1621        /** Creates a new {@code DefaultModelManager} instance. */
1622        public DefaultModelManager()
1623        {
1624            super();
1625        }
1626    
1627        /**
1628         * Gets the bootstrap object factory of the instance.
1629         *
1630         * @return The bootstrap object factory of the instance.
1631         */
1632        public org.jomc.model.bootstrap.ObjectFactory getBootstrapObjectFactory()
1633        {
1634            if ( this.bootstrapObjectFactory == null )
1635            {
1636                this.bootstrapObjectFactory = new org.jomc.model.bootstrap.ObjectFactory();
1637            }
1638    
1639            return this.bootstrapObjectFactory;
1640        }
1641    
1642        /**
1643         * Gets a new bootstrap context instance.
1644         *
1645         * @return A new bootstrap context instance.
1646         *
1647         * @throws JAXBException if creating a new bootstrap context instance fails.
1648         */
1649        public JAXBContext getBootstrapContext() throws JAXBException
1650        {
1651            return JAXBContext.newInstance( BOOTSTRAP_CONTEXT, this.getClassLoader() );
1652        }
1653    
1654        /**
1655         * Gets a new bootstrap {@code Marshaller}.
1656         *
1657         * @param validating {@code true} for a marshaller with additional schema validation support enabled; {@code false}
1658         * for a marshaller without additional schema validation support enabled.
1659         * @param formattedOutput {@code true} for the marshaller to produce formatted output; {@code false} for the
1660         * marshaller to not apply any formatting when marshalling.
1661         *
1662         * @return A new bootstrap {@code Marshaller}.
1663         *
1664         * @throws IOException if reading schema resources fails.
1665         * @throws SAXException if parsing schema resources fails.
1666         * @throws JAXBException if unmarshalling schema resources fails.
1667         */
1668        public Marshaller getBootstrapMarshaller( final boolean validating, final boolean formattedOutput )
1669            throws IOException, SAXException, JAXBException
1670        {
1671            final Marshaller m = this.getBootstrapContext().createMarshaller();
1672            m.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );
1673            m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.valueOf( formattedOutput ) );
1674    
1675            if ( validating )
1676            {
1677                m.setSchema( this.getBootstrapSchema() );
1678            }
1679    
1680            return m;
1681        }
1682    
1683        /**
1684         * Gets a new bootstrap {@code Unmarshaller}.
1685         *
1686         * @param validating {@code true} for an unmarshaller with additional schema validation support enabled;
1687         * {@code false} for an unmarshaller without additional schema validation support enabled.
1688         *
1689         * @return A new bootstrap {@code Unmarshaller}.
1690         *
1691         * @throws IOException if reading schema resources fails.
1692         * @throws SAXException if parsing schema resources fails.
1693         * @throws JAXBException if unmarshalling schema resources fails.
1694         */
1695        public Unmarshaller getBootstrapUnmarshaller( final boolean validating )
1696            throws IOException, SAXException, JAXBException
1697        {
1698            final Unmarshaller u = this.getBootstrapContext().createUnmarshaller();
1699            if ( validating )
1700            {
1701                u.setSchema( this.getBootstrapSchema() );
1702            }
1703    
1704            return u;
1705        }
1706    
1707        /**
1708         * Gets the bootstrap schema.
1709         *
1710         * @return The bootstrap schema.
1711         *
1712         * @throws SAXException if parsing the bootstrap schema fails.
1713         */
1714        public javax.xml.validation.Schema getBootstrapSchema() throws SAXException
1715        {
1716            if ( this.bootstrapSchema == null )
1717            {
1718                final URL url = this.getClassLoader().getResource( BOOTSTRAP_SCHEMA_LOCATION );
1719                this.log( Level.FINE, this.getMessage( "processing", new Object[]
1720                    {
1721                        url.toExternalForm()
1722                    } ), null );
1723    
1724                this.bootstrapSchema = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI ).newSchema( url );
1725            }
1726    
1727            return this.bootstrapSchema;
1728        }
1729    
1730        /**
1731         * Validates a given bootstrap object.
1732         *
1733         * @param bootstrapObject The object to validate.
1734         *
1735         * @throws NullPointerException if {@code bootstrapObject} is {@code null}.
1736         * @throws ModelException if {@code bootstrapObject} is invalid.
1737         * @throws IOException if reading schema resources fails.
1738         * @throws SAXException if parsing schema resources fails.
1739         * @throws JAXBException if unmarshalling schema resources fails.
1740         */
1741        public void validateBootstrapObject( final JAXBElement<? extends BootstrapObject> bootstrapObject )
1742            throws ModelException, IOException, SAXException, JAXBException
1743        {
1744            if ( bootstrapObject == null )
1745            {
1746                throw new NullPointerException( "bootstrapObject" );
1747            }
1748    
1749            final StringWriter stringWriter = new StringWriter();
1750            final Validator validator = this.getBootstrapSchema().newValidator();
1751            final ModelExceptionErrorHandler errorHandler = new ModelExceptionErrorHandler();
1752            validator.setErrorHandler( errorHandler );
1753            this.getBootstrapMarshaller( false, false ).marshal( bootstrapObject, stringWriter );
1754    
1755            try
1756            {
1757                validator.validate( new StreamSource( new StringReader( stringWriter.toString() ) ) );
1758            }
1759            catch ( final SAXException e )
1760            {
1761                final ModelException modelException = new ModelException( e.getMessage(), e );
1762                modelException.getDetails().addAll( errorHandler.getDetails() );
1763                throw modelException;
1764            }
1765        }
1766    
1767        /**
1768         * Transforms a given {@code BootstrapObject} with a given {@code Transformer}.
1769         *
1770         * @param bootstrapObject The {@code BootstrapObject} to transform.
1771         * @param transformer The {@code Transformer} to transform {@code bootstrapObject} with.
1772         * @param <T> The type of {@code bootstrapObject}.
1773         *
1774         * @return {@code bootstrapObject} transformed with {@code transformer}.
1775         *
1776         * @throws NullPointerException if {@code bootstrapObject} or {@code transformer} is {@code null}.
1777         * @throws IOException if reading schema resources fails.
1778         * @throws SAXException if parsing schema resources fails.
1779         * @throws JAXBException if binding fails.
1780         * @throws TransformerException if the transformation fails.
1781         */
1782        public <T extends BootstrapObject> T transformBootstrapObject(
1783            final JAXBElement<T> bootstrapObject, final Transformer transformer )
1784            throws IOException, SAXException, JAXBException, TransformerException
1785        {
1786            if ( bootstrapObject == null )
1787            {
1788                throw new NullPointerException( "bootstrapObject" );
1789            }
1790            if ( transformer == null )
1791            {
1792                throw new NullPointerException( "transformer" );
1793            }
1794    
1795            final JAXBContext ctx = this.getBootstrapContext();
1796            final JAXBSource source = new JAXBSource( ctx, bootstrapObject );
1797            final JAXBResult result = new JAXBResult( ctx );
1798            transformer.transform( source, result );
1799            return ( (JAXBElement<T>) result.getResult() ).getValue();
1800        }
1801    
1802        /**
1803         * Sets the object factory of the instance.
1804         *
1805         * @param value The new object factory of the instance or {@code null}.
1806         *
1807         * @see #getObjectFactory()
1808         */
1809        public void setObjectFactory( final ObjectFactory value )
1810        {
1811            this.objectFactory = value;
1812        }
1813    
1814        /**
1815         * Sets the entity resolver of the instance.
1816         *
1817         * @param value The new entity resolver of the instance or {@code null}.
1818         *
1819         * @see #getEntityResolver()
1820         */
1821        public void setEntityResolver( final EntityResolver value )
1822        {
1823            this.entityResolver = value;
1824        }
1825    
1826        /**
1827         * Sets the L/S resolver of the instance.
1828         *
1829         * @param value The new L/S resolver of the instance or {@code null}.
1830         *
1831         * @see #getLSResourceResolver()
1832         */
1833        public void setLSResourceResolver( final LSResourceResolver value )
1834        {
1835            this.resourceResolver = value;
1836        }
1837    
1838        /**
1839         * Sets the JAXB context of the instance.
1840         *
1841         * @param value The new JAXB context of the instance or {@code null}.
1842         *
1843         * @see #getContext()
1844         */
1845        public void setContext( final JAXBContext value )
1846        {
1847            this.context = value;
1848        }
1849    
1850        /**
1851         * Sets the schema of the instance.
1852         *
1853         * @param value The new schema of the instance or {@code null}.
1854         *
1855         * @see #getSchema()
1856         */
1857        public void setSchema( final javax.xml.validation.Schema value )
1858        {
1859            this.schema = value;
1860        }
1861    
1862        /**
1863         * Gets the list of registered listeners.
1864         *
1865         * @return The list of registered listeners.
1866         *
1867         * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
1868         */
1869        public List<Listener> getListeners()
1870        {
1871            if ( this.listeners == null )
1872            {
1873                this.listeners = new LinkedList<Listener>();
1874            }
1875    
1876            return this.listeners;
1877        }
1878    
1879        /**
1880         * Gets the location to search for bootstrap documents.
1881         * <p>The bootstrap document location is controlled by system property
1882         * {@code org.jomc.model.DefaultModelManager.bootstrapDocumentLocation} holding the location to search at. If that
1883         * property is not set, the {@code META-INF/jomc-bootstrap.xml} default is returned.</p>
1884         *
1885         * @return The location to search for bootstrap documents.
1886         *
1887         * @see #getSchemas()
1888         */
1889        public String getBootstrapDocumentLocation()
1890        {
1891            return System.getProperty( "org.jomc.model.DefaultModelManager.bootstrapDocumentLocation",
1892                                       DEFAULT_BOOTSTRAP_DOCUMENT_LOCATION );
1893    
1894        }
1895    
1896        /**
1897         * Gets the schemas backing the instance.
1898         *
1899         * @return The schemas backing the instance.
1900         *
1901         * @throws IOException if reading schema resources fails.
1902         * @throws SAXException if parsing schema resources fails.
1903         * @throws JAXBException if unmarshalling schema resources fails.
1904         *
1905         * @see #getBootstrapDocumentLocation()
1906         */
1907        public Schemas getSchemas() throws IOException, JAXBException, SAXException
1908        {
1909            if ( this.schemas == null )
1910            {
1911                this.schemas = new Schemas();
1912    
1913                final JAXBContext ctx = JAXBContext.newInstance( BOOTSTRAP_CONTEXT, this.getClassLoader() );
1914                final Unmarshaller u = ctx.createUnmarshaller();
1915                final String bootstrapLocation = this.getBootstrapDocumentLocation();
1916                this.log( Level.FINE, this.getMessage( "bootstrapLocation", new Object[]
1917                    {
1918                        bootstrapLocation
1919                    } ), null );
1920    
1921                final Enumeration<URL> e = this.getClassLoader().getResources( bootstrapLocation );
1922                u.setSchema( this.getBootstrapSchema() );
1923    
1924                while ( e.hasMoreElements() )
1925                {
1926                    final URL url = e.nextElement();
1927                    this.log( Level.FINE, this.getMessage( "processing", new Object[]
1928                        {
1929                            url.toExternalForm()
1930                        } ), null );
1931    
1932                    Object content = u.unmarshal( url );
1933                    if ( content instanceof JAXBElement )
1934                    {
1935                        content = ( (JAXBElement) content ).getValue();
1936                    }
1937    
1938                    if ( content instanceof Schema )
1939                    {
1940                        final Schema s = (Schema) content;
1941                        this.log( Level.FINE, this.getMessage( "addingSchema", new Object[]
1942                            {
1943                                s.getPublicId(), s.getSystemId(), s.getContextId(), s.getClasspathId()
1944                            } ), null );
1945    
1946                        this.schemas.getSchema().add( s );
1947                    }
1948                    else if ( content instanceof Schemas )
1949                    {
1950                        for ( Schema s : ( (Schemas) content ).getSchema() )
1951                        {
1952                            this.log( Level.FINE, this.getMessage( "addingSchema", new Object[]
1953                                {
1954                                    s.getPublicId(), s.getSystemId(), s.getContextId(), s.getClasspathId()
1955                                } ), null );
1956    
1957                            this.schemas.getSchema().add( s );
1958                        }
1959                    }
1960                }
1961            }
1962    
1963            return this.schemas;
1964        }
1965    
1966        /**
1967         * Gets the default location to search for documents.
1968         * <p>The default document location is controlled by system property
1969         * {@code org.jomc.model.DefaultModelManager.defaultDocumentLocation} holding the location to search at by default.
1970         * If that property is not set, the {@code META-INF/jomc.xml} default is returned.</p>
1971         *
1972         * @return The default location to search for documents.
1973         *
1974         * @see #getClasspathModules(java.lang.String)
1975         */
1976        public String getDefaultDocumentLocation()
1977        {
1978            return System.getProperty( "org.jomc.model.DefaultModelManager.defaultDocumentLocation",
1979                                       DEFAULT_DOCUMENT_LOCATION );
1980    
1981        }
1982    
1983        /**
1984         * Gets modules by searching the class loader of the instance for resources.
1985         * <p><b>Note:</b><br/>
1986         * This method does not validate the modules.</p>
1987         *
1988         * @param location The location to search at.
1989         *
1990         * @return All resources from the class loader of the instance matching {@code location}.
1991         *
1992         * @throws NullPointerException if {@code location} is {@code null}.
1993         * @throws IOException if reading resources fails.
1994         * @throws SAXException if parsing schema resources fails.
1995         * @throws JAXBException if unmarshalling schema resources fails.
1996         *
1997         * @see #getDefaultDocumentLocation()
1998         */
1999        public Modules getClasspathModules( final String location ) throws IOException, SAXException, JAXBException
2000        {
2001            if ( location == null )
2002            {
2003                throw new NullPointerException( "location" );
2004            }
2005    
2006            this.log( Level.FINE, this.getMessage( "documentLocation", new Object[]
2007                {
2008                    location
2009                } ), null );
2010    
2011            final long t0 = System.currentTimeMillis();
2012            final Text text = new Text();
2013            text.setLanguage( "en" );
2014            text.setValue( this.getMessage( "classpathModulesInfo", new Object[]
2015                {
2016                    location
2017                } ) );
2018    
2019            final Modules mods = new Modules();
2020            mods.setDocumentation( new Texts() );
2021            mods.getDocumentation().setDefaultLanguage( "en" );
2022            mods.getDocumentation().getText().add( text );
2023    
2024            final Unmarshaller u = this.getUnmarshaller( false );
2025            final Enumeration<URL> resources = this.getClassLoader().getResources( location );
2026    
2027            Integer count = 0;
2028            while ( resources.hasMoreElements() )
2029            {
2030                count++;
2031                final URL url = resources.nextElement();
2032    
2033                this.log( Level.FINE, this.getMessage( "processing", new Object[]
2034                    {
2035                        url.toExternalForm()
2036                    } ), null );
2037    
2038                Object content = u.unmarshal( url );
2039                if ( content instanceof JAXBElement )
2040                {
2041                    content = ( (JAXBElement) content ).getValue();
2042                }
2043    
2044                if ( content instanceof Module )
2045                {
2046                    mods.getModule().add( (Module) content );
2047                }
2048                else
2049                {
2050                    this.log( Level.WARNING, this.getMessage( "ignoringDocument", new Object[]
2051                        {
2052                            content == null ? "<>" : content.toString(), url.toExternalForm()
2053                        } ), null );
2054    
2055                }
2056            }
2057    
2058            this.log( Level.FINE, this.getMessage( "classpathReport", new Object[]
2059                {
2060                    count, Long.valueOf( System.currentTimeMillis() - t0 )
2061                } ), null );
2062    
2063            return mods;
2064        }
2065    
2066        /**
2067         * Gets the classpath module name.
2068         * <p>The classpath module name is controlled by system property
2069         * {@code org.jomc.model.DefaultModelManager.classpathModuleName} holding the classpath module name.
2070         * If that property is not set, the {@code Java Classpath} default is returned.</p>
2071         *
2072         * @return The name of the classpath module.
2073         *
2074         * @see #getClasspathModule(org.jomc.model.Modules)
2075         */
2076        public String getClasspathModuleName()
2077        {
2078            return System.getProperty( "org.jomc.model.DefaultModelManager.classpathModuleName",
2079                                       DEFAULT_CLASSPATH_MODULE_NAME );
2080    
2081        }
2082    
2083        /**
2084         * Gets a module holding model objects resolved by inspecting the class loader of the instance.
2085         * <p>This method searches the given modules for unresolved references and tries to resolve each unresolved
2086         * reference by inspecting the class loader of the instance.</p>
2087         *
2088         * @param modules The modules to resolve by inspecting the class loader of the instance.
2089         *
2090         * @return A module holding model objects resolved by inspecting the class loader of the instance or {@code null} if
2091         * nothing could be resolved.
2092         *
2093         * @see #getClasspathModuleName()
2094         */
2095        public Module getClasspathModule( final Modules modules )
2096        {
2097            final Module module = new Module();
2098            module.setVersion( System.getProperty( "java.specification.version" ) );
2099            module.setName( this.getClasspathModuleName() );
2100    
2101            this.resolveClasspath( modules, module );
2102    
2103            final boolean resolved = ( module.getSpecifications() != null &&
2104                                       !module.getSpecifications().getSpecification().isEmpty() ) ||
2105                                     ( module.getImplementations() != null &&
2106                                       !module.getImplementations().getImplementation().isEmpty() );
2107    
2108            return resolved ? module : null;
2109        }
2110    
2111        /**
2112         * Gets the default location to search for style sheets.
2113         * <p>The default style sheet location is controlled by system property
2114         * {@code org.jomc.model.DefaultModelManager.defaultStylesheetLocation} holding the location to search at by
2115         * default. If that property is not set, the {@code META-INF/jomc.xslt} default is returned.</p>
2116         *
2117         * @return The default location to search for style sheets.
2118         *
2119         * @see #getClasspathTransformers(java.lang.String)
2120         */
2121        public String getDefaultStylesheetLocation()
2122        {
2123            return System.getProperty( "org.jomc.model.DefaultModelManager.defaultStylesheetLocation",
2124                                       DEFAULT_STYLESHEET_LOCATION );
2125    
2126        }
2127    
2128        /**
2129         * Gets transformers by searching the class loader of the instance for resources.
2130         *
2131         * @param location The location to search at.
2132         *
2133         * @return All resources from the class loader of the instance matching {@code location}.
2134         *
2135         * @throws NullPointerException if {@code location} is {@code null}.
2136         * @throws IOException if reading resources fails.
2137         * @throws TransformerConfigurationException if getting the transformers fails.
2138         *
2139         * @see #getDefaultStylesheetLocation()
2140         */
2141        public List<Transformer> getClasspathTransformers( final String location )
2142            throws IOException, TransformerConfigurationException
2143        {
2144            if ( location == null )
2145            {
2146                throw new NullPointerException( "location" );
2147            }
2148    
2149            this.log( Level.FINE, this.getMessage( "stylesheetLocation", new Object[]
2150                {
2151                    location
2152                } ), null );
2153    
2154            final long t0 = System.currentTimeMillis();
2155            final List<Transformer> transformers = new LinkedList<Transformer>();
2156            final TransformerFactory transformerFactory = TransformerFactory.newInstance();
2157            final Enumeration<URL> resources = this.getClassLoader().getResources( location );
2158            final ErrorListener errorListener = new ErrorListener()
2159            {
2160    
2161                public void warning( final TransformerException exception ) throws TransformerException
2162                {
2163                    log( Level.WARNING, exception.getMessage(), exception );
2164                }
2165    
2166                public void error( final TransformerException exception ) throws TransformerException
2167                {
2168                    log( Level.SEVERE, exception.getMessage(), exception );
2169                    throw exception;
2170                }
2171    
2172                public void fatalError( final TransformerException exception ) throws TransformerException
2173                {
2174                    log( Level.SEVERE, exception.getMessage(), exception );
2175                    throw exception;
2176                }
2177    
2178            };
2179    
2180            final URIResolver uriResolver = new URIResolver()
2181            {
2182    
2183                public Source resolve( final String href, final String base ) throws TransformerException
2184                {
2185                    try
2186                    {
2187                        Source source = null;
2188                        final InputSource inputSource = getEntityResolver().resolveEntity( null, href );
2189    
2190                        if ( inputSource != null )
2191                        {
2192                            source = new SAXSource( inputSource );
2193                        }
2194    
2195                        return source;
2196                    }
2197                    catch ( final SAXException e )
2198                    {
2199                        log( Level.SEVERE, e.getMessage(), e );
2200                        throw new TransformerException( e );
2201                    }
2202                    catch ( final IOException e )
2203                    {
2204                        log( Level.SEVERE, e.getMessage(), e );
2205                        throw new TransformerException( e );
2206                    }
2207                }
2208    
2209            };
2210    
2211            transformerFactory.setErrorListener( errorListener );
2212            transformerFactory.setURIResolver( uriResolver );
2213    
2214            Integer count = 0;
2215            while ( resources.hasMoreElements() )
2216            {
2217                count++;
2218                final URL url = resources.nextElement();
2219    
2220                this.log( Level.FINE, this.getMessage( "processing", new Object[]
2221                    {
2222                        url.toExternalForm()
2223                    } ), null );
2224    
2225                final InputStream in = url.openStream();
2226                final Transformer transformer = transformerFactory.newTransformer( new StreamSource( in ) );
2227                in.close();
2228    
2229                transformer.setErrorListener( errorListener );
2230                transformer.setURIResolver( uriResolver );
2231                transformers.add( transformer );
2232            }
2233    
2234            this.log( Level.FINE, this.getMessage( "classpathReport", new Object[]
2235                {
2236                    count, Long.valueOf( System.currentTimeMillis() - t0 )
2237                } ), null );
2238    
2239            return transformers;
2240        }
2241    
2242        /**
2243         * Gets the class loader of the instance.
2244         *
2245         * @return The class loader of the instance.
2246         *
2247         * @see #setClassLoader(java.lang.ClassLoader)
2248         */
2249        public ClassLoader getClassLoader()
2250        {
2251            if ( this.classLoader == null )
2252            {
2253                this.classLoader = this.getClass().getClassLoader();
2254                if ( this.classLoader == null )
2255                {
2256                    this.classLoader = ClassLoader.getSystemClassLoader();
2257                }
2258    
2259            }
2260    
2261            return this.classLoader;
2262        }
2263    
2264        /**
2265         * Sets the class loader of the instance.
2266         *
2267         * @param value The new class loader of the instance.
2268         *
2269         * @see #getClassLoader()
2270         */
2271        public void setClassLoader( final ClassLoader value )
2272        {
2273            this.classLoader = value;
2274            this.bootstrapSchema = null;
2275            this.schema = null;
2276            this.schemas = null;
2277            this.schemaResources = null;
2278            this.entityResolver = null;
2279            this.resourceResolver = null;
2280            this.context = null;
2281        }
2282    
2283        /**
2284         * Notifies registered listeners.
2285         *
2286         * @param level The level of the event.
2287         * @param message The message of the event or {@code null}.
2288         * @param throwable The throwable of the event {@code null}.
2289         *
2290         * @see #getListeners()
2291         */
2292        protected void log( final Level level, final String message, final Throwable throwable )
2293        {
2294            for ( Listener l : this.getListeners() )
2295            {
2296                l.onLog( level, message, throwable );
2297            }
2298        }
2299    
2300        /**
2301         * Resolves references by inspecting the class loader of the instance.
2302         *
2303         * @param modules The modules to resolve.
2304         * @param cpModule The module for resolved references.
2305         *
2306         * @throws NullPointerException if {@code cpModule} is {@code null}.
2307         */
2308        private void resolveClasspath( final Modules modules, final Module cpModule )
2309        {
2310            for ( Module m : modules.getModule() )
2311            {
2312                if ( m.getSpecifications() != null )
2313                {
2314                    this.resolveClasspath( modules, m.getSpecifications(), cpModule );
2315                }
2316    
2317                if ( m.getImplementations() != null )
2318                {
2319                    this.resolveClasspath( modules, m.getImplementations(), cpModule );
2320                }
2321    
2322            }
2323        }
2324    
2325        private void resolveClasspath( final Modules modules, final SpecificationReference ref, final Module cpModule )
2326        {
2327            if ( modules.getSpecification( ref.getIdentifier() ) == null )
2328            {
2329                this.resolveClasspath( ref.getIdentifier(), cpModule );
2330            }
2331        }
2332    
2333        private void resolveClasspath( final Modules modules, final Specifications references, final Module cpModule )
2334        {
2335            for ( SpecificationReference ref : references.getReference() )
2336            {
2337                this.resolveClasspath( modules, ref, cpModule );
2338            }
2339    
2340        }
2341    
2342        private void resolveClasspath( final Modules modules, final Implementations implementations, final Module cpModule )
2343        {
2344            for ( Implementation implementation : implementations.getImplementation() )
2345            {
2346                if ( implementation.getSpecifications() != null )
2347                {
2348                    this.resolveClasspath( modules, implementation.getSpecifications(), cpModule );
2349                }
2350    
2351                if ( implementation.getDependencies() != null )
2352                {
2353                    this.resolveClasspath( modules, implementation.getDependencies(), cpModule );
2354                }
2355            }
2356        }
2357    
2358        private void resolveClasspath( final Modules modules, final Dependencies dependencies, final Module cpModule )
2359        {
2360            for ( Dependency dependency : dependencies.getDependency() )
2361            {
2362                this.resolveClasspath( modules, dependency, cpModule );
2363            }
2364        }
2365    
2366        private void resolveClasspath( final String identifier, final Module cpModule )
2367        {
2368            Specification specification =
2369                cpModule.getSpecifications() == null ? null
2370                : cpModule.getSpecifications().getSpecification( identifier );
2371    
2372            if ( specification == null )
2373            {
2374                try
2375                {
2376                    final Class classpathSpec = Class.forName( identifier, true, this.getClassLoader() );
2377                    if ( Modifier.isPublic( classpathSpec.getModifiers() ) )
2378                    {
2379                        String vendor = null;
2380                        String version = null;
2381    
2382                        if ( classpathSpec.getPackage() != null )
2383                        {
2384                            vendor = classpathSpec.getPackage().getSpecificationVendor();
2385                            version = classpathSpec.getPackage().getSpecificationVersion();
2386                        }
2387    
2388                        specification = new Specification();
2389                        specification.setIdentifier( identifier );
2390                        specification.setClazz( classpathSpec.getName() );
2391                        specification.setMultiplicity( Multiplicity.MANY );
2392                        specification.setVendor( vendor );
2393                        specification.setVersion( version );
2394    
2395                        this.log( Level.FINE, this.getMessage( "classpathSpecification", new Object[]
2396                            {
2397                                specification.getIdentifier(),
2398                                specification.getMultiplicity().value()
2399                            } ), null );
2400    
2401    
2402                        if ( cpModule.getSpecifications() == null )
2403                        {
2404                            cpModule.setSpecifications( new Specifications() );
2405                        }
2406    
2407                        cpModule.getSpecifications().getSpecification().add( specification );
2408    
2409                        this.resolveClasspath( specification, cpModule );
2410                    }
2411    
2412                }
2413                catch ( final ClassNotFoundException e )
2414                {
2415                    this.log( Level.FINE, this.getMessage( "noSuchClass", new Object[]
2416                        {
2417                            e.getMessage()
2418                        } ), null );
2419    
2420                }
2421            }
2422        }
2423    
2424        private void resolveClasspath( final Specification specification, final Module cpModule )
2425        {
2426            if ( specification == null )
2427            {
2428                throw new NullPointerException( "specification" );
2429            }
2430    
2431            Implementation implementation =
2432                cpModule.getImplementations() == null ? null
2433                : cpModule.getImplementations().getImplementation( specification.getIdentifier() );
2434    
2435            if ( implementation == null )
2436            {
2437                String name = null;
2438    
2439                try
2440                {
2441                    final Class classpathImpl = Class.forName( specification.getClazz(), true, this.getClassLoader() );
2442                    boolean classpathImplementation = false;
2443    
2444                    if ( Modifier.isPublic( classpathImpl.getModifiers() ) )
2445                    {
2446                        if ( !Modifier.isAbstract( classpathImpl.getModifiers() ) )
2447                        {
2448                            try
2449                            {
2450                                classpathImpl.getConstructor( NO_CLASSES );
2451                                name = "init";
2452                                classpathImplementation = true;
2453                            }
2454                            catch ( final NoSuchMethodException e )
2455                            {
2456                                this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
2457                                    {
2458                                        e.getMessage()
2459                                    } ), null );
2460    
2461                            }
2462                        }
2463    
2464                        if ( !classpathImplementation )
2465                        {
2466                            final char[] c = classpathImpl.getName().substring(
2467                                classpathImpl.getPackage().getName().length() + 1 ).toCharArray();
2468    
2469                            name = String.valueOf( c );
2470                            c[0] = Character.toUpperCase( c[0] );
2471    
2472                            if ( this.checkFactoryMethod( classpathImpl, classpathImpl, "getDefault" ) )
2473                            {
2474                                name = "default";
2475                                classpathImplementation = true;
2476                            }
2477                            else if ( this.checkFactoryMethod( classpathImpl, classpathImpl, "getInstance" ) )
2478                            {
2479                                name = "instance";
2480                                classpathImplementation = true;
2481                            }
2482                            else if ( this.checkFactoryMethod( classpathImpl, classpathImpl, "get" + String.valueOf( c ) ) )
2483                            {
2484                                classpathImplementation = true;
2485                            }
2486    
2487                        }
2488    
2489                        if ( classpathImplementation )
2490                        {
2491                            String vendor = null;
2492                            String version = null;
2493                            if ( classpathImpl.getPackage() != null )
2494                            {
2495                                vendor = classpathImpl.getPackage().getImplementationVendor();
2496                                version = classpathImpl.getPackage().getImplementationVersion();
2497                            }
2498    
2499                            implementation = new Implementation();
2500                            implementation.setVendor( vendor );
2501                            implementation.setFinal( true );
2502                            implementation.setName( name );
2503                            implementation.setIdentifier( specification.getIdentifier() );
2504                            implementation.setClazz( classpathImpl.getName() );
2505                            implementation.setVersion( version );
2506    
2507                            final Specifications implemented = new Specifications();
2508                            final SpecificationReference ref = new SpecificationReference();
2509                            ref.setIdentifier( specification.getIdentifier() );
2510                            ref.setVersion( specification.getVersion() );
2511                            implemented.getReference().add( ref );
2512                            implementation.setSpecifications( implemented );
2513    
2514                            this.log( Level.FINE, this.getMessage( "classpathImplementation", new Object[]
2515                                {
2516                                    implementation.getIdentifier(),
2517                                    specification.getIdentifier(),
2518                                    implementation.getName()
2519                                } ), null );
2520    
2521                            if ( cpModule.getImplementations() == null )
2522                            {
2523                                cpModule.setImplementations( new Implementations() );
2524                            }
2525    
2526                            cpModule.getImplementations().getImplementation().add( implementation );
2527                        }
2528                        else
2529                        {
2530                            this.log( Level.FINE, this.getMessage( "noClasspathImplementation", new Object[]
2531                                {
2532                                    specification.getIdentifier()
2533                                } ), null );
2534    
2535                        }
2536                    }
2537                }
2538                catch ( final ClassNotFoundException e )
2539                {
2540                    this.log( Level.FINE, this.getMessage( "noSuchClass", new Object[]
2541                        {
2542                            e.getMessage()
2543                        } ), null );
2544    
2545                }
2546            }
2547        }
2548    
2549        private boolean checkFactoryMethod( final Class clazz, final Class type, final String methodName )
2550        {
2551            boolean factoryMethod = false;
2552    
2553            try
2554            {
2555                final Method m = clazz.getMethod( methodName, NO_CLASSES );
2556                factoryMethod = Modifier.isStatic( m.getModifiers() ) && type.isAssignableFrom( m.getReturnType() );
2557            }
2558            catch ( final NoSuchMethodException e )
2559            {
2560                this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
2561                    {
2562                        e.getMessage()
2563                    } ), null );
2564    
2565                factoryMethod = false;
2566            }
2567    
2568            return factoryMethod;
2569        }
2570    
2571        private Method getFactoryMethod( final Class clazz, final String methodName )
2572        {
2573            Method m = null;
2574    
2575            try
2576            {
2577                m = clazz.getMethod( methodName, NO_CLASSES );
2578            }
2579            catch ( final NoSuchMethodException e )
2580            {
2581                this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
2582                    {
2583                        e.getMessage()
2584                    } ), null );
2585    
2586                m = null;
2587            }
2588    
2589            return m;
2590        }
2591    
2592        /**
2593         * Searches all available {@code META-INF/MANIFEST.MF} resources and gets a set containing URLs of entries whose
2594         * name end with a known schema extension.
2595         *
2596         * @return URLs of any matching entries.
2597         *
2598         * @throws IOException if reading or parsing fails.
2599         */
2600        private Set<URL> getSchemaResources() throws IOException
2601        {
2602            if ( this.schemaResources == null )
2603            {
2604                this.schemaResources = new HashSet<URL>();
2605    
2606                for ( final Enumeration<URL> e = this.getClassLoader().getResources( "META-INF/MANIFEST.MF" );
2607                      e.hasMoreElements(); )
2608                {
2609                    final URL manifestUrl = e.nextElement();
2610                    final String externalForm = manifestUrl.toExternalForm();
2611                    final String baseUrl = externalForm.substring( 0, externalForm.indexOf( "META-INF" ) );
2612                    final InputStream manifestStream = manifestUrl.openStream();
2613                    final Manifest mf = new Manifest( manifestStream );
2614                    manifestStream.close();
2615    
2616                    for ( Map.Entry<String, Attributes> entry : mf.getEntries().entrySet() )
2617                    {
2618                        for ( int i = SCHEMA_EXTENSIONS.length - 1; i >= 0; i-- )
2619                        {
2620                            if ( entry.getKey().toLowerCase().endsWith( '.' + SCHEMA_EXTENSIONS[i].toLowerCase() ) )
2621                            {
2622                                final URL schemaUrl = new URL( baseUrl + entry.getKey() );
2623                                this.schemaResources.add( schemaUrl );
2624                                this.log( Level.FINE, this.getMessage( "processing", new Object[]
2625                                    {
2626                                        schemaUrl.toExternalForm()
2627                                    } ), null );
2628    
2629                            }
2630                        }
2631                    }
2632                }
2633            }
2634    
2635            return this.schemaResources;
2636        }
2637    
2638        /**
2639         * Gets the implementation of an object.
2640         *
2641         * @param modules The modules to search for the implementation of {@code object}.
2642         * @param object The object to get the implementation for.
2643         *
2644         * @return The implementation for {@code object} or {@code null}, if nothing is known about {@code object}.
2645         */
2646        private Implementation getImplementation( final Modules modules, final Object object )
2647        {
2648            return this.collectImplementation( modules, object.getClass() );
2649        }
2650    
2651        private Implementation collectImplementation( final Modules modules, final Class clazz )
2652        {
2653            Implementation i = modules.getImplementation( clazz );
2654            if ( i == null && clazz.getSuperclass() != null )
2655            {
2656                i = this.collectImplementation( modules, clazz.getSuperclass() );
2657            }
2658    
2659            return i;
2660        }
2661    
2662        private void collectFinalSuperDependencies(
2663            final Modules modules, final Implementation implementation, final String dependencyName,
2664            final Implementations implementations, final Implementations seen, final boolean includeImplementation )
2665        {
2666            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
2667            {
2668                seen.getImplementation().add( implementation );
2669    
2670                if ( includeImplementation )
2671                {
2672                    final Dependencies dependencies = modules.getDependencies( implementation.getIdentifier() );
2673    
2674                    if ( dependencies != null )
2675                    {
2676                        for ( Dependency d : dependencies.getDependency() )
2677                        {
2678                            if ( dependencyName.equals( d.getName() ) && d.isFinal() &&
2679                                 implementations.getImplementation( implementation.getIdentifier() ) == null )
2680                            {
2681                                implementations.getImplementation().add( implementation );
2682                            }
2683                        }
2684                    }
2685                }
2686    
2687                if ( implementation.getImplementations() != null )
2688                {
2689                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
2690                    {
2691                        this.collectFinalSuperDependencies( modules, modules.getImplementation( r.getIdentifier() ),
2692                                                            dependencyName, implementations, seen, true );
2693    
2694                    }
2695                }
2696            }
2697        }
2698    
2699        private void collectFinalSuperMessages(
2700            final Modules modules, final Implementation implementation, final String messageName,
2701            final Implementations implementations, final Implementations seen, final boolean includeImplementation )
2702        {
2703            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
2704            {
2705                seen.getImplementation().add( implementation );
2706    
2707                if ( includeImplementation )
2708                {
2709                    final Messages messages = modules.getMessages( implementation.getIdentifier() );
2710    
2711                    if ( messages != null )
2712                    {
2713                        for ( Message m : messages.getMessage() )
2714                        {
2715                            if ( messageName.equals( m.getName() ) && m.isFinal() &&
2716                                 implementations.getImplementation( implementation.getIdentifier() ) == null )
2717                            {
2718                                implementations.getImplementation().add( implementation );
2719                            }
2720                        }
2721                    }
2722                }
2723    
2724                if ( implementation.getImplementations() != null )
2725                {
2726                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
2727                    {
2728                        this.collectFinalSuperMessages( modules, modules.getImplementation( r.getIdentifier() ),
2729                                                        messageName, implementations, seen, true );
2730    
2731                    }
2732                }
2733            }
2734        }
2735    
2736        private void collectFinalSuperProperties(
2737            final Modules modules, final Implementation implementation, final String propertyName,
2738            final Implementations implementations, final Implementations seen, final boolean includeImplementation )
2739        {
2740            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
2741            {
2742                seen.getImplementation().add( implementation );
2743    
2744                if ( includeImplementation )
2745                {
2746                    final Properties properties = modules.getProperties( implementation.getIdentifier() );
2747    
2748                    if ( properties != null )
2749                    {
2750                        for ( Property p : properties.getProperty() )
2751                        {
2752                            if ( propertyName.equals( p.getName() ) && p.isFinal() &&
2753                                 implementations.getImplementation( implementation.getIdentifier() ) == null )
2754                            {
2755                                implementations.getImplementation().add( implementation );
2756                            }
2757                        }
2758                    }
2759                }
2760    
2761                if ( implementation.getImplementations() != null )
2762                {
2763                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
2764                    {
2765                        this.collectFinalSuperProperties( modules, modules.getImplementation( r.getIdentifier() ),
2766                                                          propertyName, implementations, seen, true );
2767    
2768                    }
2769                }
2770            }
2771        }
2772    
2773        private void collectFinalSuperSpecifications(
2774            final Modules modules, final Implementation implementation, final String specificationIdentifier,
2775            final Implementations implementations, final Implementations seen, final boolean includeImplementation )
2776        {
2777            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
2778            {
2779                seen.getImplementation().add( implementation );
2780    
2781                if ( includeImplementation )
2782                {
2783                    final Specifications specifications = modules.getSpecifications( implementation.getIdentifier() );
2784    
2785                    if ( specifications != null )
2786                    {
2787                        for ( SpecificationReference r : specifications.getReference() )
2788                        {
2789                            if ( specificationIdentifier.equals( r.getIdentifier() ) && r.isFinal() &&
2790                                 implementations.getImplementation( implementation.getIdentifier() ) == null )
2791                            {
2792                                implementations.getImplementation().add( implementation );
2793                            }
2794                        }
2795                    }
2796                }
2797    
2798                if ( implementation.getImplementations() != null )
2799                {
2800                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
2801                    {
2802                        this.collectFinalSuperSpecifications( modules, modules.getImplementation( r.getIdentifier() ),
2803                                                              specificationIdentifier, implementations, seen, true );
2804    
2805                    }
2806                }
2807            }
2808        }
2809    
2810        private void collectFinalSuperImplementations( final Modules modules, final Implementation implementation,
2811                                                       final Implementations implementations, final Implementations seen,
2812                                                       final boolean includeImplementation )
2813        {
2814            if ( implementation != null && seen.getImplementation( implementation.getIdentifier() ) == null )
2815            {
2816                seen.getImplementation().add( implementation );
2817    
2818                if ( includeImplementation && implementation.isFinal() &&
2819                     implementations.getImplementation( implementation.getIdentifier() ) == null )
2820                {
2821                    implementations.getImplementation().add( implementation );
2822                }
2823    
2824                if ( implementation.getImplementations() != null )
2825                {
2826                    for ( ImplementationReference r : implementation.getImplementations().getReference() )
2827                    {
2828                        this.collectFinalSuperImplementations( modules, modules.getImplementation( r.getIdentifier() ),
2829                                                               implementations, seen, true );
2830    
2831                    }
2832                }
2833            }
2834        }
2835    
2836        private Implementation findInheritanceCycle( final Modules modules, final Implementation current,
2837                                                     final Implementation report, final Implementations implementations )
2838        {
2839            if ( current != null )
2840            {
2841                if ( implementations.getImplementation( current.getIdentifier() ) != null )
2842                {
2843                    return report;
2844                }
2845    
2846                implementations.getImplementation().add( current );
2847    
2848                if ( current.getImplementations() != null )
2849                {
2850                    for ( ImplementationReference r : current.getImplementations().getReference() )
2851                    {
2852                        return this.findInheritanceCycle( modules, modules.getImplementation( r.getIdentifier() ),
2853                                                          current, implementations );
2854    
2855                    }
2856                }
2857            }
2858    
2859            return null;
2860        }
2861    
2862        private String getMessage( final String key, final Object args )
2863        {
2864            return new MessageFormat(
2865                ResourceBundle.getBundle( DefaultModelManager.class.getName().replace( '.', '/' ), Locale.getDefault() ).
2866                getString( key ) ).format( args );
2867    
2868        }
2869    
2870        private void assertImplementationMessagesUniqueness(
2871            final Implementation implementation, final List<ModelException.Detail> details )
2872        {
2873            if ( implementation.getMessages() != null )
2874            {
2875                for ( Message m : implementation.getMessages().getMessage() )
2876                {
2877                    if ( implementation.getMessages().getReference( m.getName() ) != null )
2878                    {
2879                        final ModelException.Detail detail = new ModelException.Detail(
2880                            "IMPLEMENTATION_MESSAGES_UNIQUENESS_CONSTRAINT", Level.SEVERE,
2881                            this.getMessage( "messagesUniquenessConstraint", new Object[]
2882                            {
2883                                implementation.getIdentifier(), m.getName()
2884                            } ) );
2885    
2886                        detail.setElement( this.getObjectFactory().createImplementation( implementation ) );
2887                        details.add( detail );
2888                    }
2889                }
2890            }
2891        }
2892    
2893        private void assertImplementationPropertiesUniqueness(
2894            final Implementation implementation, final List<ModelException.Detail> details )
2895        {
2896            if ( implementation.getProperties() != null )
2897            {
2898                for ( Property p : implementation.getProperties().getProperty() )
2899                {
2900                    if ( implementation.getProperties().getReference( p.getName() ) != null )
2901                    {
2902                        final ModelException.Detail detail = new ModelException.Detail(
2903                            "IMPLEMENTATION_PROPERTIES_UNIQUENESS_CONSTRAINT", Level.SEVERE,
2904                            this.getMessage( "propertiesUniquenessConstraint", new Object[]
2905                            {
2906                                implementation.getIdentifier(), p.getName()
2907                            } ) );
2908    
2909                        detail.setElement( this.getObjectFactory().createImplementation( implementation ) );
2910                        details.add( detail );
2911                    }
2912                }
2913            }
2914        }
2915    
2916        private ModelException.Detail newIncompatibleImplementationDetail(
2917            final JAXBElement<? extends ModelObject> element, final String implementation,
2918            final String implementationModule, final String specification, final String specificationModule,
2919            final String implementedVersion, final String specifiedVersion )
2920        {
2921            final ModelException.Detail detail = new ModelException.Detail(
2922                "IMPLEMENTATION_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
2923                this.getMessage( "incompatibleImplementation", new Object[]
2924                {
2925                    implementation, implementationModule, specification, specificationModule,
2926                    implementedVersion, specifiedVersion
2927                } ) );
2928    
2929            detail.setElement( element );
2930            return detail;
2931        }
2932    
2933        private ModelException.Detail newIncompatibleDependencyDetail(
2934            final JAXBElement<? extends ModelObject> element, final String implementation,
2935            final String implementationModule, final String specification, final String specificationModule,
2936            final String requiredVersion, final String availableVersion )
2937        {
2938            final ModelException.Detail detail = new ModelException.Detail(
2939                "DEPENDENCY_COMPATIBILITY_CONSTRAINT", Level.SEVERE, this.getMessage( "incompatibleDependency", new Object[]
2940                {
2941                    implementation, implementationModule, specification, specificationModule,
2942                    requiredVersion, availableVersion
2943                } ) );
2944    
2945            detail.setElement( element );
2946            return detail;
2947        }
2948    
2949        private ModelException.Detail newImplementationNameConstraintDetail(
2950            final JAXBElement<? extends ModelObject> element, final Specification specification,
2951            final Implementation implementation )
2952        {
2953            final ModelException.Detail detail = new ModelException.Detail(
2954                "IMPLEMENTATION_NAME_CONSTRAINT", Level.SEVERE,
2955                this.getMessage( "implementationNameConstraint", new Object[]
2956                {
2957                    implementation.getIdentifier(), specification.getIdentifier(), implementation.getName()
2958                } ) );
2959    
2960            detail.setElement( element );
2961            return detail;
2962        }
2963    
2964        private ModelException.Detail newMandatoryDependencyConstraintDetail(
2965            final JAXBElement<? extends ModelObject> element, final String implementation, final String dependencyName )
2966        {
2967            final ModelException.Detail detail = new ModelException.Detail(
2968                "MANDATORY_DEPENDENCY_CONSTRAINT", Level.SEVERE,
2969                this.getMessage( "mandatoryDependencyConstraint", new Object[]
2970                {
2971                    implementation, dependencyName
2972                } ) );
2973    
2974            detail.setElement( element );
2975            return detail;
2976        }
2977    
2978        private ModelException.Detail newMultiplicityConstraintDetail(
2979            final JAXBElement<? extends ModelObject> element, final Specification specification,
2980            final Implementation implementation )
2981        {
2982            final ModelException.Detail detail = new ModelException.Detail(
2983                "MULTIPLICITY_CONSTRAINT", Level.SEVERE, this.getMessage( "multiplicityConstraint", new Object[]
2984                {
2985                    implementation.getIdentifier(), specification.getIdentifier(), specification.getMultiplicity().value()
2986                } ) );
2987    
2988            detail.setElement( element );
2989            return detail;
2990        }
2991    
2992        private ModelException.Detail newImplementationInheritanceConstraintDetail(
2993            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
2994            final Implementation finalSuperImplementation )
2995        {
2996            final ModelException.Detail detail = new ModelException.Detail(
2997                "IMPLEMENTATION_INHERITANCE_CONSTRAINT", Level.SEVERE,
2998                this.getMessage( "implementationInheritanceConstraint", new Object[]
2999                {
3000                    implementation.getIdentifier(), finalSuperImplementation.getIdentifier()
3001                } ) );
3002    
3003            detail.setElement( element );
3004            return detail;
3005        }
3006    
3007        private ModelException.Detail newSpecificationInheritanceConstraintDetail(
3008            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3009            final SpecificationReference specification, final Implementation finalSuperSpecification )
3010        {
3011            final ModelException.Detail detail = new ModelException.Detail(
3012                "SPECIFICATION_INHERITANCE_CONSTRANT", Level.SEVERE,
3013                this.getMessage( "specificationInheritanceConstraint", new Object[]
3014                {
3015                    implementation.getIdentifier(), specification.getIdentifier(), finalSuperSpecification.getIdentifier()
3016                } ) );
3017    
3018            detail.setElement( element );
3019            return detail;
3020        }
3021    
3022        private ModelException.Detail newDependencyInheritanceConstraintDetail(
3023            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3024            final Dependency dependency, final Implementation finalSuperDependency )
3025        {
3026            final ModelException.Detail detail = new ModelException.Detail(
3027                "DEPENDENCY_INHERITANCE_CONSTRAINT", Level.SEVERE,
3028                this.getMessage( "dependencyInheritanceConstraint", new Object[]
3029                {
3030                    implementation.getIdentifier(), dependency.getName(), finalSuperDependency.getIdentifier()
3031                } ) );
3032    
3033            detail.setElement( element );
3034            return detail;
3035        }
3036    
3037        private ModelException.Detail newPropertyInheritanceConstraintDetail(
3038            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3039            final Property property, final Implementation finalSuperProperty )
3040        {
3041            final ModelException.Detail detail = new ModelException.Detail(
3042                "PROPERTY_INHERITANCE_CONSTRAINT", Level.SEVERE,
3043                this.getMessage( "propertyInheritanceConstraint", new Object[]
3044                {
3045                    implementation.getIdentifier(), property.getName(), finalSuperProperty.getIdentifier()
3046                } ) );
3047    
3048            detail.setElement( element );
3049            return detail;
3050        }
3051    
3052        private ModelException.Detail newPropertyInheritanceConstraintDetail(
3053            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3054            final PropertyReference reference, final Implementation finalSuperProperty )
3055        {
3056            final ModelException.Detail detail = new ModelException.Detail(
3057                "PROPERTY_INHERITANCE_CONSTRAINT", Level.SEVERE,
3058                this.getMessage( "propertyInheritanceConstraint", new Object[]
3059                {
3060                    implementation.getIdentifier(), reference.getName(), finalSuperProperty.getIdentifier()
3061                } ) );
3062    
3063            detail.setElement( element );
3064            return detail;
3065        }
3066    
3067        private ModelException.Detail newMessageInheritanceConstraintDetail(
3068            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3069            final Message message, final Implementation finalSuperMessage )
3070        {
3071            final ModelException.Detail detail = new ModelException.Detail(
3072                "MESSAGE_INHERITANCE_CONSTRAINT", Level.SEVERE,
3073                this.getMessage( "messageInheritanceConstraint", new Object[]
3074                {
3075                    implementation.getIdentifier(), message.getName(), finalSuperMessage.getIdentifier()
3076                } ) );
3077    
3078            detail.setElement( element );
3079            return detail;
3080        }
3081    
3082        private ModelException.Detail newMessageInheritanceConstraintDetail(
3083            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3084            final MessageReference reference, final Implementation finalSuperMessage )
3085        {
3086            final ModelException.Detail detail = new ModelException.Detail(
3087                "MESSAGE_INHERITANCE_CONSTRAINT", Level.SEVERE,
3088                this.getMessage( "messageInheritanceConstraint", new Object[]
3089                {
3090                    implementation.getIdentifier(), reference.getName(), finalSuperMessage.getIdentifier()
3091                } ) );
3092    
3093            detail.setElement( element );
3094            return detail;
3095        }
3096    
3097        private ModelException.Detail newDependencyPropertyReferenceDeclarationConstraintDetail(
3098            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3099            final Dependency dependency, final PropertyReference reference )
3100        {
3101            final ModelException.Detail detail = new ModelException.Detail(
3102                "DEPENDENCY_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3103                this.getMessage( "dependencyPropertyReferenceDeclarationConstraint", new Object[]
3104                {
3105                    implementation.getIdentifier(), dependency.getName(), reference.getName()
3106                } ) );
3107    
3108            detail.setElement( element );
3109            return detail;
3110        }
3111    
3112        private ModelException.Detail newDependencyPropertiesOverrideConstraintDetail(
3113            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3114            final Dependency dependency, final Specification specification, final Property property )
3115        {
3116            final ModelException.Detail detail = new ModelException.Detail(
3117                "DEPENDENCY_PROPERTIES_OVERRIDE_CONSTRAINT", Level.SEVERE,
3118                this.getMessage( "dependencyPropertiesOverrideConstraint", new Object[]
3119                {
3120                    implementation.getIdentifier(), dependency.getName(), specification.getIdentifier(),
3121                    specification.getScope(), property.getName()
3122                } ) );
3123    
3124            detail.setElement( element );
3125            return detail;
3126        }
3127    
3128        private ModelException.Detail newImplementationSpecificationDeclarationConstraintDetail(
3129            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3130            final Specification specification )
3131        {
3132            final ModelException.Detail detail = new ModelException.Detail(
3133                "IMPLEMENTATION_SPECIFICATION_DECLARATION_CONSTRAINT", Level.SEVERE,
3134                this.getMessage( "implementationSpecificationDeclarationConstraint", new Object[]
3135                {
3136                    implementation.getIdentifier(), specification.getIdentifier()
3137                } ) );
3138    
3139            detail.setElement( element );
3140            return detail;
3141        }
3142    
3143        private ModelException.Detail newModuleMessageReferenceDeclarationConstraintDetail(
3144            final JAXBElement<? extends ModelObject> element, final Module module, final MessageReference reference )
3145        {
3146            final ModelException.Detail detail = new ModelException.Detail(
3147                "MODULE_MESSAGE_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3148                this.getMessage( "moduleMessageReferenceDeclarationConstraint", new Object[]
3149                {
3150                    module.getName(), reference.getName()
3151                } ) );
3152    
3153            detail.setElement( element );
3154            return detail;
3155        }
3156    
3157        private ModelException.Detail newModulePropertyReferenceDeclarationConstraintDetail(
3158            final JAXBElement<? extends ModelObject> element, final Module module, final PropertyReference reference )
3159        {
3160            final ModelException.Detail detail = new ModelException.Detail(
3161                "MODULE_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3162                this.getMessage( "modulePropertyReferenceDeclarationConstraint", new Object[]
3163                {
3164                    module.getName(), reference.getName()
3165                } ) );
3166    
3167            detail.setElement( element );
3168            return detail;
3169        }
3170    
3171        private ModelException.Detail newModuleImplementationReferenceDeclarationConstraintDetail(
3172            final JAXBElement<? extends ModelObject> element, final Module module, final ImplementationReference reference )
3173        {
3174            final ModelException.Detail detail = new ModelException.Detail(
3175                "MODULE_IMPLEMENTATION_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3176                this.getMessage( "moduleImplementationReferenceDeclarationConstraint", new Object[]
3177                {
3178                    module.getName(), reference.getIdentifier()
3179                } ) );
3180    
3181            detail.setElement( element );
3182            return detail;
3183        }
3184    
3185        private ModelException.Detail newImplementationImplementationDeclarationConstraintDetail(
3186            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3187            final Implementation declaration )
3188        {
3189            final ModelException.Detail detail = new ModelException.Detail(
3190                "IMPLEMENTATION_IMPLEMENTATION_DECLARATION_CONSTRAINT", Level.SEVERE,
3191                this.getMessage( "implementationImplementationDeclarationConstraint", new Object[]
3192                {
3193                    implementation.getIdentifier(), declaration.getIdentifier()
3194                } ) );
3195    
3196            detail.setElement( element );
3197            return detail;
3198        }
3199    
3200        private ModelException.Detail newModuleSpecificationReferenceDeclarationConstraintDetail(
3201            final JAXBElement<? extends ModelObject> element, final Module module, final SpecificationReference reference )
3202        {
3203            final ModelException.Detail detail = new ModelException.Detail(
3204                "MODULE_SPECIFICATION_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3205                this.getMessage( "moduleSpecificationReferenceDeclarationConstraint", new Object[]
3206                {
3207                    module.getName(), reference.getIdentifier()
3208                } ) );
3209    
3210            detail.setElement( element );
3211            return detail;
3212        }
3213    
3214        private ModelException.Detail newDependencyOverrideConstraintDetail(
3215            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3216            final Dependency dependency )
3217        {
3218            final ModelException.Detail detail = new ModelException.Detail(
3219                "DEPENDENCY_OVERRIDE_CONSTRAINT", Level.SEVERE,
3220                this.getMessage( "dependencyOverrideConstraint", new Object[]
3221                {
3222                    implementation.getIdentifier(), dependency.getName()
3223                } ) );
3224    
3225            detail.setElement( element );
3226            return detail;
3227        }
3228    
3229        private ModelException.Detail newMessageOverrideConstraintDetail(
3230            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3231            final Message message )
3232        {
3233            final ModelException.Detail detail = new ModelException.Detail(
3234                "MESSAGE_OVERRIDE_CONSTRAINT", Level.SEVERE, this.getMessage( "messageOverrideConstraint", new Object[]
3235                {
3236                    implementation.getIdentifier(), message.getName()
3237                } ) );
3238    
3239            detail.setElement( element );
3240            return detail;
3241        }
3242    
3243        private ModelException.Detail newMessageOverrideConstraintDetail(
3244            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3245            final MessageReference reference )
3246        {
3247            final ModelException.Detail detail = new ModelException.Detail(
3248                "MESSAGE_OVERRIDE_CONSTRAINT", Level.SEVERE, this.getMessage( "messageOverrideConstraint", new Object[]
3249                {
3250                    implementation.getIdentifier(), reference.getName()
3251                } ) );
3252    
3253            detail.setElement( element );
3254            return detail;
3255        }
3256    
3257        private ModelException.Detail newPropertyOverrideConstraintDetail(
3258            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3259            final Property property )
3260        {
3261            final ModelException.Detail detail = new ModelException.Detail(
3262                "PROPERTY_OVERRIDE_CONSTRAINT", Level.SEVERE, this.getMessage( "propertyOverrideConstraint", new Object[]
3263                {
3264                    implementation.getIdentifier(), property.getName()
3265                } ) );
3266    
3267            detail.setElement( element );
3268            return detail;
3269        }
3270    
3271        private ModelException.Detail newPropertyOverrideConstraintDetail(
3272            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3273            final PropertyReference reference )
3274        {
3275            final ModelException.Detail detail = new ModelException.Detail(
3276                "PROPERTY_OVERRIDE_CONSTRAINT", Level.SEVERE, this.getMessage( "propertyOverrideConstraint", new Object[]
3277                {
3278                    implementation.getIdentifier(), reference.getName()
3279                } ) );
3280    
3281            detail.setElement( element );
3282            return detail;
3283        }
3284    
3285        private ModelException.Detail newSpecificationOverrideConstraintDetail(
3286            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3287            final SpecificationReference reference )
3288        {
3289            final ModelException.Detail detail = new ModelException.Detail(
3290                "SPECIFICATION_OVERRIDE_CONSTRAINT", Level.SEVERE,
3291                this.getMessage( "specificationOverrideConstraint", new Object[]
3292                {
3293                    implementation.getIdentifier(), reference.getIdentifier()
3294                } ) );
3295    
3296            detail.setElement( element );
3297            return detail;
3298        }
3299    
3300        private ModelException.Detail newAbstractLocationConstraintDetail(
3301            final JAXBElement<? extends ModelObject> element, final Implementation implementation, final String location )
3302        {
3303            final ModelException.Detail detail = new ModelException.Detail(
3304                "ABSTRACT_IMPLEMENTATION_LOCATION_CONSTRAINT", Level.SEVERE,
3305                this.getMessage( "abstractLocationConstraint", new Object[]
3306                {
3307                    implementation.getIdentifier(), location
3308                } ) );
3309    
3310            detail.setElement( element );
3311            return detail;
3312        }
3313    
3314        private ModelException.Detail newFinalModuleMessageConstraintDetail(
3315            final JAXBElement<? extends ModelObject> element, final Module module, final Message message )
3316        {
3317            final ModelException.Detail detail = new ModelException.Detail(
3318                "FINAL_MODULE_MESSAGE_CONSTRAINT", Level.SEVERE,
3319                this.getMessage( "finalModuleMessageConstraint", new Object[]
3320                {
3321                    module.getName(), message.getName()
3322                } ) );
3323    
3324            detail.setElement( element );
3325            return detail;
3326        }
3327    
3328        private ModelException.Detail newOverrideModuleMessageConstraintDetail(
3329            final JAXBElement<? extends ModelObject> element, final Module module, final Message message )
3330        {
3331            final ModelException.Detail detail = new ModelException.Detail(
3332                "OVERRIDE_MODULE_MESSAGE_CONSTRAINT", Level.SEVERE,
3333                this.getMessage( "overrideModuleMessageConstraint", new Object[]
3334                {
3335                    module.getName(), message.getName()
3336                } ) );
3337    
3338            detail.setElement( element );
3339            return detail;
3340        }
3341    
3342        private ModelException.Detail newFinalModulePropertyConstraintDetail(
3343            final JAXBElement<? extends ModelObject> element, final Module module, final Property property )
3344        {
3345            final ModelException.Detail detail = new ModelException.Detail(
3346                "FINAL_MODULE_PROPERTY_CONSTRAINT", Level.SEVERE,
3347                this.getMessage( "finalModulePropertyConstraint", new Object[]
3348                {
3349                    module.getName(), property.getName()
3350                } ) );
3351    
3352            detail.setElement( element );
3353            return detail;
3354        }
3355    
3356        private ModelException.Detail newOverrideModulePropertyConstraintDetail(
3357            final JAXBElement<? extends ModelObject> element, final Module module, final Property property )
3358        {
3359            final ModelException.Detail detail = new ModelException.Detail(
3360                "OVERRIDE_MODULE_PROPERTY_CONSTRAINT", Level.SEVERE,
3361                this.getMessage( "overrideModulePropertyConstraint", new Object[]
3362                {
3363                    module.getName(), property.getName()
3364                } ) );
3365    
3366            detail.setElement( element );
3367            return detail;
3368        }
3369    
3370        private ModelException.Detail newSpecificationPropertyReferenceDeclarationConstraintDetail(
3371            final JAXBElement<? extends ModelObject> element, final Specification specification,
3372            final PropertyReference reference )
3373        {
3374            final ModelException.Detail detail = new ModelException.Detail(
3375                "SPECIFICATION_PROPERTY_REFERENCE_DECLARATION_CONSTRAINT", Level.SEVERE,
3376                this.getMessage( "specificationPropertyReferenceDeclarationConstraint", new Object[]
3377                {
3378                    specification.getIdentifier(), reference.getName()
3379                } ) );
3380    
3381            detail.setElement( element );
3382            return detail;
3383        }
3384    
3385        private ModelException.Detail newSpecificationMultipleInheritanceContraintDetail(
3386            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3387            final SpecificationReference reference )
3388        {
3389            final ModelException.Detail detail = new ModelException.Detail(
3390                "SPECIFICATION_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
3391                this.getMessage( "multipleInheritanceSpecificationConstraint", new Object[]
3392                {
3393                    implementation.getIdentifier(), reference.getIdentifier()
3394                } ) );
3395    
3396            detail.setElement( element );
3397            return detail;
3398        }
3399    
3400        private ModelException.Detail newDependencyMultipleInheritanceContraintDetail(
3401            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3402            final Dependency dependency )
3403        {
3404            final ModelException.Detail detail = new ModelException.Detail(
3405                "DEPENDENCY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
3406                this.getMessage( "multipleInheritanceDependencyConstraint", new Object[]
3407                {
3408                    implementation.getIdentifier(), dependency.getName()
3409                } ) );
3410    
3411            detail.setElement( element );
3412            return detail;
3413        }
3414    
3415        private ModelException.Detail newMessageMultipleInheritanceContraintDetail(
3416            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3417            final Message message )
3418        {
3419            final ModelException.Detail detail = new ModelException.Detail(
3420                "MESSAGE_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
3421                this.getMessage( "multipleInheritanceMessageConstraint", new Object[]
3422                {
3423                    implementation.getIdentifier(), message.getName()
3424                } ) );
3425    
3426            detail.setElement( element );
3427            return detail;
3428        }
3429    
3430        private ModelException.Detail newPropertyMultipleInheritanceContraintDetail(
3431            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3432            final Property property )
3433        {
3434            final ModelException.Detail detail = new ModelException.Detail(
3435                "PROPERTY_MULTIPLE_INHERITANCE_CONSTRAINT", Level.SEVERE,
3436                this.getMessage( "multipleInheritancePropertyConstraint", new Object[]
3437                {
3438                    implementation.getIdentifier(), property.getName()
3439                } ) );
3440    
3441            detail.setElement( element );
3442            return detail;
3443        }
3444    
3445        private ModelException.Detail newImplementationInheritanceCycleConstraintDetail(
3446            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3447            final Implementation cycle )
3448        {
3449            final ModelException.Detail detail = new ModelException.Detail(
3450                "IMPLEMENTATION_INHERITANCE_CYCLE_CONSTRAINT", Level.SEVERE,
3451                this.getMessage( "implementationInheritanceCycleConstraint", new Object[]
3452                {
3453                    implementation.getIdentifier(), cycle.getIdentifier()
3454                } ) );
3455    
3456            detail.setElement( element );
3457            return detail;
3458        }
3459    
3460        private ModelException.Detail newImplementationInheritanceCompatibilityConstraintDetail(
3461            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3462            final Implementation superImplementation, final String expectedVersion )
3463        {
3464            final ModelException.Detail detail = new ModelException.Detail(
3465                "IMPLEMENTATION_INHERITANCE_COMPATIBILITY_CONSTRAINT", Level.SEVERE,
3466                this.getMessage( "implementationInheritanceCompatibilityConstraint", new Object[]
3467                {
3468                    implementation.getIdentifier(), superImplementation.getIdentifier(), superImplementation.getVersion(),
3469                    expectedVersion
3470                } ) );
3471    
3472            detail.setElement( element );
3473            return detail;
3474        }
3475    
3476        private ModelException.Detail newSpecificationVersioningConstraintDetail(
3477            final JAXBElement<? extends ModelObject> element, final Implementation implementation,
3478            final Specification specification )
3479        {
3480            final ModelException.Detail detail = new ModelException.Detail(
3481                "SPECIFICATION_VERSIONING_CONSTRAINT", Level.SEVERE,
3482                this.getMessage( "specificationVersioningConstraint", new Object[]
3483                {
3484                    implementation.getIdentifier(), specification.getIdentifier()
3485                } ) );
3486    
3487            detail.setElement( element );
3488            return detail;
3489        }
3490    
3491        private ModelException.Detail newImplementationVersioningConstraintDetail(
3492            final JAXBElement<? extends ModelObject> element, final Implementation declaring,
3493            final Implementation implementation )
3494        {
3495            final ModelException.Detail detail = new ModelException.Detail(
3496                "IMPLEMENTATION_VERSIONING_CONSTRAINT", Level.SEVERE,
3497                this.getMessage( "implementationVersioningConstraint", new Object[]
3498                {
3499                    declaring.getIdentifier(), implementation.getIdentifier()
3500                } ) );
3501    
3502            detail.setElement( element );
3503            return detail;
3504        }
3505    
3506        // SECTION-END
3507    }