View Javadoc

1   /*
2    *  jDTAUS Core RI Client Container
3    *  Copyright (C) 2005 Christian Schulte
4    *  <cs@schulte.it>
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19   *
20   */
21  package org.jdtaus.core.container.ri.client;
22  
23  import java.beans.Beans;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.lang.reflect.Constructor;
27  import java.lang.reflect.InvocationTargetException;
28  import java.lang.reflect.Method;
29  import java.lang.reflect.Modifier;
30  import java.net.URI;
31  import java.net.URISyntaxException;
32  import java.net.URL;
33  import java.text.MessageFormat;
34  import java.text.ParseException;
35  import java.util.Arrays;
36  import java.util.Collection;
37  import java.util.Collections;
38  import java.util.Comparator;
39  import java.util.Enumeration;
40  import java.util.HashMap;
41  import java.util.HashSet;
42  import java.util.Iterator;
43  import java.util.LinkedList;
44  import java.util.List;
45  import java.util.Locale;
46  import java.util.Map;
47  import java.util.Set;
48  import java.util.TreeMap;
49  import java.util.logging.Level;
50  import java.util.logging.Logger;
51  import javax.xml.parsers.DocumentBuilder;
52  import javax.xml.parsers.DocumentBuilderFactory;
53  import javax.xml.parsers.ParserConfigurationException;
54  import javax.xml.transform.ErrorListener;
55  import javax.xml.transform.Transformer;
56  import javax.xml.transform.TransformerConfigurationException;
57  import javax.xml.transform.TransformerException;
58  import javax.xml.transform.TransformerFactory;
59  import javax.xml.transform.dom.DOMResult;
60  import javax.xml.transform.dom.DOMSource;
61  import javax.xml.transform.stream.StreamSource;
62  import org.jdtaus.core.container.Argument;
63  import org.jdtaus.core.container.Arguments;
64  import org.jdtaus.core.container.Dependencies;
65  import org.jdtaus.core.container.Dependency;
66  import org.jdtaus.core.container.DuplicateSpecificationException;
67  import org.jdtaus.core.container.IllegalPropertyTypeException;
68  import org.jdtaus.core.container.Implementation;
69  import org.jdtaus.core.container.Implementations;
70  import org.jdtaus.core.container.IncompatibleImplementationException;
71  import org.jdtaus.core.container.Message;
72  import org.jdtaus.core.container.Messages;
73  import org.jdtaus.core.container.MissingImplementationException;
74  import org.jdtaus.core.container.MissingPropertyException;
75  import org.jdtaus.core.container.MissingSpecificationException;
76  import org.jdtaus.core.container.Model;
77  import org.jdtaus.core.container.ModelError;
78  import org.jdtaus.core.container.ModelObject;
79  import org.jdtaus.core.container.Module;
80  import org.jdtaus.core.container.Modules;
81  import org.jdtaus.core.container.Properties;
82  import org.jdtaus.core.container.Property;
83  import org.jdtaus.core.container.PropertyOverwriteConstraintException;
84  import org.jdtaus.core.container.Specification;
85  import org.jdtaus.core.container.Specifications;
86  import org.jdtaus.core.container.Text;
87  import org.jdtaus.core.container.ri.client.versioning.VersionParser;
88  import org.w3c.dom.Document;
89  import org.w3c.dom.Element;
90  import org.w3c.dom.NodeList;
91  import org.xml.sax.ErrorHandler;
92  import org.xml.sax.SAXException;
93  import org.xml.sax.SAXParseException;
94  
95  /**
96   * {@code Model} reference implementation.
97   *
98   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
99   * @version $JDTAUS: DefaultModel.java 8743 2012-10-07 03:06:20Z schulte $
100  *
101  * @see <a href="http://xml.jdtaus.org/1.0.x/jdtaus-core/jdtaus-core-schemas/jdtaus-container-1.1.xsd">jdtaus-container-1.1.xsd</a>
102  */
103 public class DefaultModel implements Model
104 {
105     //--Constants---------------------------------------------------------------
106 
107     /** JAXP configuration key to the Schema implementation attribute. */
108     private static final String SCHEMA_LANGUAGE_KEY =
109         "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
110 
111     /** JAXP Schema implementation to use. */
112     private static final String SCHEMA_LANGUAGE =
113         "http://www.w3.org/2001/XMLSchema";
114 
115     /**
116      * jDTAUS {@code Model} namespace URI for the deprecated 1.0 and 1.1 model.
117      */
118     private static final String MODEL_NS =
119         "http://jdtaus.org/runtime/container/xml";
120 
121     /** {@code jDTAUS Container Model} namespace URI. */
122     private static final String CONTAINER_NS =
123         "http://jdtaus.org/core/model/container";
124 
125     /** {@code jDTAUS Container Model RI} namespace URI. */
126     private static final String MODULE_NS =
127         "http://jdtaus.org/core/model/container/module";
128 
129     /** Location of the document resources searched for by default. */
130     private static final String MODEL_LOCATION =
131         "META-INF/jdtaus/module.xml";
132 
133     /** Location of the transformation resources searched for by default. */
134     private static final String TRANSFORMATION_LOCATION =
135         "META-INF/jdtaus/container.xslt";
136 
137     /** Model versions supported by this implementation. */
138     private static final String[] SUPPORTED_MODEL_VERSIONS =
139     {
140         "1.0", "1.1", "1.2", "1.3", "1.4"
141     };
142 
143     /** String constructor arguments. */
144     private static final Class[] CTOR_ARGS_STRING =
145     {
146         String.class
147     };
148 
149     /** String constructor arguments. */
150     private static final Class[] CTOR_ARGS_CHAR =
151     {
152         char.class
153     };
154 
155     /** Constant for the name of the platform module. */
156     private static final String PLATFORM_MODULE_NAME = Model.class.getName();
157 
158     /** Constant for the version of the platform module. */
159     private static final String PLATFORM_MODULE_VERSION = "1.0";
160 
161     /** Constant for model version 1.1. */
162     private static final String V_1_1 = "1.1";
163 
164     /** Constant for model version 1.3. */
165     private static final String V_1_3 = "1.3";
166 
167     /** Constant for model version 1.4. */
168     private static final String V_1_4 = "1.4";
169 
170     /** Constant for the maximum supported model version. */
171     private static final String MODEL_VERSION = V_1_4;
172 
173     //---------------------------------------------------------------Constants--
174     //--Constructors------------------------------------------------------------
175 
176     /**
177      * Creates a new {@code DefaultModel} instance.
178      *
179      * @throws ModelError if no model can be read.
180      *
181      * @see #readModules()
182      */
183     public DefaultModel()
184     {
185         try
186         {
187             this.modules = this.readModules();
188             // Add the platform module.
189             final Module[] modulesWithPlatform =
190                 new Module[ this.modules.size() + 1 ];
191 
192             System.arraycopy( this.modules.getModules(), 0, modulesWithPlatform,
193                               0, this.modules.size() );
194 
195             modulesWithPlatform[this.modules.size()] = this.getPlatformModule();
196             this.modules.setModules( modulesWithPlatform );
197 
198             this.linkParentImplementations();
199             this.assertSpecificationsAvailable();
200             this.updateSpecificationReferences();
201             this.linkImplementedSpecifications();
202             this.linkDependencies();
203             this.assertCompatibility();
204             this.assertOverwrittenProperties();
205             this.assertImplementedProperties();
206         }
207         catch ( final ParserConfigurationException e )
208         {
209             throw new ModelError( e );
210         }
211         catch ( final SAXException e )
212         {
213             throw new ModelError( e );
214         }
215         catch ( final IOException e )
216         {
217             throw new ModelError( e );
218         }
219         catch ( final ParseException e )
220         {
221             throw new ModelError( e );
222         }
223         catch ( final TransformerConfigurationException e )
224         {
225             throw new ModelError( e );
226         }
227         catch ( final TransformerException e )
228         {
229             throw new ModelError( e );
230         }
231         catch ( final URISyntaxException e )
232         {
233             throw new ModelError( e );
234         }
235         finally
236         {
237             this.specifications = null;
238             this.implementations = null;
239             this.dependencies = null;
240             this.impl2parent = null;
241             this.moduleMap = null;
242         }
243     }
244 
245     //------------------------------------------------------------Constructors--
246     //--Model-------------------------------------------------------------------
247 
248     public Modules getModules()
249     {
250         return this.modules;
251     }
252 
253     //-------------------------------------------------------------------Model--
254     //--DefaultModel------------------------------------------------------------
255 
256     /** Logger of the class. */
257     private static final Logger LOGGER =
258         Logger.getLogger( DefaultModel.class.getName() );
259 
260     /** Holds the instance of the platform module. */
261     private Module platformModule;
262 
263     /** Holds the loaded model. */
264     private Modules modules;
265 
266     /**
267      * Maps specification identifiers to a list of specification instances by
268      * version.
269      */
270     private Map/*<String,Collection>*/ specifications = new HashMap( 1000 );
271 
272     /** Maps implementation identifiers to implementation instances. */
273     private Map/*<String,Implementation>*/ implementations = new HashMap( 1000 );
274 
275     /**
276      * Maps identifiers of implementations to identifiers of parent
277      * implementations.
278      */
279     private Map/*<String,String>*/ impl2parent = new HashMap( 1000 );
280 
281     /** Maps dependency keys to implementation names. */
282     private Map/*<String,String>*/ dependencies = new HashMap( 1000 );
283 
284     /** Maps module names to resource URLs. */
285     private Map/*<String,URL>*/ moduleMap = new HashMap( 1000 );
286 
287     /**
288      * Reads the module resources.
289      *
290      * @return all read modules without resolved references.
291      *
292      * @throws IOException if reading fails.
293      * @throws ParserConfigurationException if configuring the parser fails.
294      * @throws SAXException if parsing documents fails.
295      * @throws ParseException if parsing versions fails.
296      * @throws TransformerException if creating a transformer fails or if
297      * transforming documents fails.
298      * @throws URISyntaxException if creating a resource URI fails.
299      */
300     private Modules readModules()
301         throws IOException, ParserConfigurationException, SAXException,
302                ParseException, TransformerException, URISyntaxException
303     {
304         final Map documents = new HashMap();
305         final DocumentBuilderFactory xmlFactory =
306             DocumentBuilderFactory.newInstance();
307 
308         final Enumeration resources = ClassLoaderFactory.loadResources(
309             this.getClass(), MODEL_LOCATION );
310 
311         xmlFactory.setNamespaceAware( true );
312 
313         try
314         {
315             xmlFactory.setValidating( true );
316             xmlFactory.setAttribute( SCHEMA_LANGUAGE_KEY, SCHEMA_LANGUAGE );
317         }
318         catch ( final IllegalArgumentException e )
319         {
320             LOGGER.log( Level.CONFIG, e.getMessage() );
321             LOGGER.log( Level.WARNING, DefaultModelBundle.getInstance().
322                 getNoValidationWarningMessage( Locale.getDefault(),
323                                                e.getMessage() ) );
324 
325             xmlFactory.setValidating( false );
326         }
327 
328         final DocumentBuilder xmlBuilder = xmlFactory.newDocumentBuilder();
329         xmlBuilder.setEntityResolver( new BootstrapEntityResolver() );
330 
331         // Parse and validate all files from the classpath.
332         while ( resources.hasMoreElements() )
333         {
334             final URL resource = (URL) resources.nextElement();
335 
336             if ( LOGGER.isLoggable( Level.FINE ) )
337             {
338                 LOGGER.log( Level.FINE, DefaultModelBundle.getInstance().
339                     getResourceInformationMessage(
340                     Locale.getDefault(), resource.toExternalForm() ) );
341 
342             }
343 
344             final InputStream stream = resource.openStream();
345             xmlBuilder.setErrorHandler(
346                 new ErrorHandler()
347                 {
348 
349                     public void warning( final SAXParseException e )
350                     {
351                         LOGGER.log( Level.WARNING,
352                                     DefaultModelBundle.getInstance().
353                             getParseExceptionMessage(
354                             Locale.getDefault(), resource.toExternalForm(),
355                             e.getMessage(), new Integer( e.getLineNumber() ),
356                             new Integer( e.getColumnNumber() ) ) );
357 
358                     }
359 
360                     public void fatalError( final SAXParseException e )
361                         throws SAXException
362                     {
363                         throw new SAXException(
364                             DefaultModelBundle.getInstance().
365                             getParseExceptionMessage(
366                             Locale.getDefault(), resource.toExternalForm(),
367                             e.getMessage(), new Integer( e.getLineNumber() ),
368                             new Integer( e.getColumnNumber() ) ), e );
369 
370                     }
371 
372                     public void error( final SAXParseException e )
373                         throws SAXException
374                     {
375                         throw new SAXException(
376                             DefaultModelBundle.getInstance().
377                             getParseExceptionMessage(
378                             Locale.getDefault(), resource.toExternalForm(),
379                             e.getMessage(), new Integer( e.getLineNumber() ),
380                             new Integer( e.getColumnNumber() ) ), e );
381 
382                     }
383 
384                 } );
385 
386             final Document doc = xmlBuilder.parse( stream );
387             stream.close();
388             documents.put( new URI( resource.toString() ), doc );
389         }
390 
391         // Transform the XML documents.
392         return this.transformDocuments( documents );
393     }
394 
395     private void updateSpecificationReferences()
396     {
397         for ( int m = this.modules.size() - 1; m >= 0; m-- )
398         {
399             final Module module = this.modules.getModule( m );
400             for ( int s = module.getSpecifications().size() - 1; s >= 0; s-- )
401             {
402                 final Specification spec = module.getSpecifications().
403                     getSpecification( s );
404 
405                 final Collection references =
406                     (Collection) this.specifications.get( spec.getIdentifier() );
407 
408                 assert references != null : "Expected specification meta-data.";
409 
410                 for ( final Iterator it = references.iterator(); it.hasNext(); )
411                 {
412                     final Specification reference = (Specification) it.next();
413                     reference.setModuleName( module.getName() );
414 
415                     if ( !reference.equals( spec ) )
416                     {
417                         reference.setDocumentation( spec.getDocumentation() );
418                         reference.setMultiplicity( spec.getMultiplicity() );
419                         reference.setProperties( spec.getProperties() );
420                         reference.setScope( spec.getScope() );
421                         reference.setStateless( spec.isStateless() );
422                         reference.setVendor( spec.getVendor() );
423                         reference.setModelVersion( spec.getModelVersion() );
424                     }
425                 }
426             }
427         }
428     }
429 
430     private void linkParentImplementations()
431     {
432         for ( final Iterator it = this.implementations.entrySet().iterator();
433               it.hasNext(); )
434         {
435             final Map.Entry e = (Map.Entry) it.next();
436             final String identifier = (String) e.getKey();
437             final Implementation implementation = (Implementation) e.getValue();
438             final String parentIdentifier =
439                 (String) this.impl2parent.get( identifier );
440 
441             if ( parentIdentifier != null )
442             {
443                 final Implementation parent =
444                     (Implementation) this.implementations.get(
445                     parentIdentifier );
446 
447                 if ( parent == null )
448                 {
449                     throw new MissingImplementationException(
450                         parentIdentifier );
451 
452                 }
453 
454                 implementation.setParent( parent );
455             }
456         }
457     }
458 
459     private void linkImplementedSpecifications()
460     {
461         for ( final Iterator it = this.implementations.values().iterator();
462               it.hasNext(); )
463         {
464             final Implementation implementation = (Implementation) it.next();
465 
466             for ( int i = implementation.getImplementedSpecifications().
467                 size() - 1; i >= 0; i-- )
468             {
469                 final Specification implemented =
470                     implementation.getImplementedSpecifications().
471                     getSpecification( i );
472 
473                 final Collection specs =
474                     (Collection) this.specifications.get(
475                     implemented.getIdentifier() );
476 
477                 assert specs != null : "Expected specification meta-data.";
478 
479                 for ( final Iterator s = specs.iterator(); s.hasNext(); )
480                 {
481                     final Specification spec = (Specification) s.next();
482                     final Collection col = new LinkedList(
483                         Arrays.asList( spec.getImplementations().
484                         getImplementations() ) );
485 
486                     col.add( implementation );
487 
488                     final Implementations impls = new Implementations();
489                     impls.setImplementations(
490                         (Implementation[]) col.toArray(
491                         new Implementation[ col.size() ] ) );
492 
493                     spec.setImplementations( impls );
494                 }
495             }
496         }
497     }
498 
499     private void linkDependencies()
500     {
501         for ( final Iterator it = this.implementations.values().iterator();
502               it.hasNext(); )
503         {
504             final Implementation implementation = (Implementation) it.next();
505             for ( int i = implementation.getDeclaredDependencies().size() - 1;
506                   i >= 0; i-- )
507             {
508                 final Dependency d = implementation.getDeclaredDependencies().
509                     getDependency( i );
510 
511                 final String key =
512                     implementation.getIdentifier() + '/' + d.getName();
513 
514                 final String name = (String) this.dependencies.get( key );
515 
516                 if ( name != null )
517                 {
518                     d.setImplementation( d.getSpecification().
519                         getImplementation( name ) );
520 
521                 }
522             }
523         }
524     }
525 
526     private void assertSpecificationsAvailable()
527     {
528         final Implementation[] impls = this.modules.getImplementations().
529             getImplementations();
530 
531         for ( int i = impls.length - 1; i >= 0; i-- )
532         {
533             final Specifications specs = impls[i].getImplementedSpecifications();
534             final Dependencies deps = impls[i].getDependencies();
535 
536             for ( int j = specs.size() - 1; j >= 0; j-- )
537             {
538                 try
539                 {
540                     this.modules.getSpecification(
541                         specs.getSpecification( j ).getIdentifier() );
542 
543                 }
544                 catch ( final MissingSpecificationException e )
545                 {
546                     if ( !this.addPlatformSpecification(
547                         specs.getSpecification( j ).getIdentifier(), true ) )
548                     {
549                         throw e;
550                     }
551                 }
552             }
553 
554             for ( int j = deps.size() - 1; j >= 0; j-- )
555             {
556                 try
557                 {
558                     this.modules.getSpecification(
559                         deps.getDependency( j ).getSpecification().
560                         getIdentifier() );
561 
562                 }
563                 catch ( final MissingSpecificationException e )
564                 {
565                     if ( !this.addPlatformSpecification(
566                         deps.getDependency( j ).getSpecification().
567                         getIdentifier(), true ) )
568                     {
569                         throw e;
570                     }
571                 }
572             }
573         }
574     }
575 
576     private void assertCompatibility() throws ParseException
577     {
578         for ( int i = this.modules.getImplementations().size() - 1; i >= 0;
579               i-- )
580         {
581             final Implementation impl = this.modules.getImplementations().
582                 getImplementation( i );
583 
584             if ( impl.getModelVersion() == null ||
585                  VersionParser.compare( impl.getModelVersion(), V_1_3 ) < 0 )
586             {
587                 continue;
588             }
589 
590             final Specifications specs = impl.getImplementedSpecifications();
591             final Dependencies deps = impl.getDependencies();
592 
593             for ( int s = specs.size() - 1; s >= 0; s-- )
594             {
595                 final Specification implemented = specs.getSpecification( s );
596                 final Specification available =
597                     this.modules.getSpecification( implemented.getIdentifier() );
598 
599                 if ( available.getModelVersion() == null ||
600                      VersionParser.compare( available.getModelVersion(),
601                                             V_1_3 ) < 0 )
602                 {
603                     continue;
604                 }
605 
606                 if ( implemented.getVersion() != null )
607                 {
608                     try
609                     {
610                         if ( VersionParser.compare(
611                             implemented.getVersion(),
612                             available.getVersion() ) < 0 )
613                         {
614                             throw new IncompatibleImplementationException(
615                                 available.getIdentifier(),
616                                 available.getVersion(),
617                                 impl.getIdentifier(), implemented.getVersion(),
618                                 null );
619 
620                         }
621                     }
622                     catch ( final ParseException e )
623                     {
624                         final IncompatibleImplementationException iie =
625                             new IncompatibleImplementationException(
626                             available.getIdentifier(), available.getVersion(),
627                             impl.getIdentifier(), implemented.getVersion(),
628                             null );
629 
630                         iie.initCause( e );
631                         throw iie;
632                     }
633                 }
634             }
635 
636             for ( int d = deps.size() - 1; d >= 0; d-- )
637             {
638                 final Specification required =
639                     deps.getDependency( d ).getSpecification();
640 
641                 final Specification available =
642                     this.modules.getSpecification( required.getIdentifier() );
643 
644                 if ( available.getModelVersion() == null ||
645                      VersionParser.compare( available.getModelVersion(),
646                                             V_1_3 ) < 0 )
647                 {
648                     continue;
649                 }
650 
651                 if ( required.getVersion() != null )
652                 {
653                     try
654                     {
655                         if ( VersionParser.compare(
656                             available.getVersion(),
657                             required.getVersion() ) < 0 )
658                         {
659                             throw new IncompatibleImplementationException(
660                                 available.getIdentifier(),
661                                 available.getVersion(),
662                                 impl.getIdentifier(), null,
663                                 required.getVersion() );
664 
665                         }
666                     }
667                     catch ( final ParseException e )
668                     {
669                         final IncompatibleImplementationException iie =
670                             new IncompatibleImplementationException(
671                             available.getIdentifier(), available.getVersion(),
672                             impl.getIdentifier(), null, required.getVersion() );
673 
674                         iie.initCause( e );
675                         throw iie;
676                     }
677                 }
678             }
679         }
680     }
681 
682     private void assertOverwrittenProperties() throws ParseException
683     {
684         for ( int i = this.modules.getImplementations().size() - 1; i >= 0;
685               i-- )
686         {
687             final Implementation impl = this.modules.getImplementations().
688                 getImplementation( i );
689 
690             final Dependencies deps = impl.getDependencies();
691             for ( int d = deps.size() - 1; d >= 0; d-- )
692             {
693                 final Dependency dep = deps.getDependency( d );
694                 if ( dep.getSpecification().getScope() !=
695                      Specification.SCOPE_MULTITON &&
696                      dep.getDeclaredProperties().size() > 0 )
697                 {
698                     throw new PropertyOverwriteConstraintException(
699                         impl.getIdentifier(), dep.getName() );
700 
701                 }
702 
703                 final Properties properties = dep.getDeclaredProperties();
704                 for ( int p = properties.size() - 1; p >= 0; p-- )
705                 {
706                     final Property dependencyProperty =
707                         properties.getProperty( p );
708 
709                     try
710                     {
711                         final Property specificationProperty =
712                             dep.getSpecification().getProperties().
713                             getProperty( dependencyProperty.getName() );
714 
715                         if ( !dependencyProperty.getType().
716                             equals( specificationProperty.getType() ) )
717                         {
718                             throw new IllegalPropertyTypeException(
719                                 dependencyProperty.getName(),
720                                 dependencyProperty.getType(),
721                                 specificationProperty.getType() );
722 
723                         }
724 
725                         dependencyProperty.setApi( true );
726                     }
727                     catch ( final MissingPropertyException e )
728                     {
729                         if ( VersionParser.compare(
730                             dep.getSpecification().getModelVersion(),
731                             V_1_3 ) >= 0 )
732                         {
733                             final PropertyOverwriteConstraintException poce =
734                                 new PropertyOverwriteConstraintException(
735                                 impl.getIdentifier(), dep.getName() );
736 
737                             poce.initCause( e );
738                             throw poce;
739                         }
740                     }
741                 }
742             }
743         }
744     }
745 
746     private void assertImplementedProperties() throws ParseException
747     {
748         for ( int i = this.modules.getImplementations().size() - 1; i >= 0;
749               i-- )
750         {
751             final Map properties = new HashMap( 100 );
752             final Implementation impl = this.modules.getImplementations().
753                 getImplementation( i );
754 
755             final Specifications specs = impl.getImplementedSpecifications();
756             for ( int s = specs.size() - 1; s >= 0; s-- )
757             {
758                 final Specification implementedSpec =
759                     specs.getSpecification( s );
760 
761                 final Properties props = implementedSpec.getProperties();
762                 for ( int p = props.size() - 1; p >= 0; p-- )
763                 {
764                     final Property implementedProperty =
765                         props.getProperty( p );
766 
767                     final Property alreadyImplemented =
768                         (Property) properties.get(
769                         implementedProperty.getName() );
770 
771                     if ( alreadyImplemented != null )
772                     {
773                         if ( !implementedProperty.getType().
774                             equals( alreadyImplemented.getType() ) )
775                         {
776                             throw new IllegalPropertyTypeException(
777                                 implementedProperty.getName(),
778                                 implementedProperty.getType(),
779                                 alreadyImplemented.getType() );
780 
781                         }
782                     }
783                     else
784                     {
785                         properties.put( implementedProperty.getName(),
786                                         implementedProperty );
787 
788                     }
789 
790                     try
791                     {
792                         final Property property =
793                             impl.getProperties().getProperty(
794                             implementedProperty.getName() );
795 
796                         if ( !property.getType().
797                             equals( implementedProperty.getType() ) )
798                         {
799                             throw new IllegalPropertyTypeException(
800                                 property.getName(), property.getType(),
801                                 implementedProperty.getType() );
802 
803                         }
804                     }
805                     catch ( final MissingPropertyException e )
806                     {
807                         if ( VersionParser.compare( impl.getModelVersion(),
808                                                     V_1_3 ) >= 0 )
809                         {
810                             final PropertyOverwriteConstraintException poce =
811                                 new PropertyOverwriteConstraintException(
812                                 impl.getIdentifier(),
813                                 implementedSpec.getIdentifier(),
814                                 implementedProperty.getName() );
815 
816                             poce.initCause( e );
817                             throw poce;
818                         }
819                     }
820                 }
821             }
822 
823             for ( int p = impl.getProperties().size() - 1; p >= 0; p-- )
824             {
825                 final Property property = impl.getProperties().getProperty( p );
826                 final Property specified =
827                     (Property) properties.get( property.getName() );
828 
829                 if ( specified != null &&
830                      !property.getType().equals( specified.getType() ) )
831                 {
832                     throw new IllegalPropertyTypeException(
833                         property.getName(), property.getType(),
834                         specified.getType() );
835 
836                 }
837             }
838         }
839     }
840 
841     private Specification getSpecification( final String identifier,
842                                             final String version )
843     {
844         Collection c = (Collection) this.specifications.get( identifier );
845         if ( c == null )
846         {
847             c = new LinkedList();
848             this.specifications.put( identifier, c );
849         }
850 
851         Specification specification = null;
852         for ( final Iterator it = c.iterator(); it.hasNext(); )
853         {
854             final Specification s = (Specification) it.next();
855 
856             if ( s.getVersion() == null
857                  ? version == null
858                  : s.getVersion().equals( version ) )
859             {
860                 specification = s;
861                 break;
862             }
863         }
864 
865         if ( specification == null )
866         {
867             specification = new Specification();
868             specification.setIdentifier( identifier );
869             specification.setVersion( version );
870             c.add( specification );
871         }
872 
873         return specification;
874     }
875 
876     private Implementation getImplementation( final String identifier )
877     {
878         Implementation implementation =
879             (Implementation) this.implementations.get( identifier );
880 
881         if ( implementation == null )
882         {
883             implementation = new Implementation();
884             implementation.setIdentifier( identifier );
885             this.implementations.put( identifier, implementation );
886         }
887 
888         return implementation;
889     }
890 
891     private Modules transformDocuments( final Map xml )
892         throws ParseException, IOException, TransformerException
893     {
894         final Modules mods = new Modules();
895         mods.setModelVersion( MODEL_VERSION );
896 
897         final List list = new LinkedList();
898 
899         for ( final Iterator it = xml.entrySet().iterator(); it.hasNext(); )
900         {
901             final Map.Entry entry = (Map.Entry) it.next();
902             Document doc = (Document) entry.getValue();
903 
904             final TransformerFactory f = TransformerFactory.newInstance();
905             final Enumeration transformers = ClassLoaderFactory.loadResources(
906                 this.getClass(), TRANSFORMATION_LOCATION );
907 
908             while ( transformers.hasMoreElements() )
909             {
910                 final URL rsrc = (URL) transformers.nextElement();
911 
912                 if ( LOGGER.isLoggable( Level.CONFIG ) )
913                 {
914                     LOGGER.log( Level.CONFIG, DefaultModelBundle.getInstance().
915                         getResourceInformationMessage(
916                         Locale.getDefault(), rsrc.toExternalForm() ) );
917 
918                 }
919 
920                 f.setErrorListener( new ErrorListener()
921                 {
922 
923                     public void warning( final TransformerException e )
924                         throws TransformerException
925                     {
926                         LOGGER.log( Level.WARNING,
927                                     DefaultModelBundle.getInstance().
928                             getParseExceptionMessage(
929                             Locale.getDefault(), rsrc.toExternalForm(),
930                             e.getMessage(),
931                             new Integer( e.getLocator().getLineNumber() ),
932                             new Integer( e.getLocator().getColumnNumber() ) ) );
933 
934                     }
935 
936                     public void error( final TransformerException e )
937                         throws TransformerException
938                     {
939                         throw new TransformerException(
940                             DefaultModelBundle.getInstance().
941                             getParseExceptionMessage(
942                             Locale.getDefault(), rsrc.toExternalForm(),
943                             e.getMessage(),
944                             new Integer( e.getLocator().getLineNumber() ),
945                             new Integer( e.getLocator().getColumnNumber() ) ),
946                             e );
947 
948                     }
949 
950                     public void fatalError( final TransformerException e )
951                         throws TransformerException
952                     {
953                         throw new TransformerException(
954                             DefaultModelBundle.getInstance().
955                             getParseExceptionMessage(
956                             Locale.getDefault(), rsrc.toExternalForm(),
957                             e.getMessage(),
958                             new Integer( e.getLocator().getLineNumber() ),
959                             new Integer( e.getLocator().getColumnNumber() ) ),
960                             e );
961 
962                     }
963 
964                 } );
965 
966                 final Transformer t =
967                     f.newTransformer( new StreamSource( rsrc.openStream() ) );
968 
969                 final DOMSource source = new DOMSource( doc );
970                 final DOMResult result = new DOMResult();
971                 t.transform( source, result );
972 
973                 doc = (Document) result.getNode();
974             }
975 
976             final URL documentResource = ( (URI) entry.getKey() ).toURL();
977             final Element e = doc.getDocumentElement();
978             String namespace = doc.getDocumentElement().getNamespaceURI();
979 
980             if ( namespace == null )
981             {
982                 throw new ModelError(
983                     DefaultModelBundle.getInstance().
984                     getUnknownNamespaceMessage(
985                     Locale.getDefault(), namespace,
986                     doc.getDocumentElement().getNodeName() ) );
987 
988             }
989 
990             final boolean deprecatedModel;
991             final String modelVersion;
992 
993             if ( MODEL_NS.equals( namespace ) )
994             {
995                 deprecatedModel = true;
996 
997                 if ( !e.hasAttributeNS( namespace, "version" ) )
998                 {
999                     throw new ModelError(
1000                         DefaultModelBundle.getInstance().
1001                         getMissingAttributeMessage(
1002                         Locale.getDefault(), "version", e.getLocalName() ) );
1003 
1004                 }
1005 
1006                 modelVersion = e.getAttributeNS( namespace, "version" );
1007             }
1008             else if ( MODULE_NS.equals( namespace ) )
1009             {
1010                 deprecatedModel = true;
1011                 namespace = CONTAINER_NS;
1012 
1013                 if ( !e.hasAttributeNS( MODULE_NS, "modelVersion" ) )
1014                 {
1015                     throw new ModelError(
1016                         DefaultModelBundle.getInstance().
1017                         getMissingAttributeMessage(
1018                         Locale.getDefault(), "modelVersion",
1019                         e.getLocalName() ) );
1020 
1021                 }
1022 
1023                 modelVersion = e.getAttributeNS( MODULE_NS, "modelVersion" );
1024             }
1025             else if ( CONTAINER_NS.equals( namespace ) )
1026             {
1027                 deprecatedModel = false;
1028 
1029                 if ( !e.hasAttributeNS( CONTAINER_NS, "modelVersion" ) )
1030                 {
1031                     throw new ModelError(
1032                         DefaultModelBundle.getInstance().
1033                         getMissingAttributeMessage(
1034                         Locale.getDefault(), "modelVersion",
1035                         e.getLocalName() ) );
1036 
1037                 }
1038 
1039                 modelVersion = e.getAttributeNS( CONTAINER_NS, "modelVersion" );
1040             }
1041             else
1042             {
1043                 throw new ModelError(
1044                     DefaultModelBundle.getInstance().
1045                     getUnknownNamespaceMessage(
1046                     Locale.getDefault(), namespace,
1047                     doc.getDocumentElement().getLocalName() ) );
1048 
1049             }
1050 
1051             boolean versionSupported = false;
1052             if ( modelVersion != null )
1053             {
1054                 for ( int i = SUPPORTED_MODEL_VERSIONS.length - 1; i >= 0; i-- )
1055                 {
1056                     if ( SUPPORTED_MODEL_VERSIONS[i].equals( modelVersion ) )
1057                     {
1058                         versionSupported = true;
1059                         break;
1060                     }
1061                 }
1062             }
1063 
1064             if ( !versionSupported )
1065             {
1066                 throw new ModelError(
1067                     DefaultModelBundle.getInstance().
1068                     getUnsupportedModelversionMessage(
1069                     Locale.getDefault(), modelVersion ) );
1070 
1071             }
1072 
1073             if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1074             {
1075                 if ( e.getLocalName().equals( "module" ) )
1076                 {
1077                     final Module m = this.transformModule(
1078                         modelVersion, namespace, e, documentResource );
1079 
1080                     if ( m != null )
1081                     {
1082                         list.add( m );
1083                     }
1084                 }
1085                 else if ( e.getLocalName().equals( "modules" ) )
1086                 {
1087                     final NodeList l = e.getElementsByTagNameNS( namespace,
1088                                                                  "module" );
1089 
1090                     for ( int i = l.getLength() - 1; i >= 0; i-- )
1091                     {
1092                         if ( l.item( i ).getParentNode().equals( e ) )
1093                         {
1094                             final Module m = this.transformModule(
1095                                 modelVersion, namespace, (Element) l.item( i ),
1096                                 documentResource );
1097 
1098                             if ( m != null )
1099                             {
1100                                 list.add( m );
1101                             }
1102                         }
1103                     }
1104                 }
1105                 else
1106                 {
1107                     throw new ModelError(
1108                         DefaultModelBundle.getInstance().
1109                         getUnsupportedElementMessage( Locale.getDefault(),
1110                                                       e.getLocalName() ) );
1111 
1112                 }
1113             }
1114             else
1115             {
1116                 final Module m = this.transformModule( modelVersion, namespace,
1117                                                        e, documentResource );
1118 
1119                 if ( m != null )
1120                 {
1121                     list.add( m );
1122                 }
1123             }
1124 
1125             if ( deprecatedModel )
1126             {
1127                 if ( LOGGER.isLoggable( Level.CONFIG ) )
1128                 {
1129                     LOGGER.log( Level.CONFIG, DefaultModelBundle.getInstance().
1130                         getDeprecatedModelMessage( Locale.getDefault(),
1131                                                    namespace,
1132                                                    modelVersion ) );
1133 
1134                 }
1135             }
1136         }
1137 
1138         // Merge any provided platform modules.
1139         Module providedPlatformModule = null;
1140         for ( final Iterator it = list.iterator(); it.hasNext(); )
1141         {
1142             final Module module = (Module) it.next();
1143             if ( PLATFORM_MODULE_NAME.equals( module.getName() ) )
1144             {
1145                 providedPlatformModule = module;
1146                 it.remove();
1147                 break;
1148             }
1149         }
1150 
1151         mods.setModules(
1152             (Module[]) list.toArray( new Module[ list.size() ] ) );
1153 
1154         this.modules = mods;
1155 
1156         if ( providedPlatformModule != null &&
1157              providedPlatformModule.getSpecifications() != null )
1158         {
1159             for ( int i = providedPlatformModule.getSpecifications().size() - 1;
1160                   i >= 0; i-- )
1161             {
1162                 this.addPlatformSpecification(
1163                     providedPlatformModule.getSpecifications().
1164                     getSpecification( i ).getIdentifier(), true );
1165 
1166             }
1167         }
1168 
1169         return mods;
1170     }
1171 
1172     private Specifications transformSpecifications(
1173         final String modelVersion, final String namespace,
1174         final Element specificationsElement ) throws ParseException
1175     {
1176         final List list = new LinkedList();
1177         NodeList l =
1178             specificationsElement.getElementsByTagNameNS( namespace,
1179                                                           "specification" );
1180 
1181         if ( l != null && l.getLength() > 0 )
1182         {
1183             for ( int i = l.getLength() - 1; i >= 0; i-- )
1184             {
1185                 if ( l.item( i ).getParentNode().
1186                     equals( specificationsElement ) )
1187                 {
1188                     list.add( this.transformSpecification(
1189                         modelVersion, namespace, (Element) l.item( i ) ) );
1190 
1191                 }
1192             }
1193         }
1194 
1195         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1196         {
1197             l = specificationsElement.getElementsByTagNameNS( namespace,
1198                                                               "reference" );
1199 
1200             if ( l != null && l.getLength() > 0 )
1201             {
1202                 for ( int i = l.getLength() - 1; i >= 0; i-- )
1203                 {
1204                     if ( l.item( i ).getParentNode().
1205                         equals( specificationsElement ) )
1206                     {
1207                         list.add(
1208                             this.transformSpecificationReference(
1209                             namespace, (Element) l.item( i ) ) );
1210 
1211                     }
1212                 }
1213             }
1214         }
1215 
1216         final Specifications specs = new Specifications();
1217         specs.setModelVersion( modelVersion );
1218         specs.setSpecifications( (Specification[]) list.toArray(
1219             new Specification[ list.size() ] ) );
1220 
1221         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1222         {
1223             this.transformModelObject( namespace, specificationsElement, specs );
1224         }
1225 
1226         return specs;
1227     }
1228 
1229     private Implementations transformImplementations(
1230         final String modelVersion, final String namespace,
1231         final Module module, final Element implementationsElement )
1232         throws ParseException
1233     {
1234         final List list = new LinkedList();
1235         final NodeList l =
1236             implementationsElement.getElementsByTagNameNS( namespace,
1237                                                            "implementation" );
1238 
1239         if ( l != null && l.getLength() > 0 )
1240         {
1241             for ( int i = l.getLength() - 1; i >= 0; i-- )
1242             {
1243                 if ( l.item( i ).getParentNode().
1244                     equals( implementationsElement ) )
1245                 {
1246                     list.add( this.transformImplementation(
1247                         modelVersion, namespace, module,
1248                         (Element) l.item( i ) ) );
1249 
1250                 }
1251             }
1252         }
1253 
1254         final Implementations impls = new Implementations();
1255         impls.setModelVersion( modelVersion );
1256         impls.setImplementations( (Implementation[]) list.toArray(
1257             new Implementation[ list.size() ] ) );
1258 
1259         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1260         {
1261             this.transformModelObject( namespace, implementationsElement,
1262                                        impls );
1263 
1264         }
1265 
1266         return impls;
1267     }
1268 
1269     private Properties transformProperties(
1270         final String modelVersion, final String namespace,
1271         final Element propertiesElement )
1272         throws ParseException
1273     {
1274         final Map transformed = new TreeMap();
1275         final NodeList l =
1276             propertiesElement.getElementsByTagNameNS( namespace, "property" );
1277 
1278         if ( l != null && l.getLength() > 0 )
1279         {
1280             for ( int i = l.getLength() - 1; i >= 0; i-- )
1281             {
1282                 if ( l.item( i ).getParentNode().equals( propertiesElement ) )
1283                 {
1284                     final Property p = this.transformProperty(
1285                         modelVersion, namespace, (Element) l.item( i ) );
1286 
1287                     if ( propertiesElement.getParentNode().getLocalName().
1288                         equals( "specification" ) )
1289                     {
1290                         p.setValue( null );
1291                         p.setApi( true );
1292                     }
1293 
1294                     transformed.put( p.getName(), p );
1295                 }
1296             }
1297         }
1298 
1299         final Properties props = new Properties();
1300         props.setModelVersion( modelVersion );
1301         props.setProperties( (Property[]) transformed.values().toArray(
1302             new Property[ transformed.size() ] ) );
1303 
1304         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1305         {
1306             this.transformModelObject( namespace, propertiesElement, props );
1307         }
1308 
1309         return props;
1310     }
1311 
1312     private Dependencies transformDependencies(
1313         final String modelVersion, final String namespace,
1314         final String implementationIdentifier,
1315         final Element dependenciesElement ) throws ParseException
1316     {
1317         final List list = new LinkedList();
1318         final NodeList l =
1319             dependenciesElement.getElementsByTagNameNS( namespace,
1320                                                         "dependency" );
1321 
1322         if ( l != null && l.getLength() > 0 )
1323         {
1324             for ( int i = l.getLength() - 1; i >= 0; i-- )
1325             {
1326                 if ( l.item( i ).getParentNode().equals( dependenciesElement ) )
1327                 {
1328                     list.add(
1329                         this.transformDependency( modelVersion, namespace,
1330                                                   implementationIdentifier,
1331                                                   (Element) l.item( i ) ) );
1332 
1333                 }
1334             }
1335         }
1336 
1337         final Dependencies deps = new Dependencies();
1338         deps.setModelVersion( modelVersion );
1339         deps.setDependencies( (Dependency[]) list.toArray(
1340             new Dependency[ list.size() ] ) );
1341 
1342         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1343         {
1344             this.transformModelObject( namespace, dependenciesElement, deps );
1345         }
1346 
1347         return deps;
1348     }
1349 
1350     private Messages transformMessages(
1351         final String modelVersion, final String namespace, final Module module,
1352         final Element messagesElement )
1353     {
1354         final List messages = new LinkedList();
1355         NodeList l = messagesElement.getElementsByTagNameNS( namespace,
1356                                                              "message" );
1357 
1358         if ( l != null && l.getLength() > 0 )
1359         {
1360             for ( int i = l.getLength() - 1; i >= 0; i-- )
1361             {
1362                 if ( l.item( i ).getParentNode().equals( messagesElement ) )
1363                 {
1364                     messages.add(
1365                         this.transformMessage( modelVersion, module.getName(),
1366                                                namespace,
1367                                                (Element) l.item( i ) ) );
1368 
1369                 }
1370             }
1371         }
1372 
1373         l = messagesElement.getElementsByTagNameNS( namespace,
1374                                                     "reference" );
1375 
1376         if ( l != null && l.getLength() > 0 )
1377         {
1378             for ( int i = l.getLength() - 1; i >= 0; i-- )
1379             {
1380                 if ( l.item( i ).getParentNode().equals( messagesElement ) )
1381                 {
1382                     final String name =
1383                         ( (Element) l.item( i ) ).getAttributeNS(
1384                         namespace, "name" );
1385 
1386                     messages.add( module.getMessages().getMessage( name ) );
1387                 }
1388             }
1389         }
1390 
1391         final Messages msgs = new Messages();
1392         msgs.setModelVersion( modelVersion );
1393         msgs.setMessages( (Message[]) messages.toArray(
1394             new Message[ messages.size() ] ) );
1395 
1396         this.transformModelObject( namespace, messagesElement, msgs );
1397 
1398         return msgs;
1399     }
1400 
1401     private Arguments transformArguments(
1402         final String modelVersion, final String namespace,
1403         final Element argumentsElement )
1404     {
1405         final List arguments = new LinkedList();
1406         final NodeList l =
1407             argumentsElement.getElementsByTagNameNS( namespace,
1408                                                      "argument" );
1409 
1410         if ( l != null && l.getLength() > 0 )
1411         {
1412             for ( int i = l.getLength() - 1; i >= 0; i-- )
1413             {
1414                 if ( l.item( i ).getParentNode().equals( argumentsElement ) )
1415                 {
1416                     arguments.add(
1417                         this.transformArgument( modelVersion, namespace,
1418                                                 (Element) l.item( i ) ) );
1419 
1420                 }
1421             }
1422         }
1423 
1424         Collections.sort( arguments, new Comparator()
1425         {
1426 
1427             public int compare( final Object o1, final Object o2 )
1428             {
1429                 return ( (Argument) o1 ).getIndex() -
1430                        ( (Argument) o2 ).getIndex();
1431 
1432             }
1433 
1434         } );
1435 
1436         final Arguments args = new Arguments();
1437         args.setModelVersion( modelVersion );
1438         args.setArguments( (Argument[]) arguments.toArray(
1439             new Argument[ arguments.size() ] ) );
1440 
1441         this.transformModelObject( namespace, argumentsElement, args );
1442 
1443         return args;
1444     }
1445 
1446     private Module transformModule( final String modelVersion,
1447                                     final String namespace, final Element e,
1448                                     final URL documentResource )
1449         throws ParseException
1450     {
1451         NodeList l;
1452         Module module = new Module();
1453         module.setModelVersion( modelVersion );
1454         module.setName( e.getAttributeNS( namespace, "name" ) );
1455         module.setVersion( e.getAttributeNS( namespace, "version" ) );
1456         if ( e.hasAttributeNS( namespace, "description" ) )
1457         {
1458             final String txt = e.getAttributeNS( namespace, "description" );
1459             module.setDescription( txt );
1460         }
1461 
1462         l = e.getElementsByTagNameNS( namespace, "specifications" );
1463 
1464         if ( l != null && l.getLength() > 0 )
1465         {
1466             for ( int i = l.getLength() - 1; i >= 0; i-- )
1467             {
1468                 if ( l.item( i ).getParentNode().equals( e ) )
1469                 {
1470                     module.setSpecifications(
1471                         this.transformSpecifications(
1472                         modelVersion, namespace, (Element) l.item( i ) ) );
1473 
1474                     break;
1475                 }
1476             }
1477         }
1478 
1479         l = e.getElementsByTagNameNS( namespace, "properties" );
1480 
1481         if ( l != null && l.getLength() > 0 )
1482         {
1483             for ( int i = l.getLength() - 1; i >= 0; i-- )
1484             {
1485                 if ( l.item( i ).getParentNode().equals( e ) )
1486                 {
1487                     module.setProperties(
1488                         this.transformProperties(
1489                         modelVersion, namespace, (Element) l.item( i ) ) );
1490 
1491                     break;
1492                 }
1493             }
1494         }
1495 
1496         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1497         {
1498             l = e.getElementsByTagNameNS( namespace, "messages" );
1499 
1500             if ( l != null && l.getLength() > 0 )
1501             {
1502                 for ( int i = l.getLength() - 1; i >= 0; i-- )
1503                 {
1504                     if ( l.item( i ).getParentNode().equals( e ) )
1505                     {
1506                         module.setMessages(
1507                             this.transformMessages(
1508                             modelVersion, namespace, module,
1509                             (Element) l.item( i ) ) );
1510 
1511                         break;
1512                     }
1513                 }
1514             }
1515 
1516             this.transformModelObject( namespace, e, module );
1517         }
1518 
1519         l = e.getElementsByTagNameNS( namespace, "implementations" );
1520 
1521         if ( l != null && l.getLength() > 0 )
1522         {
1523             for ( int i = l.getLength() - 1; i >= 0; i-- )
1524             {
1525                 if ( l.item( i ).getParentNode().equals( e ) )
1526                 {
1527                     module.setImplementations(
1528                         this.transformImplementations(
1529                         modelVersion, namespace, module,
1530                         (Element) l.item( i ) ) );
1531 
1532                     break;
1533                 }
1534             }
1535         }
1536 
1537         if ( this.moduleMap.containsKey( module.getName() ) &&
1538              Beans.isDesignTime() )
1539         {
1540             if ( LOGGER.isLoggable( Level.CONFIG ) )
1541             {
1542                 LOGGER.log( Level.CONFIG, DefaultModelBundle.getInstance().
1543                     getIgnoredModuleMessage(
1544                     Locale.getDefault(), documentResource.toExternalForm(),
1545                     ( (URL) this.moduleMap.get( module.getName() ) ).
1546                     toExternalForm() ) );
1547 
1548             }
1549 
1550             module = null;
1551         }
1552         else
1553         {
1554             this.moduleMap.put( module.getName(), documentResource );
1555         }
1556 
1557         return module;
1558     }
1559 
1560     private Specification transformSpecificationReference(
1561         final String namespace, final Element e )
1562     {
1563         String version = null;
1564         final String identifier = e.getAttributeNS( namespace, "identifier" );
1565         if ( e.hasAttributeNS( namespace, "version" ) )
1566         {
1567             version = e.getAttributeNS( namespace, "version" );
1568         }
1569 
1570         return this.getSpecification( identifier, version );
1571     }
1572 
1573     private Specification transformSpecification( final String modelVersion,
1574                                                   final String namespace,
1575                                                   final Element xml )
1576         throws ParseException
1577     {
1578         final Specification spec =
1579             this.transformSpecificationReference( namespace, xml );
1580 
1581         spec.setModelVersion( modelVersion );
1582         spec.setVendor( xml.getAttributeNS( namespace, "vendor" ) );
1583         if ( xml.hasAttributeNS( namespace, "description" ) )
1584         {
1585             final String txt = xml.getAttributeNS( namespace, "description" );
1586             spec.setDescription( txt );
1587         }
1588 
1589         if ( xml.hasAttributeNS( namespace, "singleton" ) )
1590         {
1591             spec.setSingleton(
1592                 Boolean.valueOf( xml.getAttributeNS(
1593                 namespace, "singleton" ) ).booleanValue() );
1594 
1595         }
1596 
1597         if ( VersionParser.compare( modelVersion, V_1_1 ) >= 0 )
1598         {
1599             final String multiplicity =
1600                 xml.getAttributeNS( namespace, "multiplicity" );
1601 
1602             if ( "one".equalsIgnoreCase( multiplicity ) )
1603             {
1604                 spec.setMultiplicity( Specification.MULTIPLICITY_ONE );
1605             }
1606             else if ( "many".equalsIgnoreCase( multiplicity ) )
1607             {
1608                 spec.setMultiplicity( Specification.MULTIPLICITY_MANY );
1609             }
1610             else
1611             {
1612                 throw new ModelError(
1613                     DefaultModelBundle.getInstance().
1614                     getUnsupportedMultiplicityMessage( Locale.getDefault(),
1615                                                        multiplicity ) );
1616 
1617             }
1618         }
1619 
1620         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1621         {
1622             if ( xml.hasAttributeNS( namespace, "stateless" ) )
1623             {
1624                 spec.setStateless( Boolean.valueOf( xml.getAttributeNS(
1625                     namespace, "stateless" ) ).booleanValue() );
1626 
1627             }
1628 
1629             final String scope = xml.getAttributeNS( namespace, "scope" );
1630             if ( "multiton".equalsIgnoreCase( scope ) )
1631             {
1632                 spec.setScope( Specification.SCOPE_MULTITON );
1633             }
1634             else if ( "context".equalsIgnoreCase( scope ) )
1635             {
1636                 spec.setScope( Specification.SCOPE_CONTEXT );
1637             }
1638             else if ( "singleton".equalsIgnoreCase( scope ) )
1639             {
1640                 spec.setScope( Specification.SCOPE_SINGLETON );
1641             }
1642             else
1643             {
1644                 throw new ModelError(
1645                     DefaultModelBundle.getInstance().
1646                     getUnsupportedScopeMessage( Locale.getDefault(),
1647                                                 spec.getIdentifier(), scope ) );
1648 
1649             }
1650 
1651             final NodeList l =
1652                 xml.getElementsByTagNameNS( namespace, "properties" );
1653 
1654             if ( l != null && l.getLength() > 0 )
1655             {
1656                 for ( int i = l.getLength() - 1; i >= 0; i-- )
1657                 {
1658                     if ( l.item( i ).getParentNode().equals( xml ) )
1659                     {
1660                         spec.setProperties(
1661                             this.transformProperties(
1662                             modelVersion, namespace, (Element) l.item( i ) ) );
1663 
1664                         break;
1665                     }
1666                 }
1667             }
1668 
1669             this.transformModelObject( namespace, xml, spec );
1670         }
1671 
1672         return spec;
1673     }
1674 
1675     private Implementation transformImplementation( final String modelVersion,
1676                                                     final String namespace,
1677                                                     final Module module,
1678                                                     final Element xml )
1679         throws ParseException
1680     {
1681         final String identifier = xml.getAttributeNS( namespace, "identifier" );
1682         final Implementation impl = this.getImplementation( identifier );
1683         impl.setModelVersion( modelVersion );
1684         impl.setModuleName( module.getName() );
1685         impl.setName( xml.getAttributeNS( namespace, "name" ) );
1686         impl.setVendor( xml.getAttributeNS( namespace, "vendor" ) );
1687         impl.setVersion( xml.getAttributeNS( namespace, "version" ) );
1688 
1689         if ( xml.hasAttributeNS( namespace, "parent" ) )
1690         {
1691             this.impl2parent.put( impl.getIdentifier(),
1692                                   xml.getAttributeNS( namespace, "parent" ) );
1693 
1694         }
1695 
1696         NodeList l = xml.getElementsByTagNameNS( namespace, "dependencies" );
1697 
1698         if ( l != null && l.getLength() > 0 )
1699         {
1700             for ( int i = l.getLength() - 1; i >= 0; i-- )
1701             {
1702                 if ( l.item( i ).getParentNode().equals( xml ) )
1703                 {
1704                     impl.setDependencies(
1705                         this.transformDependencies(
1706                         modelVersion, namespace, identifier,
1707                         (Element) l.item( i ) ) );
1708 
1709                     break;
1710                 }
1711             }
1712         }
1713 
1714         final String specificationsName =
1715             VersionParser.compare( modelVersion, V_1_3 ) >= 0
1716             ? "specifications"
1717             : "implementedSpecifications";
1718 
1719         l = xml.getElementsByTagNameNS( namespace, specificationsName );
1720         if ( l != null && l.getLength() > 0 )
1721         {
1722             for ( int i = l.getLength() - 1; i >= 0; i-- )
1723             {
1724                 if ( l.item( i ).getParentNode().equals( xml ) )
1725                 {
1726                     if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1727                     {
1728                         impl.setImplementedSpecifications(
1729                             this.transformSpecifications(
1730                             modelVersion, namespace, (Element) l.item( i ) ) );
1731 
1732                         break;
1733                     }
1734                     else
1735                     {
1736                         final Set set = new HashSet();
1737                         final NodeList deprecated =
1738                             ( (Element) l.item( i ) ).getElementsByTagNameNS(
1739                             namespace, "implementedSpecification" );
1740 
1741                         if ( deprecated != null && deprecated.getLength() > 0 )
1742                         {
1743                             for ( int d = deprecated.getLength() - 1; d >= 0;
1744                                   d-- )
1745                             {
1746                                 if ( deprecated.item( d ).getParentNode().
1747                                     equals( l.item( i ) ) )
1748                                 {
1749                                     set.add(
1750                                         this.transformSpecificationReference(
1751                                         namespace,
1752                                         (Element) deprecated.item( d ) ) );
1753 
1754                                 }
1755                             }
1756                         }
1757 
1758                         final Specifications specs = new Specifications();
1759                         specs.setModelVersion( modelVersion );
1760                         specs.setSpecifications(
1761                             (Specification[]) set.toArray(
1762                             new Specification[ set.size() ] ) );
1763 
1764                         impl.setImplementedSpecifications( specs );
1765                         break;
1766                     }
1767                 }
1768             }
1769         }
1770 
1771         l = xml.getElementsByTagNameNS( namespace, "properties" );
1772 
1773         if ( l != null && l.getLength() > 0 )
1774         {
1775             for ( int i = l.getLength() - 1; i >= 0; i-- )
1776             {
1777                 if ( l.item( i ).getParentNode().equals( xml ) )
1778                 {
1779                     impl.setProperties(
1780                         this.transformProperties( modelVersion, namespace,
1781                                                   (Element) l.item( i ) ) );
1782 
1783                     break;
1784                 }
1785             }
1786         }
1787 
1788         if ( VersionParser.compare( modelVersion, V_1_1 ) >= 0 &&
1789              xml.hasAttributeNS( namespace, "final" ) )
1790         {
1791             impl.setFinal( Boolean.valueOf( xml.getAttributeNS( namespace,
1792                                                                 "final" ) ).
1793                 booleanValue() );
1794 
1795         }
1796 
1797         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1798         {
1799             l = xml.getElementsByTagNameNS( namespace, "messages" );
1800 
1801             if ( l != null && l.getLength() > 0 )
1802             {
1803                 for ( int i = l.getLength() - 1; i >= 0; i-- )
1804                 {
1805                     if ( l.item( i ).getParentNode().equals( xml ) )
1806                     {
1807                         impl.setMessages( this.transformMessages(
1808                             modelVersion, namespace, module,
1809                             (Element) l.item( i ) ) );
1810 
1811                         break;
1812                     }
1813                 }
1814             }
1815 
1816             this.transformModelObject( namespace, xml, impl );
1817         }
1818 
1819         return impl;
1820     }
1821 
1822     private Property transformProperty( final String modelVersion,
1823                                         final String namespace,
1824                                         final Element xml )
1825         throws ParseException
1826     {
1827         final Property prop = new Property();
1828         prop.setModelVersion( modelVersion );
1829         prop.setName( xml.getAttributeNS( namespace, "name" ) );
1830 
1831         if ( xml.hasAttributeNS( namespace, "api" ) )
1832         {
1833             final String api = xml.getAttributeNS( namespace, "api" );
1834             prop.setApi( Boolean.valueOf( api ).booleanValue() );
1835         }
1836 
1837         final String type = xml.hasAttributeNS( namespace, "type" )
1838                             ? xml.getAttributeNS( namespace, "type" )
1839                             : null;
1840 
1841         final String value = xml.hasAttributeNS( namespace, "value" )
1842                              ? xml.getAttributeNS( namespace, "value" )
1843                              : null;
1844 
1845         if ( type == null )
1846         {
1847             throw new ModelError(
1848                 DefaultModelBundle.getInstance().
1849                 getMissingPropertyTypeMessage(
1850                 Locale.getDefault(), prop.getName(),
1851                 xml.getParentNode().getParentNode().getLocalName() ) );
1852 
1853         }
1854 
1855         this.updatePropertyValue( type, value, prop );
1856 
1857         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1858         {
1859             this.transformModelObject( namespace, xml, prop );
1860         }
1861 
1862         return prop;
1863     }
1864 
1865     private Dependency transformDependency(
1866         final String modelVersion, final String namespace,
1867         final String implementationIdentifier, final Element xml )
1868         throws ParseException
1869     {
1870         final Dependency dep = new Dependency();
1871         dep.setModelVersion( modelVersion );
1872         dep.setName( xml.getAttributeNS( namespace, "name" ) );
1873 
1874         if ( xml.hasAttributeNS( namespace, "bound" ) )
1875         {
1876             dep.setBound( Boolean.valueOf( xml.getAttributeNS( namespace,
1877                                                                "bound" ) ).
1878                 booleanValue() );
1879 
1880         }
1881 
1882         if ( xml.hasAttributeNS( namespace, "implementationName" ) )
1883         {
1884             final String name = xml.getAttributeNS( namespace,
1885                                                     "implementationName" );
1886 
1887             final String key = implementationIdentifier + '/' +
1888                                dep.getName();
1889 
1890             this.dependencies.put( key, name );
1891         }
1892 
1893         final String specificationIdentifier =
1894             VersionParser.compare( modelVersion, V_1_3 ) < 0
1895             ? "specificationIdentifier"
1896             : "identifier";
1897 
1898         final String identifier = xml.getAttributeNS( namespace,
1899                                                       specificationIdentifier );
1900 
1901         if ( VersionParser.compare( modelVersion, V_1_3 ) < 0 )
1902         {
1903             dep.setSpecification( this.getSpecification( identifier, null ) );
1904         }
1905         else
1906         {
1907             String version = null;
1908             if ( xml.hasAttributeNS( namespace, "version" ) )
1909             {
1910                 version = xml.getAttributeNS( namespace, "version" );
1911             }
1912 
1913             dep.setSpecification( this.getSpecification( identifier,
1914                                                          version ) );
1915 
1916         }
1917 
1918         final NodeList l =
1919             xml.getElementsByTagNameNS( namespace, "properties" );
1920 
1921         if ( l != null && l.getLength() > 0 )
1922         {
1923             for ( int i = l.getLength() - 1; i >= 0; i-- )
1924             {
1925                 if ( l.item( i ).getParentNode().equals( xml ) )
1926                 {
1927                     dep.setProperties(
1928                         this.transformProperties(
1929                         modelVersion, namespace, (Element) l.item( i ) ) );
1930 
1931                     break;
1932                 }
1933             }
1934         }
1935 
1936         if ( VersionParser.compare( modelVersion, V_1_3 ) >= 0 )
1937         {
1938             this.transformModelObject( namespace, xml, dep );
1939         }
1940 
1941         return dep;
1942     }
1943 
1944     private Text transformText( final String namespace,
1945                                 final Element textsElement )
1946     {
1947         final Text text = new Text();
1948         final String defaultLanguage =
1949             textsElement.getAttributeNS( namespace, "defaultLanguage" );
1950 
1951         final NodeList l =
1952             textsElement.getElementsByTagNameNS( namespace, "text" );
1953 
1954         if ( l != null && l.getLength() > 0 )
1955         {
1956             for ( int i = l.getLength() - 1; i >= 0; i-- )
1957             {
1958                 final Element textElement = (Element) l.item( i );
1959                 if ( textElement.getParentNode().equals( textsElement ) )
1960                 {
1961                     final String language =
1962                         textElement.getAttributeNS( namespace, "language" );
1963 
1964                     final String value =
1965                         textElement.getFirstChild().getNodeValue();
1966 
1967                     final Locale locale = new Locale( language.toLowerCase() );
1968                     text.setValue( locale, value );
1969 
1970                     if ( language.equalsIgnoreCase( defaultLanguage ) )
1971                     {
1972                         text.setValue( value );
1973                     }
1974                 }
1975             }
1976         }
1977 
1978         return text;
1979     }
1980 
1981     private void transformModelObject( final String namespace,
1982                                        final Element objectElement,
1983                                        final ModelObject modelObject )
1984     {
1985         final NodeList l = objectElement.getElementsByTagNameNS(
1986             namespace, "documentation" );
1987 
1988         if ( l != null && l.getLength() > 0 )
1989         {
1990             for ( int i = l.getLength() - 1; i >= 0; i-- )
1991             {
1992                 if ( l.item( i ).getParentNode().equals( objectElement ) )
1993                 {
1994                     modelObject.setDocumentation(
1995                         this.transformText( namespace,
1996                                             (Element) l.item( i ) ) );
1997 
1998                     break;
1999                 }
2000             }
2001         }
2002     }
2003 
2004     private Message transformMessage( final String modelVersion,
2005                                       final String moduleName,
2006                                       final String namespace,
2007                                       final Element xml )
2008     {
2009         final Message msg = new Message();
2010         msg.setModelVersion( modelVersion );
2011         msg.setModuleName( moduleName );
2012         msg.setName( xml.getAttributeNS( namespace, "name" ) );
2013 
2014         NodeList l = xml.getElementsByTagNameNS( namespace, "template" );
2015 
2016         if ( l != null && l.getLength() > 0 )
2017         {
2018             for ( int i = l.getLength() - 1; i >= 0; i-- )
2019             {
2020                 if ( l.item( i ).getParentNode().equals( xml ) )
2021                 {
2022                     final Text template = this.transformText(
2023                         namespace, (Element) l.item( i ) );
2024 
2025                     final Locale[] locales = template.getLocales();
2026                     for ( int t = locales.length - 1; t >= 0; t-- )
2027                     {
2028                         final String text = template.getValue( locales[t] );
2029                         try
2030                         {
2031                             new MessageFormat( text );
2032                         }
2033                         catch ( final IllegalArgumentException e )
2034                         {
2035                             final ModelError modelError = new ModelError(
2036                                 DefaultModelBundle.getInstance().
2037                                 getIllegalTemplateMessage( Locale.getDefault(),
2038                                                            text, msg.getName(),
2039                                                            e.getMessage() ) );
2040 
2041                             modelError.initCause( e );
2042                             throw modelError;
2043                         }
2044                     }
2045 
2046                     if ( template.getValue() != null )
2047                     {
2048                         try
2049                         {
2050                             new MessageFormat( template.getValue() );
2051                         }
2052                         catch ( final IllegalArgumentException e )
2053                         {
2054                             final ModelError modelError = new ModelError(
2055                                 DefaultModelBundle.getInstance().
2056                                 getIllegalTemplateMessage( Locale.getDefault(),
2057                                                            template.getValue(),
2058                                                            msg.getName(),
2059                                                            e.getMessage() ) );
2060 
2061                             modelError.initCause( e );
2062                             throw modelError;
2063                         }
2064                     }
2065 
2066                     msg.setTemplate( template );
2067                     break;
2068                 }
2069             }
2070         }
2071 
2072         l = xml.getElementsByTagNameNS( namespace, "arguments" );
2073 
2074         if ( l != null && l.getLength() > 0 )
2075         {
2076             for ( int i = l.getLength() - 1; i >= 0; i-- )
2077             {
2078                 if ( l.item( i ).getParentNode().equals( xml ) )
2079                 {
2080                     msg.setArguments(
2081                         this.transformArguments(
2082                         modelVersion, namespace, (Element) l.item( i ) ) );
2083 
2084                     break;
2085                 }
2086             }
2087         }
2088 
2089         this.transformModelObject( namespace, xml, msg );
2090 
2091         return msg;
2092     }
2093 
2094     private Argument transformArgument( final String modelVersion,
2095                                         final String namespace,
2096                                         final Element xml )
2097     {
2098         final Argument arg = new Argument();
2099         arg.setModelVersion( modelVersion );
2100         arg.setName( xml.getAttributeNS( namespace, "name" ) );
2101         arg.setIndex( Integer.valueOf( xml.getAttributeNS( namespace,
2102                                                            "index" ) ).
2103             intValue() );
2104 
2105         final String type = xml.getAttributeNS( namespace, "type" );
2106         if ( type.equalsIgnoreCase( "number" ) )
2107         {
2108             arg.setType( Argument.TYPE_NUMBER );
2109         }
2110         else if ( type.equalsIgnoreCase( "date" ) )
2111         {
2112             arg.setType( Argument.TYPE_DATE );
2113         }
2114         else if ( type.equalsIgnoreCase( "time" ) )
2115         {
2116             arg.setType( Argument.TYPE_TIME );
2117         }
2118         else if ( type.equalsIgnoreCase( "text" ) )
2119         {
2120             arg.setType( Argument.TYPE_TEXT );
2121         }
2122         else
2123         {
2124             throw new ModelError( DefaultModelBundle.getInstance().
2125                 getUnsupportedArgumentTypeMessage(
2126                 Locale.getDefault(), type ) );
2127 
2128         }
2129 
2130         this.transformModelObject( namespace, xml, arg );
2131 
2132         return arg;
2133     }
2134 
2135     /**
2136      * Gets the {@code Module} holding platform specifications.
2137      *
2138      * @return the {@code Module} holding platform specifications.
2139      */
2140     protected Module getPlatformModule()
2141     {
2142         if ( this.platformModule == null )
2143         {
2144             final String description =
2145                 DefaultModelBundle.getInstance().
2146                 getPlatformModuleDescriptionMessage( Locale.getDefault() );
2147 
2148             this.platformModule = new Module();
2149             this.platformModule.getDocumentation().setValue( description );
2150             this.platformModule.setName( PLATFORM_MODULE_NAME );
2151             this.platformModule.setVersion( PLATFORM_MODULE_VERSION );
2152 
2153             if ( LOGGER.isLoggable( Level.CONFIG ) )
2154             {
2155                 LOGGER.log( Level.CONFIG, DefaultModelBundle.getInstance().
2156                     getAddedPlatformModuleMessage(
2157                     Locale.getDefault(),
2158                     this.platformModule.getDocumentation().getValue() ) );
2159             }
2160         }
2161 
2162         return this.platformModule;
2163     }
2164 
2165     /**
2166      * Checks an identifier to identify a valid platform specification.
2167      *
2168      * @param identifier the identifier to check.
2169      *
2170      * @return {@code true} if {@code identifier} identifies a valid platform
2171      * specification; {@code false} else.
2172      *
2173      * @throws NullPointerException if {@code identifier} is {@code null}.
2174      */
2175     protected boolean isPlatformSpecification( final String identifier )
2176     {
2177         return this.addPlatformSpecification( identifier, false );
2178     }
2179 
2180     /**
2181      * Checks an identifier to identify a valid platform specification and
2182      * optionally adds a new {@code Specification} instance to the platform
2183      * module.
2184      *
2185      * @param identifier the identifier to check.
2186      * @param add {@code true} to add a new {@code Specification} instance to
2187      * the platform module; {@code false} to not update the platform module.
2188      *
2189      * @return {@code true} if {@code identifier} is an identifier of a valid
2190      * platform specification; {@code false} else.
2191      */
2192     private boolean addPlatformSpecification( final String identifier,
2193                                               final boolean add )
2194     {
2195         if ( identifier == null )
2196         {
2197             throw new NullPointerException( "identifier" );
2198         }
2199 
2200         boolean validPlatformSpec = false;
2201 
2202         try
2203         {
2204             final Class platformClass = ClassLoaderFactory.loadClass(
2205                 this.getClass(), identifier );
2206 
2207             if ( Modifier.isPublic( platformClass.getModifiers() ) )
2208             {
2209                 if ( platformClass.getPackage() != null )
2210                 {
2211                     final String specVersion = platformClass.getPackage().
2212                         getSpecificationVersion();
2213 
2214                     String specVendor = platformClass.getPackage().
2215                         getSpecificationVendor();
2216 
2217                     if ( specVendor == null )
2218                     {
2219                         specVendor = DefaultModelBundle.getInstance().
2220                             getUnknownVendorMessage( Locale.getDefault() );
2221 
2222                     }
2223 
2224                     if ( specVersion != null )
2225                     {
2226                         validPlatformSpec = true;
2227 
2228                         if ( add )
2229                         {
2230                             // Add to the platform module.
2231                             try
2232                             {
2233                                 final Specification platformSpec =
2234                                     this.getSpecification( identifier,
2235                                                            specVersion );
2236 
2237                                 platformSpec.setModelVersion( MODEL_VERSION );
2238                                 platformSpec.setDocumentation(
2239                                     this.getPlatformModule().
2240                                     getDocumentation() );
2241 
2242                                 platformSpec.setIdentifier( identifier );
2243                                 platformSpec.setModuleName(
2244                                     this.getPlatformModule().getName() );
2245 
2246                                 platformSpec.setMultiplicity(
2247                                     Specification.MULTIPLICITY_MANY );
2248 
2249                                 platformSpec.setScope(
2250                                     Specification.SCOPE_MULTITON );
2251 
2252                                 platformSpec.setVendor( specVendor );
2253 
2254                                 final Specification[] platformSpecs =
2255                                     this.getPlatformModule().
2256                                     getSpecifications().getSpecifications();
2257 
2258                                 final Specification[] newPlatformSpecs =
2259                                     new Specification[ platformSpecs.length + 1 ];
2260 
2261                                 System.arraycopy( platformSpecs, 0,
2262                                                   newPlatformSpecs, 0,
2263                                                   platformSpecs.length );
2264 
2265                                 newPlatformSpecs[platformSpecs.length] =
2266                                     platformSpec;
2267 
2268                                 final Specifications specs =
2269                                     new Specifications();
2270 
2271                                 specs.setSpecifications( newPlatformSpecs );
2272                                 this.getPlatformModule().
2273                                     setSpecifications( specs );
2274 
2275                                 if ( LOGGER.isLoggable( Level.FINE ) )
2276                                 {
2277                                     LOGGER.log( Level.FINE,
2278                                                 DefaultModelBundle.getInstance().
2279                                         getAddedPlatformSpecificationMessage(
2280                                         Locale.getDefault(), identifier,
2281                                         specVersion,
2282                                         specVendor ) );
2283 
2284                                 }
2285 
2286                                 this.addDefaultImplementation( platformClass,
2287                                                                platformSpec );
2288 
2289                             }
2290                             catch ( final DuplicateSpecificationException e )
2291                             {
2292                                 // Specification already created.
2293                             }
2294                         }
2295                     }
2296                     else
2297                     {
2298                         LOGGER.log( Level.WARNING,
2299                                     DefaultModelBundle.getInstance().
2300                             getNoVersionAvailableMessage( Locale.getDefault(),
2301                                                           identifier ) );
2302 
2303                         validPlatformSpec = false;
2304                     }
2305                 }
2306                 else
2307                 {
2308                     LOGGER.log( Level.WARNING, DefaultModelBundle.getInstance().
2309                         getNoPackageAvailableMessage( Locale.getDefault(),
2310                                                       identifier ) );
2311 
2312                     validPlatformSpec = false;
2313                 }
2314             }
2315             else
2316             {
2317                 LOGGER.log( Level.WARNING, DefaultModelBundle.getInstance().
2318                     getNotPublicMessage( Locale.getDefault(), identifier ) );
2319 
2320                 validPlatformSpec = false;
2321             }
2322         }
2323         catch ( final ClassNotFoundException ex )
2324         {
2325             LOGGER.log( Level.WARNING, DefaultModelBundle.getInstance().
2326                 getClassNotFoundMessage( Locale.getDefault(), identifier ) );
2327 
2328             validPlatformSpec = false;
2329         }
2330 
2331         return validPlatformSpec;
2332     }
2333 
2334     private void addDefaultImplementation( final Class platformClass,
2335                                            final Specification platformSpec )
2336     {
2337         try
2338         {
2339             final Method accessor = platformClass.getDeclaredMethod(
2340                 "getDefault", new Class[ 0 ] );
2341 
2342             if ( Modifier.isStatic( accessor.getModifiers() ) &&
2343                  accessor.getReturnType() == platformClass )
2344             {
2345                 boolean overwritten = false;
2346 
2347                 // Check for an overwritten implementation.
2348                 for ( int i = this.modules.getImplementations().size() - 1;
2349                       i >= 0; i-- )
2350                 {
2351                     final Implementation resourceImpl =
2352                         this.modules.getImplementations().
2353                         getImplementation( i );
2354 
2355                     if ( !"default".equals( resourceImpl.getName() ) )
2356                     {
2357                         continue;
2358                     }
2359 
2360                     for ( int s = resourceImpl.getImplementedSpecifications().
2361                         size() - 1; s >= 0; s-- )
2362                     {
2363                         final Specification implemented =
2364                             resourceImpl.getImplementedSpecifications().
2365                             getSpecification( s );
2366 
2367                         if ( implemented.getIdentifier().equals(
2368                             platformSpec.getIdentifier() ) )
2369                         {
2370                             if ( LOGGER.isLoggable( Level.FINE ) )
2371                             {
2372                                 LOGGER.log( Level.FINE,
2373                                             DefaultModelBundle.getInstance().
2374                                     getOverwrittenDefaultImplementationMessage(
2375                                     Locale.getDefault(),
2376                                     platformSpec.getIdentifier(),
2377                                     platformSpec.getIdentifier(),
2378                                     resourceImpl.getIdentifier() ) );
2379 
2380                             }
2381 
2382                             overwritten = true;
2383                             break;
2384                         }
2385                     }
2386                 }
2387 
2388                 final String implVersion = platformClass.getPackage().
2389                     getImplementationVersion();
2390 
2391                 String implVendor = platformClass.getPackage().
2392                     getImplementationVendor();
2393 
2394                 if ( implVendor == null )
2395                 {
2396                     implVendor = DefaultModelBundle.getInstance().
2397                         getUnknownVendorMessage( Locale.getDefault() );
2398 
2399                 }
2400 
2401                 if ( implVersion != null && !overwritten )
2402                 {
2403                     final Implementation defaultImpl = this.getImplementation(
2404                         platformClass.getName() );
2405 
2406                     defaultImpl.setModelVersion( MODEL_VERSION );
2407                     defaultImpl.setVersion( implVersion );
2408                     defaultImpl.setVendor( implVendor );
2409                     defaultImpl.setDocumentation(
2410                         platformSpec.getDocumentation() );
2411 
2412                     defaultImpl.setFinal( true );
2413                     defaultImpl.setModuleName( PLATFORM_MODULE_NAME );
2414                     defaultImpl.setName( "default" );
2415 
2416                     final Specifications implemented = new Specifications();
2417                     implemented.setSpecifications( new Specification[]
2418                         {
2419                             platformSpec
2420                         } );
2421 
2422                     defaultImpl.setImplementedSpecifications( implemented );
2423 
2424                     final Implementation[] current = this.getPlatformModule().
2425                         getImplementations().getImplementations();
2426 
2427                     final Implementation[] tmp =
2428                         new Implementation[ current.length + 1 ];
2429 
2430                     System.arraycopy( current, 0, tmp, 0, current.length );
2431                     tmp[current.length] = defaultImpl;
2432 
2433                     final Implementations impls = new Implementations();
2434                     impls.setImplementations( tmp );
2435 
2436                     this.getPlatformModule().setImplementations( impls );
2437 
2438                     if ( LOGGER.isLoggable( Level.FINE ) )
2439                     {
2440                         LOGGER.log( Level.FINE, DefaultModelBundle.getInstance().
2441                             getAddedDefaultImplementationMessage(
2442                             Locale.getDefault(), defaultImpl.getIdentifier(),
2443                             platformSpec.getIdentifier(), implVersion,
2444                             implVendor ) );
2445 
2446                     }
2447 
2448                 }
2449             }
2450         }
2451         catch ( final NoSuchMethodException e )
2452         {
2453             // No static accessor.
2454         }
2455     }
2456 
2457     /**
2458      * Updates the value of a property.
2459      *
2460      * @param typeName the name of the type of {@code property}.
2461      * @param value the value of {@code property}.
2462      * @param property the property to update.
2463      */
2464     private void updatePropertyValue( final String typeName,
2465                                       final String value,
2466                                       final Property property )
2467     {
2468         final Class objectType;
2469 
2470         if ( typeName.equals( Boolean.TYPE.getName() ) )
2471         {
2472             property.setType( Boolean.TYPE );
2473             objectType = Boolean.class;
2474         }
2475         else if ( typeName.equals( Byte.TYPE.getName() ) )
2476         {
2477             property.setType( Byte.TYPE );
2478             objectType = Byte.class;
2479         }
2480         else if ( typeName.equals( Character.TYPE.getName() ) )
2481         {
2482             property.setType( Character.TYPE );
2483             objectType = Character.class;
2484         }
2485         else if ( typeName.equals( Double.TYPE.getName() ) )
2486         {
2487             property.setType( Double.TYPE );
2488             objectType = Double.class;
2489         }
2490         else if ( typeName.equals( Float.TYPE.getName() ) )
2491         {
2492             property.setType( Float.TYPE );
2493             objectType = Float.class;
2494         }
2495         else if ( typeName.equals( Integer.TYPE.getName() ) )
2496         {
2497             property.setType( Integer.TYPE );
2498             objectType = Integer.class;
2499         }
2500         else if ( typeName.equals( Long.TYPE.getName() ) )
2501         {
2502             property.setType( Long.TYPE );
2503             objectType = Long.class;
2504         }
2505         else if ( typeName.equals( Short.TYPE.getName() ) )
2506         {
2507             property.setType( Short.TYPE );
2508             objectType = Short.class;
2509         }
2510         else if ( typeName.equals( Boolean.class.getName() ) )
2511         {
2512             property.setType( Boolean.class );
2513             objectType = Boolean.class;
2514         }
2515         else if ( typeName.equals( Byte.class.getName() ) )
2516         {
2517             property.setType( Byte.class );
2518             objectType = Byte.class;
2519         }
2520         else if ( typeName.equals( Character.class.getName() ) )
2521         {
2522             property.setType( Character.class );
2523             objectType = Character.class;
2524         }
2525         else if ( typeName.equals( Double.class.getName() ) )
2526         {
2527             property.setType( Double.class );
2528             objectType = Double.class;
2529         }
2530         else if ( typeName.equals( Float.class.getName() ) )
2531         {
2532             property.setType( Float.class );
2533             objectType = Float.class;
2534         }
2535         else if ( typeName.equals( Integer.class.getName() ) )
2536         {
2537             property.setType( Integer.class );
2538             objectType = Integer.class;
2539         }
2540         else if ( typeName.equals( Long.class.getName() ) )
2541         {
2542             property.setType( Long.class );
2543             objectType = Long.class;
2544         }
2545         else if ( typeName.equals( Short.class.getName() ) )
2546         {
2547             property.setType( Short.class );
2548             objectType = Short.class;
2549         }
2550         else if ( typeName.equals( String.class.getName() ) )
2551         {
2552             property.setType( String.class );
2553             objectType = String.class;
2554         }
2555         else
2556         {
2557             throw new ModelError( DefaultModelBundle.getInstance().
2558                 getUnsupportedPropertyTypeMessage( Locale.getDefault(),
2559                                                    typeName ) );
2560 
2561         }
2562 
2563         if ( value != null )
2564         {
2565             try
2566             {
2567                 // Special handling for class Character which does not provide
2568                 // a constructor taking a string.
2569                 final Constructor ctor;
2570                 final Object arg;
2571 
2572                 if ( objectType == Character.class )
2573                 {
2574                     ctor = objectType.getDeclaredConstructor( CTOR_ARGS_CHAR );
2575                     arg = new Character( value.charAt( 0 ) );
2576                 }
2577                 else
2578                 {
2579                     ctor = objectType.getDeclaredConstructor( CTOR_ARGS_STRING );
2580                     arg = value;
2581                 }
2582 
2583                 property.setValue( ctor.newInstance( new Object[]
2584                     {
2585                         arg
2586                     } ) );
2587 
2588             }
2589             catch ( final SecurityException e )
2590             {
2591                 throw new ModelError( e );
2592             }
2593             catch ( final NoSuchMethodException e )
2594             {
2595                 throw new ModelError( e );
2596             }
2597             catch ( final InvocationTargetException e )
2598             {
2599                 final Throwable targetException = e.getTargetException();
2600 
2601                 if ( targetException instanceof Error )
2602                 {
2603                     throw (Error) targetException;
2604                 }
2605                 else if ( targetException instanceof RuntimeException )
2606                 {
2607                     throw (RuntimeException) targetException;
2608                 }
2609                 else
2610                 {
2611                     throw new ModelError( targetException == null
2612                                           ? e
2613                                           : targetException );
2614 
2615                 }
2616             }
2617             catch ( final IllegalAccessException e )
2618             {
2619                 throw new ModelError( e );
2620             }
2621             catch ( final InstantiationException e )
2622             {
2623                 throw new ModelError( e );
2624             }
2625         }
2626         else
2627         {
2628             property.setValue( value );
2629         }
2630     }
2631 
2632     //------------------------------------------------------------DefaultModel--
2633 }