001 /*
002 * Copyright (c) 2009 The JOMC Project
003 * Copyright (c) 2005 Christian Schulte <cs@jomc.org>
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 *
010 * o Redistributions of source code must retain the above copyright
011 * notice, this list of conditions and the following disclaimer.
012 *
013 * o Redistributions in binary form must reproduce the above copyright
014 * notice, this list of conditions and the following disclaimer in
015 * the documentation and/or other materials provided with the
016 * distribution.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
027 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
028 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 *
030 * $Id: DefaultModelManager.java 509 2009-09-21 13:54:49Z schulte2005 $
031 *
032 */
033 package org.jomc.model;
034
035 import java.io.IOException;
036 import java.io.InputStream;
037 import java.io.Reader;
038 import java.io.StringReader;
039 import java.io.StringWriter;
040 import java.lang.reflect.Constructor;
041 import java.lang.reflect.InvocationTargetException;
042 import java.lang.reflect.Method;
043 import java.lang.reflect.Modifier;
044 import java.net.URI;
045 import java.net.URISyntaxException;
046 import java.net.URL;
047 import java.text.MessageFormat;
048 import java.util.ArrayList;
049 import java.util.Enumeration;
050 import java.util.HashMap;
051 import java.util.HashSet;
052 import java.util.Iterator;
053 import java.util.LinkedList;
054 import java.util.List;
055 import java.util.Locale;
056 import java.util.Map;
057 import java.util.ResourceBundle;
058 import java.util.Set;
059 import java.util.jar.Attributes;
060 import java.util.jar.Manifest;
061 import java.util.logging.Level;
062 import javax.xml.XMLConstants;
063 import javax.xml.bind.JAXBContext;
064 import javax.xml.bind.JAXBElement;
065 import javax.xml.bind.JAXBException;
066 import javax.xml.bind.Marshaller;
067 import javax.xml.bind.Unmarshaller;
068 import javax.xml.bind.util.JAXBResult;
069 import javax.xml.bind.util.JAXBSource;
070 import javax.xml.transform.ErrorListener;
071 import javax.xml.transform.Source;
072 import javax.xml.transform.Transformer;
073 import javax.xml.transform.TransformerConfigurationException;
074 import javax.xml.transform.TransformerException;
075 import javax.xml.transform.TransformerFactory;
076 import javax.xml.transform.URIResolver;
077 import javax.xml.transform.sax.SAXSource;
078 import javax.xml.transform.stream.StreamSource;
079 import javax.xml.validation.SchemaFactory;
080 import javax.xml.validation.Validator;
081 import org.jomc.model.bootstrap.BootstrapObject;
082 import org.jomc.model.bootstrap.Schema;
083 import org.jomc.model.bootstrap.Schemas;
084 import org.jomc.util.ParseException;
085 import org.jomc.util.TokenMgrError;
086 import org.jomc.util.VersionParser;
087 import org.jomc.util.WeakIdentityHashMap;
088 import org.w3c.dom.ls.LSInput;
089 import org.w3c.dom.ls.LSResourceResolver;
090 import org.xml.sax.EntityResolver;
091 import org.xml.sax.InputSource;
092 import org.xml.sax.SAXException;
093
094 /**
095 * Default {@code ModelManager} implementation.
096 *
097 * <p><b>Classpath support</b><ul>
098 * <li>{@link #getClassLoader() }</li>
099 * <li>{@link #setClassLoader(java.lang.ClassLoader) }</li>
100 * <li>{@link #getDefaultDocumentLocation() }</li>
101 * <li>{@link #getClasspathModule(org.jomc.model.Modules) }</li>
102 * <li>{@link #getClasspathModules(java.lang.String) }</li>
103 * <li>{@link #getDefaultStylesheetLocation() }</li>
104 * <li>{@link #getClasspathTransformers(java.lang.String) }</li>
105 * </ul></p>
106 *
107 * <p><b>Logging</b><ul>
108 * <li>{@link #getListeners() }</li>
109 * <li>{@link #log(java.util.logging.Level, java.lang.String, java.lang.Throwable) }</li>
110 * </ul></p>
111 *
112 * <p><b>Model bootstrapping</b><ul>
113 * <li>{@link #getBootstrapContext() }</li>
114 * <li>{@link #getBootstrapDocumentLocation() }</li>
115 * <li>{@link #getBootstrapMarshaller(boolean, boolean) }</li>
116 * <li>{@link #getBootstrapObjectFactory() }</li>
117 * <li>{@link #getBootstrapSchema() }</li>
118 * <li>{@link #getBootstrapUnmarshaller(boolean) }</li>
119 * <li>{@link #validateBootstrapObject(javax.xml.bind.JAXBElement) }</li>
120 * <li>{@link #transformBootstrapObject(javax.xml.bind.JAXBElement, javax.xml.transform.Transformer) }</li>
121 * </ul></p>
122 *
123 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
124 * @version $Id: DefaultModelManager.java 509 2009-09-21 13:54:49Z schulte2005 $
125 */
126 public class DefaultModelManager implements ModelManager
127 {
128 // SECTION-START[ModelManager]
129
130 public ObjectFactory getObjectFactory()
131 {
132 if ( this.objectFactory == null )
133 {
134 this.objectFactory = new ObjectFactory();
135 }
136
137 return this.objectFactory;
138 }
139
140 public EntityResolver getEntityResolver()
141 {
142 if ( this.entityResolver == null )
143 {
144 this.entityResolver = new EntityResolver()
145 {
146
147 public InputSource resolveEntity( final String publicId, final String systemId )
148 throws SAXException, IOException
149 {
150 if ( systemId == null )
151 {
152 throw new NullPointerException( "systemId" );
153 }
154
155 InputSource schemaSource = null;
156
157 try
158 {
159 final Schema s = getSchemas().getSchema( publicId );
160 if ( s != null )
161 {
162 schemaSource = new InputSource();
163 schemaSource.setPublicId( publicId );
164
165 if ( s.getClasspathId() != null )
166 {
167 schemaSource.setSystemId( getClassLoader().getResource( s.getClasspathId() ).
168 toExternalForm() );
169
170 }
171 else
172 {
173 schemaSource.setSystemId( s.getSystemId() );
174 }
175 }
176
177 if ( schemaSource == null )
178 {
179 final URI systemUri = new URI( systemId );
180 String schemaName = systemUri.getPath();
181 if ( schemaName != null )
182 {
183 final int lastIndexOfSlash = schemaName.lastIndexOf( '/' );
184 if ( lastIndexOfSlash != -1 && lastIndexOfSlash < schemaName.length() )
185 {
186 schemaName = schemaName.substring( lastIndexOfSlash + 1 );
187 }
188
189 for ( URL url : getSchemaResources() )
190 {
191 if ( url.getPath().endsWith( schemaName ) )
192 {
193 schemaSource = new InputSource();
194 schemaSource.setPublicId( publicId );
195 schemaSource.setSystemId( url.toExternalForm() );
196
197 log( Level.FINE, getMessage( "resolvedSystemIdUri", new Object[]
198 {
199 systemUri.toASCIIString(),
200 schemaSource.getSystemId()
201 } ), null );
202
203 break;
204 }
205 }
206 }
207 else
208 {
209 log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
210 {
211 systemId, systemUri.toASCIIString()
212 } ), null );
213
214 schemaSource = null;
215 }
216 }
217 }
218 catch ( final URISyntaxException e )
219 {
220 log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
221 {
222 systemId, e.getMessage()
223 } ), null );
224
225 schemaSource = null;
226 }
227 catch ( final JAXBException e )
228 {
229 throw (IOException) new IOException( e.getMessage() ).initCause( e );
230 }
231
232 return schemaSource;
233 }
234
235 };
236 }
237
238 return this.entityResolver;
239 }
240
241 public LSResourceResolver getLSResourceResolver()
242 {
243 if ( this.resourceResolver == null )
244 {
245 this.resourceResolver = new LSResourceResolver()
246 {
247
248 public LSInput resolveResource( final String type, final String namespaceURI, final String publicId,
249 final String systemId, final String baseURI )
250 {
251 LSInput input = null;
252 try
253 {
254 final InputSource schemaSource = getEntityResolver().resolveEntity( publicId, systemId );
255
256 if ( schemaSource != null )
257 {
258 input = new LSInput()
259 {
260
261 public Reader getCharacterStream()
262 {
263 return schemaSource.getCharacterStream();
264 }
265
266 public void setCharacterStream( final Reader characterStream )
267 {
268 throw new UnsupportedOperationException();
269 }
270
271 public InputStream getByteStream()
272 {
273 return schemaSource.getByteStream();
274 }
275
276 public void setByteStream( final InputStream byteStream )
277 {
278 throw new UnsupportedOperationException();
279 }
280
281 public String getStringData()
282 {
283 return null;
284 }
285
286 public void setStringData( final String stringData )
287 {
288 throw new UnsupportedOperationException();
289 }
290
291 public String getSystemId()
292 {
293 return schemaSource.getSystemId();
294 }
295
296 public void setSystemId( final String systemId )
297 {
298 throw new UnsupportedOperationException();
299 }
300
301 public String getPublicId()
302 {
303 return schemaSource.getPublicId();
304 }
305
306 public void setPublicId( final String publicId )
307 {
308 throw new UnsupportedOperationException();
309 }
310
311 public String getBaseURI()
312 {
313 return null;
314 }
315
316 public void setBaseURI( final String baseURI )
317 {
318 throw new UnsupportedOperationException();
319 }
320
321 public String getEncoding()
322 {
323 return schemaSource.getEncoding();
324 }
325
326 public void setEncoding( final String encoding )
327 {
328 throw new UnsupportedOperationException();
329 }
330
331 public boolean getCertifiedText()
332 {
333 return false;
334 }
335
336 public void setCertifiedText( final boolean certifiedText )
337 {
338 throw new UnsupportedOperationException();
339 }
340
341 };
342 }
343
344 }
345 catch ( final SAXException e )
346 {
347 log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
348 {
349 systemId, e.getMessage()
350 } ), null );
351
352 input = null;
353 }
354 catch ( final IOException e )
355 {
356 log( Level.WARNING, getMessage( "unsupportedSystemIdUri", new Object[]
357 {
358 systemId, e.getMessage()
359 } ), null );
360
361 input = null;
362 }
363
364 return input;
365 }
366
367 };
368 }
369
370 return this.resourceResolver;
371 }
372
373 public javax.xml.validation.Schema getSchema() throws IOException, SAXException, JAXBException
374 {
375 if ( this.schema == null )
376 {
377 final SchemaFactory f = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
378 final List<Source> sources = new ArrayList<Source>( this.getSchemas().getSchema().size() );
379
380 for ( Schema s : this.getSchemas().getSchema() )
381 {
382 sources.add( new StreamSource( this.getClassLoader().getResourceAsStream( s.getClasspathId() ),
383 s.getSystemId() ) );
384
385 }
386
387 this.schema = f.newSchema( sources.toArray( new Source[ sources.size() ] ) );
388 }
389
390 return this.schema;
391 }
392
393 public JAXBContext getContext() throws IOException, SAXException, JAXBException
394 {
395 if ( this.context == null )
396 {
397 final StringBuilder pkgs = new StringBuilder();
398
399 for ( final Iterator<Schema> s = this.getSchemas().getSchema().iterator(); s.hasNext(); )
400 {
401 pkgs.append( s.next().getContextId() );
402 if ( s.hasNext() )
403 {
404 pkgs.append( ':' );
405 }
406 }
407
408 if ( pkgs.length() == 0 )
409 {
410 throw new IOException( this.getMessage( "missingSchemas", new Object[]
411 {
412 this.getBootstrapDocumentLocation()
413 } ) );
414
415 }
416
417 this.context = JAXBContext.newInstance( pkgs.toString(), this.getClassLoader() );
418 }
419
420 return this.context;
421 }
422
423 public Marshaller getMarshaller( final boolean validating, final boolean formattedOutput )
424 throws IOException, SAXException, JAXBException
425 {
426 final Marshaller m = this.getContext().createMarshaller();
427 final StringBuilder schemaLocation = new StringBuilder();
428
429 for ( final Iterator<Schema> it = this.getSchemas().getSchema().iterator(); it.hasNext(); )
430 {
431 final Schema s = it.next();
432 schemaLocation.append( s.getPublicId() ).append( ' ' ).append( s.getSystemId() );
433 if ( it.hasNext() )
434 {
435 schemaLocation.append( ' ' );
436 }
437 }
438
439 m.setProperty( Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation.toString() );
440 m.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );
441 m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.valueOf( formattedOutput ) );
442
443 if ( validating )
444 {
445 m.setSchema( this.getSchema() );
446 }
447
448 return m;
449 }
450
451 public Unmarshaller getUnmarshaller( final boolean validating ) throws IOException, SAXException, JAXBException
452 {
453 final Unmarshaller u = this.getContext().createUnmarshaller();
454
455 if ( validating )
456 {
457 u.setSchema( this.getSchema() );
458 }
459
460 return u;
461 }
462
463 public void validateModelObject( final JAXBElement<? extends ModelObject> modelObject )
464 throws ModelException, IOException, SAXException, JAXBException
465 {
466 if ( modelObject == null )
467 {
468 throw new NullPointerException( "modelObject" );
469 }
470
471 final StringWriter stringWriter = new StringWriter();
472 final Validator validator = this.getSchema().newValidator();
473 final ModelExceptionErrorHandler errorHandler = new ModelExceptionErrorHandler();
474 validator.setErrorHandler( errorHandler );
475 this.getMarshaller( false, false ).marshal( modelObject, stringWriter );
476
477 try
478 {
479 validator.validate( new StreamSource( new StringReader( stringWriter.toString() ) ) );
480 }
481 catch ( final SAXException e )
482 {
483 final ModelException modelException = new ModelException( e.getMessage(), e );
484 modelException.getDetails().addAll( errorHandler.getDetails() );
485 throw modelException;
486 }
487 }
488
489 public void validateModules( final Modules modules )
490 throws ModelException, IOException, SAXException, JAXBException
491 {
492 if ( modules == null )
493 {
494 throw new NullPointerException( "modules" );
495 }
496
497 this.validateModelObject( this.getObjectFactory().createModules( modules ) );
498 final List<ModelException.Detail> details = new LinkedList<ModelException.Detail>();
499
500 try
501 {
502 for ( Module m : modules.getModule() )
503 {
504 if ( m.getMessages() != null )
505 {
506 this.assertMessagesUniqueness( m.getMessages(), details );
507 }
508
509 if ( m.getProperties() != null )
510 {
511 this.assertPropertiesUniqueness( m.getProperties(), details );
512 }
513
514 if ( m.getImplementations() != null )
515 {
516 for ( Implementation i : m.getImplementations().getImplementation() )
517 {
518 if ( i.getMessages() != null )
519 {
520 this.assertMessagesUniqueness( i.getMessages(), details );
521 }
522
523 if ( i.getProperties() != null )
524 {
525 this.assertPropertiesUniqueness( i.getProperties(), details );
526 }
527
528 if ( i.getSpecifications() != null && !i.getSpecifications().getSpecification().isEmpty() )
529 {
530 for ( Specification s : i.getSpecifications().getSpecification() )
531 {
532 details.add( this.newImplementationSpecificationDeclarationConstraintDetail(
533 this.getObjectFactory().createImplementation( i ), i, s ) );
534
535 }
536 }
537
538 final Specifications specs = modules.getSpecifications( i.getIdentifier() );
539 final Dependencies deps = modules.getDependencies( i.getIdentifier() );
540
541 if ( specs != null )
542 {
543 for ( SpecificationReference r : specs.getReference() )
544 {
545 final Specification s = specs.getSpecification( r.getIdentifier() );
546
547 if ( s != null && r.getVersion() != null && s.getVersion() != null &&
548 VersionParser.compare( r.getVersion(), s.getVersion() ) != 0 )
549 {
550 final Module moduleOfSpecification =
551 modules.getModuleOfSpecification( s.getIdentifier() );
552
553 details.add( this.newIncompatibleImplementationDetail(
554 this.getObjectFactory().createImplementation( i ),
555 i.getIdentifier(), m.getName(),
556 r.getIdentifier(), moduleOfSpecification == null
557 ? "<>" : moduleOfSpecification.getName(),
558 r.getVersion(), s.getVersion() ) );
559
560 }
561 }
562 }
563
564 if ( deps != null )
565 {
566 for ( Dependency d : deps.getDependency() )
567 {
568 final Specification s = modules.getSpecification( d.getIdentifier() );
569
570 if ( s != null )
571 {
572 if ( s.getVersion() != null && d.getVersion() != null &&
573 VersionParser.compare( d.getVersion(), s.getVersion() ) > 0 )
574 {
575 final Module moduleOfSpecification =
576 modules.getModuleOfSpecification( s.getIdentifier() );
577
578 details.add( this.newIncompatibleDependencyDetail(
579 this.getObjectFactory().createDependency( d ),
580 i.getIdentifier(), m.getName(),
581 d.getIdentifier(), moduleOfSpecification == null
582 ? "<>" : moduleOfSpecification.getName(),
583 d.getVersion(), s.getVersion() ) );
584
585 }
586
587 if ( d.getProperties() != null )
588 {
589 this.assertPropertiesUniqueness( d.getProperties(), details );
590
591 if ( !d.getProperties().getReference().isEmpty() )
592 {
593 details.add( this.newDependencyPropertyReferenceConstraintDetail(
594 this.getObjectFactory().createDependency( d ), i, d ) );
595
596 }
597
598 if ( s.getScope() != null && !d.getProperties().getProperty().isEmpty() )
599 {
600 details.add( this.newPropertyOverwriteConstraintDetail(
601 this.getObjectFactory().createDependency( d ), i, d, s,
602 s.getScope() ) );
603
604 }
605 }
606 }
607
608 final Implementations available = modules.getImplementations( d.getIdentifier() );
609
610 if ( !d.isOptional() )
611 {
612 boolean missing = false;
613
614 if ( available == null )
615 {
616 missing = true;
617 }
618 else if ( available.getImplementation().isEmpty() )
619 {
620 missing = true;
621 }
622 else if ( d.getImplementationName() != null &&
623 available.getImplementationByName( d.getImplementationName() ) == null )
624 {
625 missing = true;
626 }
627
628 if ( missing )
629 {
630 details.add( this.newMandatoryDependencyConstraintDetail(
631 this.getObjectFactory().createDependency( d ), i.getIdentifier(),
632 d.getName() ) );
633
634 }
635 }
636 }
637 }
638
639 if ( i.getParent() != null )
640 {
641 final Implementation parent = modules.getImplementation( i.getParent() );
642 if ( parent != null && parent.isFinal() )
643 {
644 details.add( this.newInheritanceConstraintDetail(
645 this.getObjectFactory().createImplementation( i ), i, parent ) );
646
647 }
648 }
649 }
650 }
651
652 if ( m.getSpecifications() != null )
653 {
654 for ( SpecificationReference r : m.getSpecifications().getReference() )
655 {
656 details.add( this.newModuleSpecificationReferenceConstraintDetail(
657 this.getObjectFactory().createModule( m ), m, r ) );
658
659 }
660
661 for ( Specification s : m.getSpecifications().getSpecification() )
662 {
663 if ( s.getProperties() != null )
664 {
665 this.assertPropertiesUniqueness( s.getProperties(), details );
666 }
667
668 final Implementations impls = modules.getImplementations( s.getIdentifier() );
669
670 if ( impls != null )
671 {
672 final Map<String, Implementation> map = new HashMap<String, Implementation>();
673
674 for ( Implementation i : impls.getImplementation() )
675 {
676 if ( map.containsKey( i.getName() ) )
677 {
678 details.add( this.newImplementationNameConstraintDetail(
679 this.getObjectFactory().createSpecification( s ), s.getIdentifier(),
680 i.getIdentifier() + ", " + map.get( i.getName() ).getIdentifier(),
681 i.getName() ) );
682
683 }
684
685 map.put( i.getName(), i );
686 }
687
688 if ( s.getMultiplicity() == Multiplicity.ONE && impls.getImplementation().size() > 1 )
689 {
690 details.add( this.newMultiplicityConstraintDetail(
691 this.getObjectFactory().createSpecification( s ), impls.getImplementation().size(),
692 s.getIdentifier(), 1, s.getMultiplicity() ) );
693
694 }
695 }
696 }
697 }
698 }
699
700 if ( !details.isEmpty() )
701 {
702 final ModelException modelException = new ModelException( this.getMessage( "validationFailed", null ) );
703 modelException.getDetails().addAll( details );
704 throw modelException;
705 }
706 }
707 catch ( final TokenMgrError e )
708 {
709 throw new ModelException( e.getMessage(), e );
710 }
711 catch ( final ParseException e )
712 {
713 throw new ModelException( e.getMessage(), e );
714 }
715 }
716
717 public <T extends ModelObject> T transformModelObject(
718 final JAXBElement<T> modelObject, final Transformer transformer )
719 throws IOException, SAXException, JAXBException, TransformerException
720 {
721 if ( modelObject == null )
722 {
723 throw new NullPointerException( "modelObject" );
724 }
725 if ( transformer == null )
726 {
727 throw new NullPointerException( "transformer" );
728 }
729
730 final JAXBContext ctx = this.getContext();
731 final JAXBSource source = new JAXBSource( ctx, modelObject );
732 final JAXBResult result = new JAXBResult( ctx );
733 transformer.transform( source, result );
734 return ( (JAXBElement<T>) result.getResult() ).getValue();
735 }
736
737 public Instance getInstance( final Modules modules, final Implementation implementation, final ClassLoader cl )
738 {
739 if ( modules == null )
740 {
741 throw new NullPointerException( "modules" );
742 }
743 if ( implementation == null )
744 {
745 throw new NullPointerException( "implementation" );
746 }
747 if ( cl == null )
748 {
749 throw new NullPointerException( "classLoader" );
750 }
751
752 final Instance instance = new Instance();
753 instance.setIdentifier( implementation.getIdentifier() );
754 instance.setImplementationName( implementation.getName() );
755 instance.setClazz( implementation.getClazz() );
756 instance.setClassLoader( cl );
757 instance.setStateless( implementation.isStateless() );
758 instance.setDependencies( modules.getDependencies( implementation.getIdentifier() ) );
759 instance.setProperties( modules.getProperties( implementation.getIdentifier() ) );
760 instance.setMessages( modules.getMessages( implementation.getIdentifier() ) );
761 instance.setSpecifications( modules.getSpecifications( implementation.getIdentifier() ) );
762 return instance;
763 }
764
765 public Instance getInstance( final Modules modules, final Implementation implementation,
766 final Dependency dependency, final ClassLoader cl )
767 {
768 if ( modules == null )
769 {
770 throw new NullPointerException( "modules" );
771 }
772 if ( implementation == null )
773 {
774 throw new NullPointerException( "implementation" );
775 }
776 if ( dependency == null )
777 {
778 throw new NullPointerException( "dependency" );
779 }
780 if ( cl == null )
781 {
782 throw new NullPointerException( "cl" );
783 }
784
785 final Instance instance = this.getInstance( modules, implementation, cl );
786 final Specification dependencySpecification = modules.getSpecification( dependency.getIdentifier() );
787
788 if ( dependencySpecification != null && dependencySpecification.getScope() == null &&
789 dependency.getProperties() != null && !dependency.getProperties().getProperty().isEmpty() )
790 {
791 final Properties properties = new Properties();
792 properties.getProperty().addAll( dependency.getProperties().getProperty() );
793
794 if ( instance.getProperties() != null )
795 {
796 for ( Property p : instance.getProperties().getProperty() )
797 {
798 if ( properties.getProperty( p.getName() ) == null )
799 {
800 properties.getProperty().add( p );
801 }
802 }
803 }
804
805 instance.setProperties( properties );
806 }
807
808 return instance;
809 }
810
811 public Instance getInstance( final Modules modules, final Object object )
812 {
813 if ( modules == null )
814 {
815 throw new NullPointerException( "modules" );
816 }
817 if ( object == null )
818 {
819 throw new NullPointerException( "object" );
820 }
821
822 synchronized ( this.objects )
823 {
824 Instance instance = (Instance) this.objects.get( object );
825
826 if ( instance == null )
827 {
828 final Implementation i = this.getImplementation( modules, object );
829
830 if ( i != null )
831 {
832 ClassLoader cl = object.getClass().getClassLoader();
833 if ( cl == null )
834 {
835 cl = ClassLoader.getSystemClassLoader();
836 }
837
838 instance = this.getInstance( modules, i, cl );
839 if ( instance != null )
840 {
841 this.objects.put( object, instance );
842 }
843 }
844 }
845
846 return instance;
847 }
848 }
849
850 public Object getObject( final Modules modules, final Specification specification, final Instance instance )
851 throws InstantiationException
852 {
853 if ( modules == null )
854 {
855 throw new NullPointerException( "modules" );
856 }
857 if ( specification == null )
858 {
859 throw new NullPointerException( "specification" );
860 }
861 if ( instance == null )
862 {
863 throw new NullPointerException( "instance" );
864 }
865
866 Object object = null;
867
868 try
869 {
870 final Class specClass = Class.forName( specification.getClazz(), true, instance.getClassLoader() );
871 final Class clazz = Class.forName( instance.getClazz(), true, instance.getClassLoader() );
872
873 if ( Modifier.isPublic( clazz.getModifiers() ) )
874 {
875 Constructor ctor = null;
876
877 try
878 {
879 ctor = clazz.getConstructor( NO_CLASSES );
880 }
881 catch ( final NoSuchMethodException e )
882 {
883 this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
884 {
885 e.getMessage()
886 } ), null );
887
888 ctor = null;
889 }
890
891 if ( ctor != null && specClass.isAssignableFrom( clazz ) )
892 {
893 synchronized ( this.objects )
894 {
895 object = clazz.newInstance();
896 this.objects.put( object, instance );
897 }
898 }
899 else
900 {
901 final StringBuilder methodNames = new StringBuilder().append( '[' );
902 Method factoryMethod = null;
903 String methodName = null;
904
905 char[] c = instance.getImplementationName().toCharArray();
906 c[0] = Character.toUpperCase( c[0] );
907 methodName = "get" + String.valueOf( c );
908
909 boolean javaIdentifier = Character.isJavaIdentifierStart( c[0] );
910 if ( javaIdentifier )
911 {
912 for ( int idx = c.length - 1; idx > 0; idx-- )
913 {
914 if ( !Character.isJavaIdentifierPart( c[idx] ) )
915 {
916 javaIdentifier = false;
917 break;
918 }
919 }
920 }
921
922 if ( javaIdentifier )
923 {
924 methodNames.append( methodName );
925 factoryMethod = this.getFactoryMethod( clazz, methodName );
926 }
927
928 if ( factoryMethod == null )
929 {
930 methodName = specification.getIdentifier().substring(
931 specification.getIdentifier().lastIndexOf( '.' ) + 1 );
932
933 c = methodName.toCharArray();
934 c[0] = Character.toUpperCase( c[0] );
935
936 javaIdentifier = Character.isJavaIdentifierStart( c[0] );
937 if ( javaIdentifier )
938 {
939 for ( int idx = c.length - 1; idx > 0; idx-- )
940 {
941 if ( !Character.isJavaIdentifierPart( c[idx] ) )
942 {
943 javaIdentifier = false;
944 break;
945 }
946 }
947 }
948
949 if ( javaIdentifier )
950 {
951 methodName = "get" + String.valueOf( c );
952 methodNames.append( " " ).append( methodName );
953 factoryMethod = this.getFactoryMethod( clazz, methodName );
954 }
955 }
956
957 if ( factoryMethod == null )
958 {
959 methodName = "getObject";
960 methodNames.append( " " ).append( methodName );
961 factoryMethod = this.getFactoryMethod( clazz, methodName );
962 }
963
964 methodNames.append( ']' );
965
966 if ( factoryMethod == null )
967 {
968 throw new InstantiationException( this.getMessage( "missingFactoryMethod", new Object[]
969 {
970 clazz.getName(), instance.getIdentifier(), methodNames.toString()
971 } ) );
972
973 }
974
975 if ( Modifier.isStatic( factoryMethod.getModifiers() ) )
976 {
977 object = factoryMethod.invoke( null, NO_OBJECTS );
978 }
979 else if ( ctor != null )
980 {
981 synchronized ( this.objects )
982 {
983 object = ctor.newInstance();
984 this.objects.put( object, instance );
985 object = factoryMethod.invoke( object, NO_OBJECTS );
986 this.objects.put( object, instance );
987 }
988 }
989 else
990 {
991 throw new InstantiationException( this.getMessage( "missingFactoryMethod", new Object[]
992 {
993 clazz.getName(), instance.getIdentifier(), methodNames.toString()
994 } ) );
995
996 }
997 }
998 }
999
1000 return object;
1001 }
1002 catch ( final InvocationTargetException e )
1003 {
1004 throw (InstantiationException) new InstantiationException().initCause(
1005 e.getTargetException() != null ? e.getTargetException() : e );
1006
1007 }
1008 catch ( final IllegalAccessException e )
1009 {
1010 throw (InstantiationException) new InstantiationException().initCause( e );
1011 }
1012 catch ( final ClassNotFoundException e )
1013 {
1014 throw (InstantiationException) new InstantiationException().initCause( e );
1015 }
1016 }
1017
1018 // SECTION-END
1019 // SECTION-START[DefaultModelManager]
1020 /** Listener interface. */
1021 public interface Listener
1022 {
1023
1024 /**
1025 * Get called on logging.
1026 *
1027 * @param level The level of the event.
1028 * @param message The message of the event or {@code null}.
1029 * @param t The throwable of the event or {@code null}.
1030 */
1031 void onLog( Level level, String message, Throwable t );
1032
1033 }
1034
1035 /**
1036 * Constant for the name of the classpath module.
1037 * @see #getClasspathModuleName()
1038 */
1039 private static final String DEFAULT_CLASSPATH_MODULE_NAME = "Java Classpath";
1040
1041 /**
1042 * Classpath location searched for documents by default.
1043 * @see #getDefaultDocumentLocation()
1044 */
1045 private static final String DEFAULT_DOCUMENT_LOCATION = "META-INF/jomc.xml";
1046
1047 /**
1048 * Classpath location searched for style sheets by default.
1049 * @see #getDefaultStylesheetLocation()
1050 */
1051 private static final String DEFAULT_STYLESHEET_LOCATION = "META-INF/jomc.xslt";
1052
1053 /** Classpath location of the bootstrap schema. */
1054 private static final String BOOTSTRAP_SCHEMA_LOCATION =
1055 Schemas.class.getPackage().getName().replace( '.', '/' ) + "/jomc-bootstrap-1.0.xsd";
1056
1057 /**
1058 * Classpath location searched for bootstrap documents by default.
1059 * @see #getBootstrapDocumentLocation()
1060 */
1061 private static final String DEFAULT_BOOTSTRAP_DOCUMENT_LOCATION = "META-INF/jomc-bootstrap.xml";
1062
1063 /** JAXB context of the bootstrap schema. */
1064 private static final String BOOTSTRAP_CONTEXT = Schemas.class.getPackage().getName();
1065
1066 /** Supported schema name extensions. */
1067 private static final String[] SCHEMA_EXTENSIONS = new String[]
1068 {
1069 "xsd"
1070 };
1071
1072 /** Empty {@code Class} array. */
1073 private static final Class[] NO_CLASSES =
1074 {
1075 };
1076
1077 /** Empty {@code Object} array. */
1078 private static final Object[] NO_OBJECTS =
1079 {
1080 };
1081
1082 /** Class loader of the instance. */
1083 private ClassLoader classLoader;
1084
1085 /** The entity resolver of the instance. */
1086 private EntityResolver entityResolver;
1087
1088 /** The L/S resolver of the instance. */
1089 private LSResourceResolver resourceResolver;
1090
1091 /** The context of the instance. */
1092 private JAXBContext context;
1093
1094 /** The schema of the instance. */
1095 private javax.xml.validation.Schema schema;
1096
1097 /** The bootstrap schema. */
1098 private javax.xml.validation.Schema bootstrapSchema;
1099
1100 /** URLs of all available classpath schema resources. */
1101 private Set<URL> schemaResources;
1102
1103 /** Schemas of the instance. */
1104 private Schemas schemas;
1105
1106 /** Object factory of the instance. */
1107 private ObjectFactory objectFactory;
1108
1109 /** Bootstrap object factory of the instance. */
1110 private org.jomc.model.bootstrap.ObjectFactory bootstrapObjectFactory;
1111
1112 /** The listeners of the instance. */
1113 private List<Listener> listeners;
1114
1115 /** Maps objects to {@code Instance}s. */
1116 private final Map objects = new WeakIdentityHashMap( 1024 );
1117
1118 /** Creates a new {@code DefaultModelManager} instance. */
1119 public DefaultModelManager()
1120 {
1121 super();
1122 }
1123
1124 /**
1125 * Gets the bootstrap object factory of the instance.
1126 *
1127 * @return The bootstrap object factory of the instance.
1128 */
1129 public org.jomc.model.bootstrap.ObjectFactory getBootstrapObjectFactory()
1130 {
1131 if ( this.bootstrapObjectFactory == null )
1132 {
1133 this.bootstrapObjectFactory = new org.jomc.model.bootstrap.ObjectFactory();
1134 }
1135
1136 return this.bootstrapObjectFactory;
1137 }
1138
1139 /**
1140 * Gets a new bootstrap context instance.
1141 *
1142 * @return A new bootstrap context instance.
1143 *
1144 * @throws JAXBException if creating a new bootstrap context instance fails.
1145 */
1146 public JAXBContext getBootstrapContext() throws JAXBException
1147 {
1148 return JAXBContext.newInstance( BOOTSTRAP_CONTEXT, this.getClassLoader() );
1149 }
1150
1151 /**
1152 * Gets a new bootstrap {@code Marshaller}.
1153 *
1154 * @param validating {@code true} for a marshaller with additional schema validation support enabled; {@code false}
1155 * for a marshaller without additional schema validation support enabled.
1156 * @param formattedOutput {@code true} for the marshaller to produce formatted output; {@code false} for the
1157 * marshaller to not apply any formatting when marshalling.
1158 *
1159 * @return A new bootstrap {@code Marshaller}.
1160 *
1161 * @throws IOException if reading schema resources fails.
1162 * @throws SAXException if parsing schema resources fails.
1163 * @throws JAXBException if unmarshalling schema resources fails.
1164 */
1165 public Marshaller getBootstrapMarshaller( final boolean validating, final boolean formattedOutput )
1166 throws IOException, SAXException, JAXBException
1167 {
1168 final Marshaller m = this.getBootstrapContext().createMarshaller();
1169 m.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );
1170 m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.valueOf( formattedOutput ) );
1171
1172 if ( validating )
1173 {
1174 m.setSchema( this.getBootstrapSchema() );
1175 }
1176
1177 return m;
1178 }
1179
1180 /**
1181 * Gets a new bootstrap {@code Unmarshaller}.
1182 *
1183 * @param validating {@code true} for an unmarshaller with additional schema validation support enabled;
1184 * {@code false} for an unmarshaller without additional schema validation support enabled.
1185 *
1186 * @return A new bootstrap {@code Unmarshaller}.
1187 *
1188 * @throws IOException if reading schema resources fails.
1189 * @throws SAXException if parsing schema resources fails.
1190 * @throws JAXBException if unmarshalling schema resources fails.
1191 */
1192 public Unmarshaller getBootstrapUnmarshaller( final boolean validating )
1193 throws IOException, SAXException, JAXBException
1194 {
1195 final Unmarshaller u = this.getBootstrapContext().createUnmarshaller();
1196 if ( validating )
1197 {
1198 u.setSchema( this.getBootstrapSchema() );
1199 }
1200
1201 return u;
1202 }
1203
1204 /**
1205 * Gets the bootstrap schema.
1206 *
1207 * @return The bootstrap schema.
1208 *
1209 * @throws SAXException if parsing the bootstrap schema fails.
1210 */
1211 public javax.xml.validation.Schema getBootstrapSchema() throws SAXException
1212 {
1213 if ( this.bootstrapSchema == null )
1214 {
1215 final URL url = this.getClassLoader().getResource( BOOTSTRAP_SCHEMA_LOCATION );
1216 this.log( Level.FINE, this.getMessage( "processing", new Object[]
1217 {
1218 url.toExternalForm()
1219 } ), null );
1220
1221 this.bootstrapSchema = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI ).newSchema( url );
1222 }
1223
1224 return this.bootstrapSchema;
1225 }
1226
1227 /**
1228 * Validates a given bootstrap object.
1229 *
1230 * @param bootstrapObject The object to validate.
1231 *
1232 * @throws NullPointerException if {@code bootstrapObject} is {@code null}.
1233 * @throws ModelException if {@code bootstrapObject} is invalid.
1234 * @throws IOException if reading schema resources fails.
1235 * @throws SAXException if parsing schema resources fails.
1236 * @throws JAXBException if unmarshalling schema resources fails.
1237 */
1238 public void validateBootstrapObject( final JAXBElement<? extends BootstrapObject> bootstrapObject )
1239 throws ModelException, IOException, SAXException, JAXBException
1240 {
1241 if ( bootstrapObject == null )
1242 {
1243 throw new NullPointerException( "bootstrapObject" );
1244 }
1245
1246 final StringWriter stringWriter = new StringWriter();
1247 final Validator validator = this.getBootstrapSchema().newValidator();
1248 final ModelExceptionErrorHandler errorHandler = new ModelExceptionErrorHandler();
1249 validator.setErrorHandler( errorHandler );
1250 this.getBootstrapMarshaller( false, false ).marshal( bootstrapObject, stringWriter );
1251
1252 try
1253 {
1254 validator.validate( new StreamSource( new StringReader( stringWriter.toString() ) ) );
1255 }
1256 catch ( final SAXException e )
1257 {
1258 final ModelException modelException = new ModelException( e.getMessage(), e );
1259 modelException.getDetails().addAll( errorHandler.getDetails() );
1260 throw modelException;
1261 }
1262 }
1263
1264 /**
1265 * Transforms a given {@code BootstrapObject} with a given {@code Transformer}.
1266 *
1267 * @param bootstrapObject The {@code BootstrapObject} to transform.
1268 * @param transformer The {@code Transformer} to transform {@code bootstrapObject} with.
1269 * @param <T> The type of {@code bootstrapObject}.
1270 *
1271 * @return {@code bootstrapObject} transformed with {@code transformer}.
1272 *
1273 * @throws NullPointerException if {@code bootstrapObject} or {@code transformer} is {@code null}.
1274 * @throws IOException if reading schema resources fails.
1275 * @throws SAXException if parsing schema resources fails.
1276 * @throws JAXBException if binding fails.
1277 * @throws TransformerException if the transformation fails.
1278 */
1279 public <T extends BootstrapObject> T transformBootstrapObject(
1280 final JAXBElement<T> bootstrapObject, final Transformer transformer )
1281 throws IOException, SAXException, JAXBException, TransformerException
1282 {
1283 if ( bootstrapObject == null )
1284 {
1285 throw new NullPointerException( "bootstrapObject" );
1286 }
1287 if ( transformer == null )
1288 {
1289 throw new NullPointerException( "transformer" );
1290 }
1291
1292 final JAXBContext ctx = this.getBootstrapContext();
1293 final JAXBSource source = new JAXBSource( ctx, bootstrapObject );
1294 final JAXBResult result = new JAXBResult( ctx );
1295 transformer.transform( source, result );
1296 return ( (JAXBElement<T>) result.getResult() ).getValue();
1297 }
1298
1299 /**
1300 * Sets the object factory of the instance.
1301 *
1302 * @param value The new object factory of the instance or {@code null}.
1303 *
1304 * @see #getObjectFactory()
1305 */
1306 public void setObjectFactory( final ObjectFactory value )
1307 {
1308 this.objectFactory = value;
1309 }
1310
1311 /**
1312 * Sets the entity resolver of the instance.
1313 *
1314 * @param value The new entity resolver of the instance or {@code null}.
1315 *
1316 * @see #getEntityResolver()
1317 */
1318 public void setEntityResolver( final EntityResolver value )
1319 {
1320 this.entityResolver = value;
1321 }
1322
1323 /**
1324 * Sets the L/S resolver of the instance.
1325 *
1326 * @param value The new L/S resolver of the instance or {@code null}.
1327 *
1328 * @see #getLSResourceResolver()
1329 */
1330 public void setLSResourceResolver( final LSResourceResolver value )
1331 {
1332 this.resourceResolver = value;
1333 }
1334
1335 /**
1336 * Sets the JAXB context of the instance.
1337 *
1338 * @param value The new JAXB context of the instance or {@code null}.
1339 *
1340 * @see #getContext()
1341 */
1342 public void setContext( final JAXBContext value )
1343 {
1344 this.context = value;
1345 }
1346
1347 /**
1348 * Sets the schema of the instance.
1349 *
1350 * @param value The new schema of the instance or {@code null}.
1351 *
1352 * @see #getSchema()
1353 */
1354 public void setSchema( final javax.xml.validation.Schema value )
1355 {
1356 this.schema = value;
1357 }
1358
1359 /**
1360 * Gets the list of registered listeners.
1361 *
1362 * @return The list of registered listeners.
1363 *
1364 * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
1365 */
1366 public List<Listener> getListeners()
1367 {
1368 if ( this.listeners == null )
1369 {
1370 this.listeners = new LinkedList<Listener>();
1371 }
1372
1373 return this.listeners;
1374 }
1375
1376 /**
1377 * Gets the location to search for bootstrap documents.
1378 * <p>The bootstrap document location is controlled by system property
1379 * {@code org.jomc.model.DefaultModelManager.bootstrapDocumentLocation} holding the location to search at. If that
1380 * property is not set, the {@code META-INF/jomc-bootstrap.xml} default is returned.</p>
1381 *
1382 * @return The location to search for bootstrap documents.
1383 *
1384 * @see #getSchemas()
1385 */
1386 public String getBootstrapDocumentLocation()
1387 {
1388 return System.getProperty( "org.jomc.model.DefaultModelManager.bootstrapDocumentLocation",
1389 DEFAULT_BOOTSTRAP_DOCUMENT_LOCATION );
1390
1391 }
1392
1393 /**
1394 * Gets the schemas backing the instance.
1395 *
1396 * @return The schemas backing the instance.
1397 *
1398 * @throws IOException if reading schema resources fails.
1399 * @throws SAXException if parsing schema resources fails.
1400 * @throws JAXBException if unmarshalling schema resources fails.
1401 *
1402 * @see #getBootstrapDocumentLocation()
1403 */
1404 public Schemas getSchemas() throws IOException, JAXBException, SAXException
1405 {
1406 if ( this.schemas == null )
1407 {
1408 this.schemas = new Schemas();
1409
1410 final JAXBContext ctx = JAXBContext.newInstance( BOOTSTRAP_CONTEXT, this.getClassLoader() );
1411 final Unmarshaller u = ctx.createUnmarshaller();
1412 final String bootstrapLocation = this.getBootstrapDocumentLocation();
1413 this.log( Level.FINE, this.getMessage( "bootstrapLocation", new Object[]
1414 {
1415 bootstrapLocation
1416 } ), null );
1417
1418 final Enumeration<URL> e = this.getClassLoader().getResources( bootstrapLocation );
1419 u.setSchema( this.getBootstrapSchema() );
1420
1421 while ( e.hasMoreElements() )
1422 {
1423 final URL url = e.nextElement();
1424 this.log( Level.FINE, this.getMessage( "processing", new Object[]
1425 {
1426 url.toExternalForm()
1427 } ), null );
1428
1429 Object content = u.unmarshal( url );
1430 if ( content instanceof JAXBElement )
1431 {
1432 content = ( (JAXBElement) content ).getValue();
1433 }
1434
1435 if ( content instanceof Schema )
1436 {
1437 final Schema s = (Schema) content;
1438 this.log( Level.FINE, this.getMessage( "addingSchema", new Object[]
1439 {
1440 s.getPublicId(), s.getSystemId(), s.getContextId(), s.getClasspathId()
1441 } ), null );
1442
1443 this.schemas.getSchema().add( s );
1444 }
1445 else if ( content instanceof Schemas )
1446 {
1447 for ( Schema s : ( (Schemas) content ).getSchema() )
1448 {
1449 this.log( Level.FINE, this.getMessage( "addingSchema", new Object[]
1450 {
1451 s.getPublicId(), s.getSystemId(), s.getContextId(), s.getClasspathId()
1452 } ), null );
1453
1454 this.schemas.getSchema().add( s );
1455 }
1456 }
1457 }
1458 }
1459
1460 return this.schemas;
1461 }
1462
1463 /**
1464 * Gets the default location to search for documents.
1465 * <p>The default document location is controlled by system property
1466 * {@code org.jomc.model.DefaultModelManager.defaultDocumentLocation} holding the location to search at by default.
1467 * If that property is not set, the {@code META-INF/jomc.xml} default is returned.</p>
1468 *
1469 * @return The default location to search for documents.
1470 *
1471 * @see #getClasspathModules(java.lang.String)
1472 */
1473 public String getDefaultDocumentLocation()
1474 {
1475 return System.getProperty( "org.jomc.model.DefaultModelManager.defaultDocumentLocation",
1476 DEFAULT_DOCUMENT_LOCATION );
1477
1478 }
1479
1480 /**
1481 * Gets modules by searching the class loader of the instance for resources.
1482 * <p><b>Note:</b><br/>
1483 * This method does not validate the modules.</p>
1484 *
1485 * @param location The location to search at.
1486 *
1487 * @return All resources from the class loader of the instance matching {@code location}.
1488 *
1489 * @throws NullPointerException if {@code location} is {@code null}.
1490 * @throws IOException if reading resources fails.
1491 * @throws SAXException if parsing schema resources fails.
1492 * @throws JAXBException if unmarshalling schema resources fails.
1493 *
1494 * @see #getDefaultDocumentLocation()
1495 */
1496 public Modules getClasspathModules( final String location ) throws IOException, SAXException, JAXBException
1497 {
1498 if ( location == null )
1499 {
1500 throw new NullPointerException( "location" );
1501 }
1502
1503 this.log( Level.FINE, this.getMessage( "documentLocation", new Object[]
1504 {
1505 location
1506 } ), null );
1507
1508 final long t0 = System.currentTimeMillis();
1509 final Text text = new Text();
1510 text.setLanguage( "en" );
1511 text.setValue( this.getMessage( "classpathModulesInfo", new Object[]
1512 {
1513 location
1514 } ) );
1515
1516 final Modules mods = new Modules();
1517 mods.setDocumentation( new Texts() );
1518 mods.getDocumentation().setDefaultLanguage( "en" );
1519 mods.getDocumentation().getText().add( text );
1520
1521 final Unmarshaller u = this.getUnmarshaller( false );
1522 final Enumeration<URL> resources = this.getClassLoader().getResources( location );
1523
1524 Integer count = 0;
1525 while ( resources.hasMoreElements() )
1526 {
1527 count++;
1528 final URL url = resources.nextElement();
1529
1530 this.log( Level.FINE, this.getMessage( "processing", new Object[]
1531 {
1532 url.toExternalForm()
1533 } ), null );
1534
1535 Object content = u.unmarshal( url );
1536 if ( content instanceof JAXBElement )
1537 {
1538 content = ( (JAXBElement) content ).getValue();
1539 }
1540
1541 if ( content instanceof Module )
1542 {
1543 mods.getModule().add( (Module) content );
1544 }
1545 else
1546 {
1547 this.log( Level.WARNING, this.getMessage( "ignoringDocument", new Object[]
1548 {
1549 content == null ? "<>" : content.toString(), url.toExternalForm()
1550 } ), null );
1551
1552 }
1553 }
1554
1555 this.log( Level.FINE, this.getMessage( "classpathReport", new Object[]
1556 {
1557 count, Long.valueOf( System.currentTimeMillis() - t0 )
1558 } ), null );
1559
1560 return mods;
1561 }
1562
1563 /**
1564 * Gets the classpath module name.
1565 * <p>The classpath module name is controlled by system property
1566 * {@code org.jomc.model.DefaultModelManager.classpathModuleName} holding the classpath module name.
1567 * If that property is not set, the {@code Java Classpath} default is returned.</p>
1568 *
1569 * @return The name of the classpath module.
1570 *
1571 * @see #getClasspathModule(org.jomc.model.Modules)
1572 */
1573 public String getClasspathModuleName()
1574 {
1575 return System.getProperty( "org.jomc.model.DefaultModelManager.classpathModuleName",
1576 DEFAULT_CLASSPATH_MODULE_NAME );
1577
1578 }
1579
1580 /**
1581 * Gets a module holding model objects resolved by inspecting the class loader of the instance.
1582 * <p>This method searches the given modules for unresolved references and tries to resolve each unresolved
1583 * reference by inspecting the class loader of the instance.</p>
1584 *
1585 * @param modules The modules to resolve by inspecting the class loader of the instance.
1586 *
1587 * @return A module holding model objects resolved by inspecting the class loader of the instance or {@code null} if
1588 * nothing could be resolved.
1589 *
1590 * @see #getClasspathModuleName()
1591 */
1592 public Module getClasspathModule( final Modules modules )
1593 {
1594 final Module module = new Module();
1595 module.setVersion( System.getProperty( "java.specification.version" ) );
1596 module.setName( this.getClasspathModuleName() );
1597
1598 this.resolveClasspath( modules, module );
1599
1600 final boolean resolved = ( module.getSpecifications() != null &&
1601 !module.getSpecifications().getSpecification().isEmpty() ) ||
1602 ( module.getImplementations() != null &&
1603 !module.getImplementations().getImplementation().isEmpty() );
1604
1605 return resolved ? module : null;
1606 }
1607
1608 /**
1609 * Gets the default location to search for style sheets.
1610 * <p>The default style sheet location is controlled by system property
1611 * {@code org.jomc.model.DefaultModelManager.defaultStylesheetLocation} holding the location to search at by
1612 * default. If that property is not set, the {@code META-INF/jomc.xslt} default is returned.</p>
1613 *
1614 * @return The default location to search for style sheets.
1615 *
1616 * @see #getClasspathTransformers(java.lang.String)
1617 */
1618 public String getDefaultStylesheetLocation()
1619 {
1620 return System.getProperty( "org.jomc.model.DefaultModelManager.defaultStylesheetLocation",
1621 DEFAULT_STYLESHEET_LOCATION );
1622
1623 }
1624
1625 /**
1626 * Gets transformers by searching the class loader of the instance for resources.
1627 *
1628 * @param location The location to search at.
1629 *
1630 * @return All resources from the class loader of the instance matching {@code location}.
1631 *
1632 * @throws NullPointerException if {@code location} is {@code null}.
1633 * @throws IOException if reading resources fails.
1634 * @throws TransformerConfigurationException if getting the transformers fails.
1635 *
1636 * @see #getDefaultStylesheetLocation()
1637 */
1638 public List<Transformer> getClasspathTransformers( final String location )
1639 throws IOException, TransformerConfigurationException
1640 {
1641 if ( location == null )
1642 {
1643 throw new NullPointerException( "location" );
1644 }
1645
1646 this.log( Level.FINE, this.getMessage( "stylesheetLocation", new Object[]
1647 {
1648 location
1649 } ), null );
1650
1651 final long t0 = System.currentTimeMillis();
1652 final List<Transformer> transformers = new LinkedList<Transformer>();
1653 final TransformerFactory transformerFactory = TransformerFactory.newInstance();
1654 final Enumeration<URL> resources = this.getClassLoader().getResources( location );
1655 final ErrorListener errorListener = new ErrorListener()
1656 {
1657
1658 public void warning( final TransformerException exception ) throws TransformerException
1659 {
1660 log( Level.WARNING, exception.getMessage(), exception );
1661 }
1662
1663 public void error( final TransformerException exception ) throws TransformerException
1664 {
1665 log( Level.SEVERE, exception.getMessage(), exception );
1666 throw exception;
1667 }
1668
1669 public void fatalError( final TransformerException exception ) throws TransformerException
1670 {
1671 log( Level.SEVERE, exception.getMessage(), exception );
1672 throw exception;
1673 }
1674
1675 };
1676
1677 final URIResolver uriResolver = new URIResolver()
1678 {
1679
1680 public Source resolve( final String href, final String base ) throws TransformerException
1681 {
1682 try
1683 {
1684 Source source = null;
1685 final InputSource inputSource = getEntityResolver().resolveEntity( null, href );
1686
1687 if ( inputSource != null )
1688 {
1689 source = new SAXSource( inputSource );
1690 }
1691
1692 return source;
1693 }
1694 catch ( final SAXException e )
1695 {
1696 log( Level.SEVERE, e.getMessage(), e );
1697 throw new TransformerException( e );
1698 }
1699 catch ( final IOException e )
1700 {
1701 log( Level.SEVERE, e.getMessage(), e );
1702 throw new TransformerException( e );
1703 }
1704 }
1705
1706 };
1707
1708 transformerFactory.setErrorListener( errorListener );
1709 transformerFactory.setURIResolver( uriResolver );
1710
1711 Integer count = 0;
1712 while ( resources.hasMoreElements() )
1713 {
1714 count++;
1715 final URL url = resources.nextElement();
1716
1717 this.log( Level.FINE, this.getMessage( "processing", new Object[]
1718 {
1719 url.toExternalForm()
1720 } ), null );
1721
1722 final InputStream in = url.openStream();
1723 final Transformer transformer = transformerFactory.newTransformer( new StreamSource( in ) );
1724 in.close();
1725
1726 transformer.setErrorListener( errorListener );
1727 transformer.setURIResolver( uriResolver );
1728 transformers.add( transformer );
1729 }
1730
1731 this.log( Level.FINE, this.getMessage( "classpathReport", new Object[]
1732 {
1733 count, Long.valueOf( System.currentTimeMillis() - t0 )
1734 } ), null );
1735
1736 return transformers;
1737 }
1738
1739 /**
1740 * Gets the class loader of the instance.
1741 *
1742 * @return The class loader of the instance.
1743 *
1744 * @see #setClassLoader(java.lang.ClassLoader)
1745 */
1746 public ClassLoader getClassLoader()
1747 {
1748 if ( this.classLoader == null )
1749 {
1750 this.classLoader = this.getClass().getClassLoader();
1751 if ( this.classLoader == null )
1752 {
1753 this.classLoader = ClassLoader.getSystemClassLoader();
1754 }
1755
1756 }
1757
1758 return this.classLoader;
1759 }
1760
1761 /**
1762 * Sets the class loader of the instance.
1763 *
1764 * @param value The new class loader of the instance.
1765 *
1766 * @see #getClassLoader()
1767 */
1768 public void setClassLoader( final ClassLoader value )
1769 {
1770 this.classLoader = value;
1771 this.bootstrapSchema = null;
1772 this.schema = null;
1773 this.schemas = null;
1774 this.schemaResources = null;
1775 this.entityResolver = null;
1776 this.resourceResolver = null;
1777 this.context = null;
1778 }
1779
1780 /**
1781 * Notifies registered listeners.
1782 *
1783 * @param level The level of the event.
1784 * @param message The message of the event or {@code null}.
1785 * @param throwable The throwable of the event {@code null}.
1786 *
1787 * @see #getListeners()
1788 */
1789 protected void log( final Level level, final String message, final Throwable throwable )
1790 {
1791 for ( Listener l : this.getListeners() )
1792 {
1793 l.onLog( level, message, throwable );
1794 }
1795 }
1796
1797 /**
1798 * Resolves references by inspecting the class loader of the instance.
1799 *
1800 * @param modules The modules to resolve.
1801 * @param cpModule The module for resolved references.
1802 *
1803 * @throws NullPointerException if {@code cpModule} is {@code null}.
1804 */
1805 private void resolveClasspath( final Modules modules, final Module cpModule )
1806 {
1807 for ( Module m : modules.getModule() )
1808 {
1809 if ( m.getSpecifications() != null )
1810 {
1811 this.resolveClasspath( modules, m.getSpecifications(), cpModule );
1812 }
1813
1814 if ( m.getImplementations() != null )
1815 {
1816 this.resolveClasspath( modules, m.getImplementations(), cpModule );
1817 }
1818
1819 }
1820 }
1821
1822 private void resolveClasspath( final Modules modules, final SpecificationReference ref, final Module cpModule )
1823 {
1824 if ( modules.getSpecification( ref.getIdentifier() ) == null )
1825 {
1826 this.resolveClasspath( ref.getIdentifier(), cpModule );
1827 }
1828 }
1829
1830 private void resolveClasspath( final Modules modules, final Specifications references, final Module cpModule )
1831 {
1832 for ( SpecificationReference ref : references.getReference() )
1833 {
1834 this.resolveClasspath( modules, ref, cpModule );
1835 }
1836
1837 }
1838
1839 private void resolveClasspath( final Modules modules, final Implementations implementations, final Module cpModule )
1840 {
1841 for ( Implementation implementation : implementations.getImplementation() )
1842 {
1843 if ( implementation.getSpecifications() != null )
1844 {
1845 this.resolveClasspath( modules, implementation.getSpecifications(), cpModule );
1846 }
1847
1848 if ( implementation.getDependencies() != null )
1849 {
1850 this.resolveClasspath( modules, implementation.getDependencies(), cpModule );
1851 }
1852 }
1853 }
1854
1855 private void resolveClasspath( final Modules modules, final Dependencies dependencies, final Module cpModule )
1856 {
1857 for ( Dependency dependency : dependencies.getDependency() )
1858 {
1859 this.resolveClasspath( modules, dependency, cpModule );
1860 }
1861 }
1862
1863 private void resolveClasspath( final String identifier, final Module cpModule )
1864 {
1865 Specification specification =
1866 cpModule.getSpecifications() == null ? null
1867 : cpModule.getSpecifications().getSpecification( identifier );
1868
1869 if ( specification == null )
1870 {
1871 try
1872 {
1873 final Class classpathSpec = Class.forName( identifier, true, this.getClassLoader() );
1874 if ( Modifier.isPublic( classpathSpec.getModifiers() ) )
1875 {
1876 String vendor = null;
1877 String version = null;
1878
1879 if ( classpathSpec.getPackage() != null )
1880 {
1881 vendor = classpathSpec.getPackage().getSpecificationVendor();
1882 version = classpathSpec.getPackage().getSpecificationVersion();
1883 }
1884
1885 specification = new Specification();
1886 specification.setIdentifier( identifier );
1887 specification.setClazz( classpathSpec.getName() );
1888 specification.setMultiplicity( Multiplicity.MANY );
1889 specification.setVendor( vendor );
1890 specification.setVersion( version );
1891
1892 this.log( Level.FINE, this.getMessage( "classpathSpecification", new Object[]
1893 {
1894 specification.getIdentifier(),
1895 specification.getMultiplicity().value()
1896 } ), null );
1897
1898
1899 if ( cpModule.getSpecifications() == null )
1900 {
1901 cpModule.setSpecifications( new Specifications() );
1902 }
1903
1904 cpModule.getSpecifications().getSpecification().add( specification );
1905
1906 this.resolveClasspath( specification, cpModule );
1907 }
1908
1909 }
1910 catch ( final ClassNotFoundException e )
1911 {
1912 this.log( Level.FINE, this.getMessage( "noSuchClass", new Object[]
1913 {
1914 e.getMessage()
1915 } ), null );
1916
1917 }
1918 }
1919 }
1920
1921 private void resolveClasspath( final Specification specification, final Module cpModule )
1922 {
1923 if ( specification == null )
1924 {
1925 throw new NullPointerException( "specification" );
1926 }
1927
1928 Implementation implementation =
1929 cpModule.getImplementations() == null ? null
1930 : cpModule.getImplementations().getImplementation( specification.getIdentifier() );
1931
1932 if ( implementation == null )
1933 {
1934 String name = null;
1935
1936 try
1937 {
1938 final Class classpathImpl = Class.forName( specification.getClazz(), true, this.getClassLoader() );
1939 boolean classpathImplementation = false;
1940
1941 if ( Modifier.isPublic( classpathImpl.getModifiers() ) )
1942 {
1943 if ( !Modifier.isAbstract( classpathImpl.getModifiers() ) )
1944 {
1945 try
1946 {
1947 classpathImpl.getConstructor( NO_CLASSES );
1948 name = "init";
1949 classpathImplementation = true;
1950 }
1951 catch ( final NoSuchMethodException e )
1952 {
1953 this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
1954 {
1955 e.getMessage()
1956 } ), null );
1957
1958 }
1959 }
1960
1961 if ( !classpathImplementation )
1962 {
1963 final char[] c = classpathImpl.getName().substring(
1964 classpathImpl.getPackage().getName().length() + 1 ).toCharArray();
1965
1966 name = String.valueOf( c );
1967 c[0] = Character.toUpperCase( c[0] );
1968
1969 if ( this.checkFactoryMethod( classpathImpl, classpathImpl, "getDefault" ) )
1970 {
1971 name = "default";
1972 classpathImplementation = true;
1973 }
1974 else if ( this.checkFactoryMethod( classpathImpl, classpathImpl, "getInstance" ) )
1975 {
1976 name = "instance";
1977 classpathImplementation = true;
1978 }
1979 else if ( this.checkFactoryMethod( classpathImpl, classpathImpl, "get" + String.valueOf( c ) ) )
1980 {
1981 classpathImplementation = true;
1982 }
1983
1984 }
1985
1986 if ( classpathImplementation )
1987 {
1988 String vendor = null;
1989 String version = null;
1990 if ( classpathImpl.getPackage() != null )
1991 {
1992 vendor = classpathImpl.getPackage().getImplementationVendor();
1993 version = classpathImpl.getPackage().getImplementationVersion();
1994 }
1995
1996 implementation = new Implementation();
1997 implementation.setVendor( vendor );
1998 implementation.setFinal( true );
1999 implementation.setName( name );
2000 implementation.setIdentifier( specification.getIdentifier() );
2001 implementation.setClazz( classpathImpl.getName() );
2002 implementation.setVersion( version );
2003
2004 final Specifications implemented = new Specifications();
2005 final SpecificationReference ref = new SpecificationReference();
2006 ref.setIdentifier( specification.getIdentifier() );
2007 ref.setVersion( specification.getVersion() );
2008 implemented.getReference().add( ref );
2009 implementation.setSpecifications( implemented );
2010
2011 this.log( Level.FINE, this.getMessage( "classpathImplementation", new Object[]
2012 {
2013 implementation.getIdentifier(),
2014 specification.getIdentifier(),
2015 implementation.getName()
2016 } ), null );
2017
2018 if ( cpModule.getImplementations() == null )
2019 {
2020 cpModule.setImplementations( new Implementations() );
2021 }
2022
2023 cpModule.getImplementations().getImplementation().add( implementation );
2024 }
2025 else
2026 {
2027 this.log( Level.FINE, this.getMessage( "noClasspathImplementation", new Object[]
2028 {
2029 specification.getIdentifier()
2030 } ), null );
2031
2032 }
2033 }
2034 }
2035 catch ( final ClassNotFoundException e )
2036 {
2037 this.log( Level.FINE, this.getMessage( "noSuchClass", new Object[]
2038 {
2039 e.getMessage()
2040 } ), null );
2041
2042 }
2043 }
2044 }
2045
2046 private boolean checkFactoryMethod( final Class clazz, final Class type, final String methodName )
2047 {
2048 boolean factoryMethod = false;
2049
2050 try
2051 {
2052 final Method m = clazz.getMethod( methodName, NO_CLASSES );
2053 factoryMethod = Modifier.isStatic( m.getModifiers() ) && type.isAssignableFrom( m.getReturnType() );
2054 }
2055 catch ( final NoSuchMethodException e )
2056 {
2057 this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
2058 {
2059 e.getMessage()
2060 } ), null );
2061
2062 factoryMethod = false;
2063 }
2064
2065 return factoryMethod;
2066 }
2067
2068 private Method getFactoryMethod( final Class clazz, final String methodName )
2069 {
2070 Method m = null;
2071
2072 try
2073 {
2074 m = clazz.getMethod( methodName, NO_CLASSES );
2075 }
2076 catch ( final NoSuchMethodException e )
2077 {
2078 this.log( Level.FINE, this.getMessage( "noSuchMethod", new Object[]
2079 {
2080 e.getMessage()
2081 } ), null );
2082
2083 m = null;
2084 }
2085
2086 return m;
2087 }
2088
2089 /**
2090 * Searches all available {@code META-INF/MANIFEST.MF} resources and gets a set containing URLs of entries whose
2091 * name end with a known schema extension.
2092 *
2093 * @return URLs of any matching entries.
2094 *
2095 * @throws IOException if reading or parsing fails.
2096 */
2097 private Set<URL> getSchemaResources() throws IOException
2098 {
2099 if ( this.schemaResources == null )
2100 {
2101 this.schemaResources = new HashSet<URL>();
2102
2103 for ( final Enumeration<URL> e = this.getClassLoader().getResources( "META-INF/MANIFEST.MF" );
2104 e.hasMoreElements(); )
2105 {
2106 final URL manifestUrl = e.nextElement();
2107 final String externalForm = manifestUrl.toExternalForm();
2108 final String baseUrl = externalForm.substring( 0, externalForm.indexOf( "META-INF" ) );
2109 final InputStream manifestStream = manifestUrl.openStream();
2110 final Manifest mf = new Manifest( manifestStream );
2111 manifestStream.close();
2112
2113 for ( Map.Entry<String, Attributes> entry : mf.getEntries().entrySet() )
2114 {
2115 for ( int i = SCHEMA_EXTENSIONS.length - 1; i >= 0; i-- )
2116 {
2117 if ( entry.getKey().toLowerCase().endsWith( '.' + SCHEMA_EXTENSIONS[i].toLowerCase() ) )
2118 {
2119 final URL schemaUrl = new URL( baseUrl + entry.getKey() );
2120 this.schemaResources.add( schemaUrl );
2121 this.log( Level.FINE, this.getMessage( "processing", new Object[]
2122 {
2123 schemaUrl.toExternalForm()
2124 } ), null );
2125
2126 }
2127 }
2128 }
2129 }
2130 }
2131
2132 return this.schemaResources;
2133 }
2134
2135 /**
2136 * Gets the implementation of an object.
2137 *
2138 * @param modules The modules to search for the implementation of {@code object}.
2139 * @param object The object to get the implementation for.
2140 *
2141 * @return The implementation for {@code object} or {@code null}, if nothing is known about {@code object}.
2142 */
2143 private Implementation getImplementation( final Modules modules, final Object object )
2144 {
2145 return this.collectImplementation( modules, object.getClass() );
2146 }
2147
2148 private Implementation collectImplementation( final Modules modules, final Class clazz )
2149 {
2150 Implementation i = modules.getImplementation( clazz );
2151 if ( i == null && clazz.getSuperclass() != null )
2152 {
2153 i = this.collectImplementation( modules, clazz.getSuperclass() );
2154 }
2155
2156 return i;
2157 }
2158
2159 private String getMessage( final String key, final Object args )
2160 {
2161 return new MessageFormat(
2162 ResourceBundle.getBundle( DefaultModelManager.class.getName().replace( '.', '/' ), Locale.getDefault() ).
2163 getString( key ) ).format( args );
2164
2165 }
2166
2167 private void assertMessagesUniqueness( final Messages messages, final List<ModelException.Detail> details )
2168 {
2169 for ( Message m : messages.getMessage() )
2170 {
2171 if ( messages.getReference( m.getName() ) != null )
2172 {
2173 final ModelException.Detail detail = new ModelException.Detail( Level.SEVERE, this.getMessage(
2174 "messagesUniquessConstraint", new Object[]
2175 {
2176 m.getName()
2177 } ) );
2178
2179 detail.setElement( this.getObjectFactory().createMessages( messages ) );
2180 details.add( detail );
2181 }
2182 }
2183 }
2184
2185 private void assertPropertiesUniqueness( final Properties properties, final List<ModelException.Detail> details )
2186 {
2187 for ( Property p : properties.getProperty() )
2188 {
2189 if ( properties.getReference( p.getName() ) != null )
2190 {
2191 final ModelException.Detail detail = new ModelException.Detail( Level.SEVERE, this.getMessage(
2192 "propertiesUniquessConstraint", new Object[]
2193 {
2194 p.getName()
2195 } ) );
2196
2197 detail.setElement( this.getObjectFactory().createProperties( properties ) );
2198 details.add( detail );
2199 }
2200 }
2201 }
2202
2203 private ModelException.Detail newIncompatibleImplementationDetail(
2204 final JAXBElement<? extends ModelObject> element, final String implementation,
2205 final String implementationModule, final String specification, final String specificationModule,
2206 final String implementedVersion, final String specifiedVersion )
2207 {
2208 final ModelException.Detail detail =
2209 new ModelException.Detail( Level.SEVERE, this.getMessage( "incompatibleImplementation", new Object[]
2210 {
2211 implementation, implementationModule, specification, specificationModule,
2212 implementedVersion, specifiedVersion
2213 } ) );
2214
2215 detail.setElement( element );
2216 return detail;
2217 }
2218
2219 private ModelException.Detail newIncompatibleDependencyDetail(
2220 final JAXBElement<? extends ModelObject> element, final String implementation,
2221 final String implementationModule, final String specification, final String specificationModule,
2222 final String requiredVersion, final String availableVersion )
2223 {
2224 final ModelException.Detail detail =
2225 new ModelException.Detail( Level.SEVERE, this.getMessage( "incompatibleDependency", new Object[]
2226 {
2227 implementation, implementationModule, specification, specificationModule,
2228 requiredVersion, availableVersion
2229 } ) );
2230
2231 detail.setElement( element );
2232 return detail;
2233 }
2234
2235 private ModelException.Detail newImplementationNameConstraintDetail(
2236 final JAXBElement<? extends ModelObject> element, final String specification, final String implementations,
2237 final String nonUniqueName )
2238 {
2239 final ModelException.Detail detail =
2240 new ModelException.Detail( Level.SEVERE, this.getMessage( "implementationNameConstraint", new Object[]
2241 {
2242 specification, implementations, nonUniqueName
2243 } ) );
2244
2245 detail.setElement( element );
2246 return detail;
2247 }
2248
2249 private ModelException.Detail newMandatoryDependencyConstraintDetail(
2250 final JAXBElement<? extends ModelObject> element, final String implementation, final String dependencyName )
2251 {
2252 final ModelException.Detail detail =
2253 new ModelException.Detail( Level.SEVERE, this.getMessage( "mandatoryDependencyConstraint", new Object[]
2254 {
2255 implementation, dependencyName
2256 } ) );
2257
2258 detail.setElement( element );
2259 return detail;
2260 }
2261
2262 private ModelException.Detail newMultiplicityConstraintDetail(
2263 final JAXBElement<? extends ModelObject> element, final Number implementations, final String specification,
2264 final Number expected, final Multiplicity multiplicity )
2265 {
2266 final ModelException.Detail detail =
2267 new ModelException.Detail( Level.SEVERE, this.getMessage( "multiplicityConstraint", new Object[]
2268 {
2269 implementations, specification, expected, multiplicity.value()
2270 } ) );
2271
2272 detail.setElement( element );
2273 return detail;
2274 }
2275
2276 private ModelException.Detail newInheritanceConstraintDetail(
2277 final JAXBElement<? extends ModelObject> element, final Implementation child, final Implementation parent )
2278 {
2279 final ModelException.Detail detail =
2280 new ModelException.Detail( Level.SEVERE, this.getMessage( "inheritanceConstraint", new Object[]
2281 {
2282 child.getIdentifier(), parent.getIdentifier()
2283 } ) );
2284
2285 detail.setElement( element );
2286 return detail;
2287 }
2288
2289 private ModelException.Detail newDependencyPropertyReferenceConstraintDetail(
2290 final JAXBElement<? extends ModelObject> element, final Implementation implementation,
2291 final Dependency dependency )
2292 {
2293 final ModelException.Detail detail = new ModelException.Detail(
2294 Level.SEVERE, this.getMessage( "dependencyPropertyReferenceConstraint", new Object[]
2295 {
2296 implementation.getIdentifier(), dependency.getName()
2297 } ) );
2298
2299 detail.setElement( element );
2300 return detail;
2301 }
2302
2303 private ModelException.Detail newPropertyOverwriteConstraintDetail(
2304 final JAXBElement<? extends ModelObject> element, final Implementation implementation,
2305 final Dependency dependency, final Specification specification, final String scope )
2306 {
2307 final ModelException.Detail detail = new ModelException.Detail(
2308 Level.SEVERE, this.getMessage( "propertyOverwriteConstraint", new Object[]
2309 {
2310 implementation.getIdentifier(), dependency.getName(), specification.getIdentifier(), scope
2311 } ) );
2312
2313 detail.setElement( element );
2314 return detail;
2315 }
2316
2317 private ModelException.Detail newImplementationSpecificationDeclarationConstraintDetail(
2318 final JAXBElement<? extends ModelObject> element, final Implementation implementation,
2319 final Specification specification )
2320 {
2321 final ModelException.Detail detail = new ModelException.Detail(
2322 Level.SEVERE, this.getMessage( "implementationSpecificationDeclarationConstraint", new Object[]
2323 {
2324 implementation.getIdentifier(), specification.getIdentifier()
2325 } ) );
2326
2327 detail.setElement( element );
2328 return detail;
2329 }
2330
2331 private ModelException.Detail newModuleSpecificationReferenceConstraintDetail(
2332 final JAXBElement<? extends ModelObject> element, final Module module, final SpecificationReference reference )
2333 {
2334 final ModelException.Detail detail = new ModelException.Detail(
2335 Level.SEVERE, this.getMessage( "moduleSpecificationReferenceConstraint", new Object[]
2336 {
2337 module.getName(), reference.getIdentifier()
2338 } ) );
2339
2340 detail.setElement( element );
2341 return detail;
2342 }
2343
2344 // SECTION-END
2345 }