1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.jomc.modlet;
32
33 import java.io.BufferedReader;
34 import java.io.File;
35 import java.io.FileInputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.Reader;
40 import java.lang.ref.Reference;
41 import java.lang.ref.SoftReference;
42 import java.lang.reflect.InvocationTargetException;
43 import java.lang.reflect.Method;
44 import java.lang.reflect.Modifier;
45 import java.net.URI;
46 import java.net.URISyntaxException;
47 import java.net.URL;
48 import java.text.MessageFormat;
49 import java.util.ArrayList;
50 import java.util.Collection;
51 import java.util.Comparator;
52 import java.util.Enumeration;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.ResourceBundle;
58 import java.util.Set;
59 import java.util.StringTokenizer;
60 import java.util.TreeMap;
61 import java.util.jar.Attributes;
62 import java.util.jar.Manifest;
63 import java.util.logging.Level;
64 import javax.xml.XMLConstants;
65 import javax.xml.bind.JAXBContext;
66 import javax.xml.bind.JAXBException;
67 import javax.xml.bind.Marshaller;
68 import javax.xml.bind.Unmarshaller;
69 import javax.xml.transform.Source;
70 import javax.xml.transform.sax.SAXSource;
71 import javax.xml.validation.SchemaFactory;
72 import javax.xml.validation.Validator;
73 import org.w3c.dom.ls.LSInput;
74 import org.w3c.dom.ls.LSResourceResolver;
75 import org.xml.sax.EntityResolver;
76 import org.xml.sax.ErrorHandler;
77 import org.xml.sax.InputSource;
78 import org.xml.sax.SAXException;
79 import org.xml.sax.SAXParseException;
80 import org.xml.sax.helpers.DefaultHandler;
81
82
83
84
85
86
87
88
89 public class DefaultModelContext extends ModelContext
90 {
91
92
93
94
95
96
97
98 public static final String PROVIDER_LOCATION_ATTRIBUTE_NAME =
99 "org.jomc.modlet.DefaultModelContext.providerLocationAttribute";
100
101
102
103
104
105
106
107 public static final String PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME =
108 "org.jomc.modlet.DefaultModelContext.platformProviderLocationAttribute";
109
110
111 private static final String[] SCHEMA_EXTENSIONS = new String[]
112 {
113 "xsd"
114 };
115
116
117
118
119
120 private static final String DEFAULT_PROVIDER_LOCATION = "META-INF/services";
121
122
123
124
125
126 private static final String DEFAULT_PLATFORM_PROVIDER_LOCATION =
127 new StringBuilder( 255 ).append( System.getProperty( "java.home" ) ).append( File.separator ).append( "lib" ).
128 append( File.separator ).append( "jomc.properties" ).toString();
129
130
131
132
133
134 private static final String MARSHALLER_LISTENER_SERVICE = "javax.xml.bind.Marshaller.Listener";
135
136
137
138
139
140 private static final String UNMARSHALLER_LISTENER_SERVICE = "javax.xml.bind.Unmarshaller.Listener";
141
142
143 private static volatile String defaultProviderLocation;
144
145
146 private static volatile String defaultPlatformProviderLocation;
147
148
149 private Reference<Set<URI>> cachedSchemaResources = new SoftReference<Set<URI>>( null );
150
151
152 private String providerLocation;
153
154
155 private String platformProviderLocation;
156
157
158
159
160
161 public DefaultModelContext()
162 {
163 super();
164 }
165
166
167
168
169
170
171 public DefaultModelContext( final ClassLoader classLoader )
172 {
173 super( classLoader );
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187 public static String getDefaultProviderLocation()
188 {
189 if ( defaultProviderLocation == null )
190 {
191 defaultProviderLocation = System.getProperty(
192 "org.jomc.modlet.DefaultModelContext.defaultProviderLocation", DEFAULT_PROVIDER_LOCATION );
193
194 }
195
196 return defaultProviderLocation;
197 }
198
199
200
201
202
203
204
205
206 public static void setDefaultProviderLocation( final String value )
207 {
208 defaultProviderLocation = value;
209 }
210
211
212
213
214
215
216
217
218
219
220 public final String getProviderLocation()
221 {
222 if ( this.providerLocation == null )
223 {
224 this.providerLocation = getDefaultProviderLocation();
225
226 if ( DEFAULT_PROVIDER_LOCATION.equals( this.providerLocation )
227 && this.getAttribute( PROVIDER_LOCATION_ATTRIBUTE_NAME ) instanceof String )
228 {
229 final String contextProviderLocation = (String) this.getAttribute( PROVIDER_LOCATION_ATTRIBUTE_NAME );
230
231 if ( this.isLoggable( Level.CONFIG ) )
232 {
233 this.log( Level.CONFIG, getMessage( "contextProviderLocationInfo",
234 contextProviderLocation ), null );
235 }
236
237 this.providerLocation = null;
238 return contextProviderLocation;
239 }
240 else if ( this.isLoggable( Level.CONFIG ) )
241 {
242 this.log( Level.CONFIG, getMessage( "defaultProviderLocationInfo", this.providerLocation ), null );
243 }
244 }
245
246 return this.providerLocation;
247 }
248
249
250
251
252
253
254
255
256 public final void setProviderLocation( final String value )
257 {
258 this.providerLocation = value;
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272 public static String getDefaultPlatformProviderLocation()
273 {
274 if ( defaultPlatformProviderLocation == null )
275 {
276 defaultPlatformProviderLocation = System.getProperty(
277 "org.jomc.modlet.DefaultModelContext.defaultPlatformProviderLocation",
278 DEFAULT_PLATFORM_PROVIDER_LOCATION );
279
280 }
281
282 return defaultPlatformProviderLocation;
283 }
284
285
286
287
288
289
290
291
292 public static void setDefaultPlatformProviderLocation( final String value )
293 {
294 defaultPlatformProviderLocation = value;
295 }
296
297
298
299
300
301
302
303
304
305
306 public final String getPlatformProviderLocation()
307 {
308 if ( this.platformProviderLocation == null )
309 {
310 this.platformProviderLocation = getDefaultPlatformProviderLocation();
311
312 if ( DEFAULT_PLATFORM_PROVIDER_LOCATION.equals( this.platformProviderLocation )
313 && this.getAttribute( PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME ) instanceof String )
314 {
315 final String contextPlatformProviderLocation =
316 (String) this.getAttribute( PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME );
317
318 if ( this.isLoggable( Level.CONFIG ) )
319 {
320 this.log( Level.CONFIG, getMessage( "contextPlatformProviderLocationInfo",
321 contextPlatformProviderLocation ), null );
322
323 }
324
325 this.platformProviderLocation = null;
326 return contextPlatformProviderLocation;
327 }
328 else if ( this.isLoggable( Level.CONFIG ) )
329 {
330 this.log( Level.CONFIG,
331 getMessage( "defaultPlatformProviderLocationInfo", this.platformProviderLocation ), null );
332
333 }
334 }
335
336 return this.platformProviderLocation;
337 }
338
339
340
341
342
343
344
345
346 public final void setPlatformProviderLocation( final String value )
347 {
348 this.platformProviderLocation = value;
349 }
350
351
352
353
354
355
356
357
358
359
360 @Override
361 public Modlets findModlets() throws ModelException
362 {
363 final Modlets modlets = new Modlets();
364 final Collection<ModletProvider> providers = this.loadProviders( ModletProvider.class );
365
366 for ( ModletProvider provider : providers )
367 {
368 if ( this.isLoggable( Level.FINER ) )
369 {
370 this.log( Level.FINER, getMessage( "creatingModlets", provider.toString() ), null );
371 }
372
373 final Modlets provided = provider.findModlets( this );
374
375 if ( provided != null )
376 {
377 if ( this.isLoggable( Level.FINEST ) )
378 {
379 for ( Modlet m : provided.getModlet() )
380 {
381 this.log( Level.FINEST,
382 getMessage( "modletInfo", m.getName(), m.getModel(),
383 m.getVendor() != null
384 ? m.getVendor() : getMessage( "noVendor" ),
385 m.getVersion() != null
386 ? m.getVersion() : getMessage( "noVersion" ) ), null );
387
388 if ( m.getSchemas() != null )
389 {
390 for ( Schema s : m.getSchemas().getSchema() )
391 {
392 this.log( Level.FINEST,
393 getMessage( "modletSchemaInfo", m.getName(), s.getPublicId(), s.getSystemId(),
394 s.getContextId() != null
395 ? s.getContextId() : getMessage( "noContext" ),
396 s.getClasspathId() != null
397 ? s.getClasspathId() : getMessage( "noClasspathId" ) ), null );
398
399 }
400 }
401
402 if ( m.getServices() != null )
403 {
404 for ( Service s : m.getServices().getService() )
405 {
406 this.log( Level.FINEST, getMessage( "modletServiceInfo", m.getName(), s.getOrdinal(),
407 s.getIdentifier(), s.getClazz() ), null );
408
409 }
410 }
411 }
412 }
413
414 modlets.getModlet().addAll( provided.getModlet() );
415 }
416 }
417
418 return modlets;
419 }
420
421
422
423
424
425
426
427
428
429 @Override
430 public Model findModel( final String model ) throws ModelException
431 {
432 if ( model == null )
433 {
434 throw new NullPointerException( "model" );
435 }
436
437 final Model m = new Model();
438 m.setIdentifier( model );
439
440 return this.findModel( m );
441 }
442
443
444
445
446
447
448
449
450
451
452
453 @Override
454 public Model findModel( final Model model ) throws ModelException
455 {
456 if ( model == null )
457 {
458 throw new NullPointerException( "model" );
459 }
460
461 Model m = model.clone();
462 final Services services = this.getModlets().getServices( m.getIdentifier() );
463
464 if ( services != null )
465 {
466 for ( Service service : services.getServices( ModelProvider.class ) )
467 {
468 final ModelProvider modelProvider = this.createServiceObject( service, ModelProvider.class );
469
470 if ( this.isLoggable( Level.FINER ) )
471 {
472 this.log( Level.FINER, getMessage( "creatingModel", m.getIdentifier(), modelProvider.toString() ),
473 null );
474
475 }
476
477 final Model provided = modelProvider.findModel( this, m );
478
479 if ( provided != null )
480 {
481 m = provided;
482 }
483 }
484 }
485
486 return m;
487 }
488
489
490
491
492
493 @Override
494 public <T> T createServiceObject( final Service service, final Class<T> type ) throws ModelException
495 {
496 if ( service == null )
497 {
498 throw new NullPointerException( "service" );
499 }
500 if ( type == null )
501 {
502 throw new NullPointerException( "type" );
503 }
504
505 try
506 {
507 final Class<?> clazz = this.findClass( service.getClazz() );
508
509 if ( clazz == null )
510 {
511 throw new ModelException( getMessage( "serviceNotFound", service.getOrdinal(), service.getIdentifier(),
512 service.getClazz() ) );
513
514 }
515
516 if ( !type.isAssignableFrom( clazz ) )
517 {
518 throw new ModelException( getMessage( "illegalService", service.getOrdinal(), service.getIdentifier(),
519 service.getClazz(), type.getName() ) );
520
521 }
522
523 final T serviceObject = clazz.asSubclass( type ).newInstance();
524
525 for ( int i = 0, s0 = service.getProperty().size(); i < s0; i++ )
526 {
527 final Property p = service.getProperty().get( i );
528 this.setProperty( serviceObject, p.getName(), p.getValue() );
529 }
530
531 return serviceObject;
532 }
533 catch ( final InstantiationException e )
534 {
535 throw new ModelException( getMessage( "failedCreatingObject", service.getClazz() ), e );
536 }
537 catch ( final IllegalAccessException e )
538 {
539 throw new ModelException( getMessage( "failedCreatingObject", service.getClazz() ), e );
540 }
541 }
542
543 @Override
544 public EntityResolver createEntityResolver( final String model ) throws ModelException
545 {
546 if ( model == null )
547 {
548 throw new NullPointerException( "model" );
549 }
550
551 return this.createEntityResolver( this.getModlets().getSchemas( model ) );
552 }
553
554 @Override
555 public EntityResolver createEntityResolver( final URI publicId ) throws ModelException
556 {
557 if ( publicId == null )
558 {
559 throw new NullPointerException( "publicId" );
560 }
561
562 return this.createEntityResolver( this.getModlets().getSchemas( publicId ) );
563 }
564
565 @Override
566 public LSResourceResolver createResourceResolver( final String model ) throws ModelException
567 {
568 if ( model == null )
569 {
570 throw new NullPointerException( "model" );
571 }
572
573 return this.createResourceResolver( this.createEntityResolver( model ) );
574 }
575
576 @Override
577 public LSResourceResolver createResourceResolver( final URI publicId ) throws ModelException
578 {
579 if ( publicId == null )
580 {
581 throw new NullPointerException( "publicId" );
582 }
583
584 return this.createResourceResolver( this.createEntityResolver( publicId ) );
585 }
586
587 @Override
588 public javax.xml.validation.Schema createSchema( final String model ) throws ModelException
589 {
590 if ( model == null )
591 {
592 throw new NullPointerException( "model" );
593 }
594
595 return this.createSchema( this.getModlets().getSchemas( model ), this.createEntityResolver( model ),
596 this.createResourceResolver( model ), model, null );
597
598 }
599
600 @Override
601 public javax.xml.validation.Schema createSchema( final URI publicId ) throws ModelException
602 {
603 if ( publicId == null )
604 {
605 throw new NullPointerException( "publicId" );
606 }
607
608 return this.createSchema( this.getModlets().getSchemas( publicId ), this.createEntityResolver( publicId ),
609 this.createResourceResolver( publicId ), null, publicId );
610
611 }
612
613 @Override
614 public JAXBContext createContext( final String model ) throws ModelException
615 {
616 if ( model == null )
617 {
618 throw new NullPointerException( "model" );
619 }
620
621 return this.createContext( this.getModlets().getSchemas( model ), model, null );
622 }
623
624 @Override
625 public JAXBContext createContext( final URI publicId ) throws ModelException
626 {
627 if ( publicId == null )
628 {
629 throw new NullPointerException( "publicId" );
630 }
631
632 return this.createContext( this.getModlets().getSchemas( publicId ), null, publicId );
633 }
634
635 @Override
636 public Marshaller createMarshaller( final String model ) throws ModelException
637 {
638 if ( model == null )
639 {
640 throw new NullPointerException( "model" );
641 }
642
643 return this.createMarshaller( this.getModlets().getSchemas( model ), this.getModlets().getServices( model ),
644 model, null );
645
646 }
647
648 @Override
649 public Marshaller createMarshaller( final URI publicId ) throws ModelException
650 {
651 if ( publicId == null )
652 {
653 throw new NullPointerException( "publicId" );
654 }
655
656 return this.createMarshaller( this.getModlets().getSchemas( publicId ), null, null, publicId );
657 }
658
659 @Override
660 public Unmarshaller createUnmarshaller( final String model ) throws ModelException
661 {
662 if ( model == null )
663 {
664 throw new NullPointerException( "model" );
665 }
666
667 return this.createUnmarshaller( this.getModlets().getSchemas( model ), this.getModlets().getServices( model ),
668 model, null );
669
670 }
671
672 @Override
673 public Unmarshaller createUnmarshaller( final URI publicId ) throws ModelException
674 {
675 if ( publicId == null )
676 {
677 throw new NullPointerException( "publicId" );
678 }
679
680 return this.createUnmarshaller( this.getModlets().getSchemas( publicId ), null, null, publicId );
681 }
682
683
684
685
686
687
688
689
690
691 @Override
692 public Model processModel( final Model model ) throws ModelException
693 {
694 if ( model == null )
695 {
696 throw new NullPointerException( "model" );
697 }
698
699 Model processed = model;
700 final Services services = this.getModlets().getServices( model.getIdentifier() );
701
702 if ( services != null )
703 {
704 for ( Service service : services.getServices( ModelProcessor.class ) )
705 {
706 final ModelProcessor modelProcessor = this.createServiceObject( service, ModelProcessor.class );
707
708 if ( this.isLoggable( Level.FINER ) )
709 {
710 this.log( Level.FINER, getMessage( "processingModel", model.getIdentifier(),
711 modelProcessor.toString() ), null );
712
713 }
714
715 final Model current = modelProcessor.processModel( this, processed );
716
717 if ( current != null )
718 {
719 processed = current;
720 }
721 }
722 }
723
724 return processed;
725 }
726
727
728
729
730
731
732
733
734
735 @Override
736 public ModelValidationReport validateModel( final Model model ) throws ModelException
737 {
738 if ( model == null )
739 {
740 throw new NullPointerException( "model" );
741 }
742
743 final Services services = this.getModlets().getServices( model.getIdentifier() );
744 final ModelValidationReport report = new ModelValidationReport();
745
746 if ( services != null )
747 {
748 for ( Service service : services.getServices( ModelValidator.class ) )
749 {
750 final ModelValidator modelValidator = this.createServiceObject( service, ModelValidator.class );
751
752 if ( this.isLoggable( Level.FINER ) )
753 {
754 this.log( Level.FINER, getMessage( "validatingModel", model.getIdentifier(),
755 modelValidator.toString() ), null );
756
757 }
758
759 final ModelValidationReport current = modelValidator.validateModel( this, model );
760
761 if ( current != null )
762 {
763 report.getDetails().addAll( current.getDetails() );
764 }
765 }
766 }
767
768 return report;
769 }
770
771
772
773
774
775
776 @Override
777 public ModelValidationReport validateModel( final String model, final Source source ) throws ModelException
778 {
779 if ( model == null )
780 {
781 throw new NullPointerException( "model" );
782 }
783 if ( source == null )
784 {
785 throw new NullPointerException( "source" );
786 }
787
788 final javax.xml.validation.Schema schema = this.createSchema( model );
789 final Validator validator = schema.newValidator();
790 final ModelErrorHandler modelErrorHandler = new ModelErrorHandler( this );
791 validator.setErrorHandler( modelErrorHandler );
792
793 try
794 {
795 validator.validate( source );
796 }
797 catch ( final SAXException e )
798 {
799 String message = getMessage( e );
800 if ( message == null && e.getException() != null )
801 {
802 message = getMessage( e.getException() );
803 }
804
805 if ( this.isLoggable( Level.FINE ) )
806 {
807 this.log( Level.FINE, message, e );
808 }
809
810 if ( modelErrorHandler.getReport().isModelValid() )
811 {
812 throw new ModelException( message, e );
813 }
814 }
815 catch ( final IOException e )
816 {
817 throw new ModelException( getMessage( e ), e );
818 }
819
820 return modelErrorHandler.getReport();
821 }
822
823 private <T> Collection<T> loadProviders( final Class<T> providerClass ) throws ModelException
824 {
825 try
826 {
827 final String providerNamePrefix = providerClass.getName() + ".";
828 final Map<String, T> providers = new TreeMap<String, T>( new Comparator<String>()
829 {
830
831 public int compare( final String key1, final String key2 )
832 {
833 return key1.compareTo( key2 );
834 }
835
836 } );
837
838 final File platformProviders = new File( this.getPlatformProviderLocation() );
839
840 if ( platformProviders.exists() )
841 {
842 if ( this.isLoggable( Level.FINEST ) )
843 {
844 this.log( Level.FINEST, getMessage( "processing", platformProviders.getAbsolutePath() ), null );
845 }
846
847 InputStream in = null;
848 boolean suppressExceptionOnClose = true;
849 final java.util.Properties p = new java.util.Properties();
850
851 try
852 {
853 in = new FileInputStream( platformProviders );
854 p.load( in );
855 suppressExceptionOnClose = false;
856 }
857 finally
858 {
859 try
860 {
861 if ( in != null )
862 {
863 in.close();
864 }
865 }
866 catch ( final IOException e )
867 {
868 if ( suppressExceptionOnClose )
869 {
870 this.log( Level.SEVERE, getMessage( e ), e );
871 }
872 else
873 {
874 throw e;
875 }
876 }
877 }
878
879 for ( Map.Entry<Object, Object> e : p.entrySet() )
880 {
881 if ( e.getKey().toString().startsWith( providerNamePrefix ) )
882 {
883 final String configuration = e.getValue().toString();
884
885 if ( this.isLoggable( Level.FINEST ) )
886 {
887 this.log( Level.FINEST, getMessage( "providerInfo", platformProviders.getAbsolutePath(),
888 providerClass.getName(), configuration ), null );
889
890 }
891
892 providers.put( e.getKey().toString(),
893 this.createProviderObject( providerClass, configuration,
894 platformProviders.toURI().toURL() ) );
895
896 }
897 }
898 }
899
900 final Enumeration<URL> classpathProviders =
901 this.findResources( this.getProviderLocation() + '/' + providerClass.getName() );
902
903 int count = 0;
904 final long t0 = System.currentTimeMillis();
905
906 while ( classpathProviders.hasMoreElements() )
907 {
908 count++;
909 final URL url = classpathProviders.nextElement();
910
911 if ( this.isLoggable( Level.FINEST ) )
912 {
913 this.log( Level.FINEST, getMessage( "processing", url.toExternalForm() ), null );
914 }
915
916 BufferedReader reader = null;
917 boolean suppressExceptionOnClose = true;
918
919 try
920 {
921 reader = new BufferedReader( new InputStreamReader( url.openStream(), "UTF-8" ) );
922
923 String line = null;
924 while ( ( line = reader.readLine() ) != null )
925 {
926 if ( line.contains( "#" ) )
927 {
928 continue;
929 }
930
931 if ( this.isLoggable( Level.FINEST ) )
932 {
933 this.log( Level.FINEST, getMessage( "providerInfo", url.toExternalForm(),
934 providerClass.getName(), line ), null );
935
936 }
937
938 providers.put( providerNamePrefix + providers.size(),
939 this.createProviderObject( providerClass, line, url ) );
940
941 }
942
943 suppressExceptionOnClose = false;
944 }
945 finally
946 {
947 try
948 {
949 if ( reader != null )
950 {
951 reader.close();
952 }
953 }
954 catch ( final IOException e )
955 {
956 if ( suppressExceptionOnClose )
957 {
958 this.log( Level.SEVERE, getMessage( e ), e );
959 }
960 else
961 {
962 throw new ModelException( getMessage( e ), e );
963 }
964 }
965 }
966 }
967
968 if ( this.isLoggable( Level.FINE ) )
969 {
970 this.log( Level.FINE, getMessage( "contextReport", count,
971 this.getProviderLocation() + '/' + providerClass.getName(),
972 Long.valueOf( System.currentTimeMillis() - t0 ) ), null );
973
974 }
975
976 return providers.values();
977 }
978 catch ( final IOException e )
979 {
980 throw new ModelException( getMessage( e ), e );
981 }
982 }
983
984 private <T> T createProviderObject( final Class<T> providerClass, final String configuration, final URL location )
985 throws ModelException
986 {
987 String className = configuration;
988
989 try
990 {
991 final Map<String, String> properties = new HashMap<String, String>();
992 final int i0 = configuration.indexOf( '[' );
993 final int i1 = configuration.lastIndexOf( ']' );
994
995 if ( i0 != -1 && i1 != -1 )
996 {
997 className = configuration.substring( 0, i0 );
998 final StringTokenizer propertyTokens =
999 new StringTokenizer( configuration.substring( i0 + 1, i1 ), "," );
1000
1001 while ( propertyTokens.hasMoreTokens() )
1002 {
1003 final String property = propertyTokens.nextToken();
1004 final int d0 = property.indexOf( '=' );
1005
1006 String propertyName = property;
1007 String propertyValue = null;
1008
1009 if ( d0 != -1 )
1010 {
1011 propertyName = property.substring( 0, d0 );
1012 propertyValue = property.substring( d0 + 1, property.length() );
1013 }
1014
1015 properties.put( propertyName, propertyValue );
1016 }
1017 }
1018
1019 final Class<?> provider = this.findClass( className );
1020
1021 if ( provider == null )
1022 {
1023 throw new ModelException( getMessage( "implementationNotFound", providerClass.getName(), className,
1024 location.toExternalForm() ) );
1025
1026 }
1027
1028 if ( !providerClass.isAssignableFrom( provider ) )
1029 {
1030 throw new ModelException( getMessage( "illegalImplementation", providerClass.getName(), className,
1031 location.toExternalForm() ) );
1032
1033 }
1034
1035 final T o = provider.asSubclass( providerClass ).newInstance();
1036
1037 for ( final Map.Entry<String, String> property : properties.entrySet() )
1038 {
1039 this.setProperty( o, property.getKey(), property.getValue() );
1040 }
1041
1042 return o;
1043 }
1044 catch ( final InstantiationException e )
1045 {
1046 throw new ModelException( getMessage( "failedCreatingObject", className ), e );
1047 }
1048 catch ( final IllegalAccessException e )
1049 {
1050 throw new ModelException( getMessage( "failedCreatingObject", className ), e );
1051 }
1052 }
1053
1054 private <T> void setProperty( final T object, final String propertyName, final String propertyValue )
1055 throws ModelException
1056 {
1057 if ( object == null )
1058 {
1059 throw new NullPointerException( "object" );
1060 }
1061 if ( propertyName == null )
1062 {
1063 throw new NullPointerException( "propertyName" );
1064 }
1065
1066 try
1067 {
1068 final char[] chars = propertyName.toCharArray();
1069
1070 if ( Character.isLowerCase( chars[0] ) )
1071 {
1072 chars[0] = Character.toUpperCase( chars[0] );
1073 }
1074
1075 final String methodNameSuffix = String.valueOf( chars );
1076 Method getterMethod = null;
1077
1078 try
1079 {
1080 getterMethod = object.getClass().getMethod( "get" + methodNameSuffix );
1081 }
1082 catch ( final NoSuchMethodException e )
1083 {
1084 if ( this.isLoggable( Level.FINEST ) )
1085 {
1086 this.log( Level.FINEST, null, e );
1087 }
1088
1089 getterMethod = null;
1090 }
1091
1092 if ( getterMethod == null )
1093 {
1094 try
1095 {
1096 getterMethod = object.getClass().getMethod( "is" + methodNameSuffix );
1097 }
1098 catch ( final NoSuchMethodException e )
1099 {
1100 if ( this.isLoggable( Level.FINEST ) )
1101 {
1102 this.log( Level.FINEST, null, e );
1103 }
1104
1105 getterMethod = null;
1106 }
1107 }
1108
1109 if ( getterMethod == null )
1110 {
1111 throw new ModelException( getMessage( "getterMethodNotFound", object.getClass().getName(),
1112 propertyName ) );
1113
1114 }
1115
1116 final Class<?> propertyType = getterMethod.getReturnType();
1117 Class<?> boxedPropertyType = propertyType;
1118 Class<?> unboxedPropertyType = propertyType;
1119
1120 if ( Boolean.TYPE.equals( propertyType ) )
1121 {
1122 boxedPropertyType = Boolean.class;
1123 }
1124 else if ( Character.TYPE.equals( propertyType ) )
1125 {
1126 boxedPropertyType = Character.class;
1127 }
1128 else if ( Byte.TYPE.equals( propertyType ) )
1129 {
1130 boxedPropertyType = Byte.class;
1131 }
1132 else if ( Short.TYPE.equals( propertyType ) )
1133 {
1134 boxedPropertyType = Short.class;
1135 }
1136 else if ( Integer.TYPE.equals( propertyType ) )
1137 {
1138 boxedPropertyType = Integer.class;
1139 }
1140 else if ( Long.TYPE.equals( propertyType ) )
1141 {
1142 boxedPropertyType = Long.class;
1143 }
1144 else if ( Float.TYPE.equals( propertyType ) )
1145 {
1146 boxedPropertyType = Float.class;
1147 }
1148 else if ( Double.TYPE.equals( propertyType ) )
1149 {
1150 boxedPropertyType = Double.class;
1151 }
1152
1153 if ( Boolean.class.equals( propertyType ) )
1154 {
1155 unboxedPropertyType = Boolean.TYPE;
1156 }
1157 else if ( Character.class.equals( propertyType ) )
1158 {
1159 unboxedPropertyType = Character.TYPE;
1160 }
1161 else if ( Byte.class.equals( propertyType ) )
1162 {
1163 unboxedPropertyType = Byte.TYPE;
1164 }
1165 else if ( Short.class.equals( propertyType ) )
1166 {
1167 unboxedPropertyType = Short.TYPE;
1168 }
1169 else if ( Integer.class.equals( propertyType ) )
1170 {
1171 unboxedPropertyType = Integer.TYPE;
1172 }
1173 else if ( Long.class.equals( propertyType ) )
1174 {
1175 unboxedPropertyType = Long.TYPE;
1176 }
1177 else if ( Float.class.equals( propertyType ) )
1178 {
1179 unboxedPropertyType = Float.TYPE;
1180 }
1181 else if ( Double.class.equals( propertyType ) )
1182 {
1183 unboxedPropertyType = Double.TYPE;
1184 }
1185
1186 Method setterMethod = null;
1187
1188 try
1189 {
1190 setterMethod = object.getClass().getMethod( "set" + methodNameSuffix, boxedPropertyType );
1191 }
1192 catch ( final NoSuchMethodException e )
1193 {
1194 if ( this.isLoggable( Level.FINEST ) )
1195 {
1196 this.log( Level.FINEST, null, e );
1197 }
1198
1199 setterMethod = null;
1200 }
1201
1202 if ( setterMethod == null && !boxedPropertyType.equals( unboxedPropertyType ) )
1203 {
1204 try
1205 {
1206 setterMethod = object.getClass().getMethod( "set" + methodNameSuffix, unboxedPropertyType );
1207 }
1208 catch ( final NoSuchMethodException e )
1209 {
1210 if ( this.isLoggable( Level.FINEST ) )
1211 {
1212 this.log( Level.FINEST, null, e );
1213 }
1214
1215 setterMethod = null;
1216 }
1217 }
1218
1219 if ( setterMethod == null )
1220 {
1221 throw new ModelException( getMessage( "setterMethodNotFound", object.getClass().getName(),
1222 propertyName ) );
1223
1224 }
1225
1226 if ( boxedPropertyType.equals( Character.class ) )
1227 {
1228 if ( propertyValue == null || propertyValue.length() != 1 )
1229 {
1230 throw new ModelException( getMessage( "unsupportedCharacterValue", object.getClass().getName(),
1231 propertyName ) );
1232
1233 }
1234
1235 setterMethod.invoke( object, Character.valueOf( propertyValue.charAt( 0 ) ) );
1236 return;
1237 }
1238
1239 if ( propertyValue != null )
1240 {
1241 if ( boxedPropertyType.equals( String.class ) )
1242 {
1243 setterMethod.invoke( object, propertyValue );
1244 return;
1245 }
1246
1247 try
1248 {
1249 setterMethod.invoke(
1250 object, boxedPropertyType.getConstructor( String.class ).newInstance( propertyValue ) );
1251
1252 return;
1253 }
1254 catch ( final NoSuchMethodException e )
1255 {
1256 if ( this.isLoggable( Level.FINEST ) )
1257 {
1258 this.log( Level.FINEST, null, e );
1259 }
1260 }
1261
1262 try
1263 {
1264 final Method valueOf = boxedPropertyType.getMethod( "valueOf", String.class );
1265
1266 if ( Modifier.isStatic( valueOf.getModifiers() )
1267 && ( valueOf.getReturnType().equals( boxedPropertyType )
1268 || valueOf.getReturnType().equals( unboxedPropertyType ) ) )
1269 {
1270 setterMethod.invoke( object, valueOf.invoke( null, propertyValue ) );
1271 return;
1272 }
1273 }
1274 catch ( final NoSuchMethodException e )
1275 {
1276 if ( this.isLoggable( Level.FINEST ) )
1277 {
1278 this.log( Level.FINEST, null, e );
1279 }
1280 }
1281
1282 throw new ModelException( getMessage( "unsupportedPropertyType", object.getClass().getName(),
1283 propertyName, propertyType.getName() ) );
1284
1285 }
1286 else
1287 {
1288 setterMethod.invoke( object, (Object) null );
1289 }
1290 }
1291 catch ( final IllegalAccessException e )
1292 {
1293 throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
1294 object.getClass().getName() ), e );
1295
1296 }
1297 catch ( final InvocationTargetException e )
1298 {
1299 throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
1300 object.getClass().getName() ), e );
1301
1302 }
1303 catch ( final InstantiationException e )
1304 {
1305 throw new ModelException( getMessage( "failedSettingProperty", propertyName, object.toString(),
1306 object.getClass().getName() ), e );
1307
1308 }
1309 }
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321 private Set<URI> getSchemaResources() throws IOException, URISyntaxException, ModelException
1322 {
1323 Set<URI> resources = this.cachedSchemaResources.get();
1324
1325 if ( resources == null )
1326 {
1327 resources = new HashSet<URI>();
1328 final long t0 = System.currentTimeMillis();
1329 int count = 0;
1330
1331 for ( final Enumeration<URL> e = this.findResources( "META-INF/MANIFEST.MF" );
1332 e.hasMoreElements(); )
1333 {
1334 InputStream manifestStream = null;
1335 boolean suppressExceptionOnClose = true;
1336
1337 try
1338 {
1339 count++;
1340 final URL manifestUrl = e.nextElement();
1341 final String externalForm = manifestUrl.toExternalForm();
1342 final String baseUrl = externalForm.substring( 0, externalForm.indexOf( "META-INF" ) );
1343 manifestStream = manifestUrl.openStream();
1344 final Manifest mf = new Manifest( manifestStream );
1345
1346 if ( this.isLoggable( Level.FINEST ) )
1347 {
1348 this.log( Level.FINEST, getMessage( "processing", externalForm ), null );
1349 }
1350
1351 for ( Map.Entry<String, Attributes> entry : mf.getEntries().entrySet() )
1352 {
1353 for ( int i = SCHEMA_EXTENSIONS.length - 1; i >= 0; i-- )
1354 {
1355 if ( entry.getKey().toLowerCase().endsWith( '.' + SCHEMA_EXTENSIONS[i].toLowerCase() ) )
1356 {
1357 final URL schemaUrl = new URL( baseUrl + entry.getKey() );
1358 resources.add( schemaUrl.toURI() );
1359
1360 if ( this.isLoggable( Level.FINEST ) )
1361 {
1362 this.log( Level.FINEST, getMessage( "foundSchemaCandidate",
1363 schemaUrl.toExternalForm() ), null );
1364
1365 }
1366 }
1367 }
1368 }
1369
1370 suppressExceptionOnClose = false;
1371 }
1372 finally
1373 {
1374 try
1375 {
1376 if ( manifestStream != null )
1377 {
1378 manifestStream.close();
1379 }
1380 }
1381 catch ( final IOException ex )
1382 {
1383 if ( suppressExceptionOnClose )
1384 {
1385 this.log( Level.SEVERE, getMessage( ex ), ex );
1386 }
1387 else
1388 {
1389 throw ex;
1390 }
1391 }
1392 }
1393 }
1394
1395 if ( this.isLoggable( Level.FINE ) )
1396 {
1397 this.log( Level.FINE, getMessage( "contextReport", count, "META-INF/MANIFEST.MF",
1398 Long.valueOf( System.currentTimeMillis() - t0 ) ), null );
1399
1400 }
1401
1402 this.cachedSchemaResources = new SoftReference<Set<URI>>( resources );
1403 }
1404
1405 return resources;
1406 }
1407
1408 private EntityResolver createEntityResolver( final Schemas schemas )
1409 {
1410 return new DefaultHandler()
1411 {
1412
1413 @Override
1414 public InputSource resolveEntity( final String publicId, final String systemId )
1415 throws SAXException, IOException
1416 {
1417 if ( systemId == null )
1418 {
1419 throw new NullPointerException( "systemId" );
1420 }
1421
1422 InputSource schemaSource = null;
1423
1424 try
1425 {
1426 Schema s = null;
1427
1428 if ( schemas != null )
1429 {
1430 s = schemas.getSchemaBySystemId( systemId );
1431
1432 if ( s == null && publicId != null )
1433 {
1434 try
1435 {
1436 final List<Schema> schemasByPublicId =
1437 schemas.getSchemasByPublicId( new URI( publicId ) );
1438
1439 if ( schemasByPublicId.size() == 1 )
1440 {
1441 s = schemasByPublicId.get( 0 );
1442 }
1443 }
1444 catch ( final URISyntaxException e )
1445 {
1446 if ( isLoggable( Level.WARNING ) )
1447 {
1448 log( Level.WARNING, getMessage( "unsupportedIdUri", publicId, getMessage( e ) ),
1449 null );
1450
1451 }
1452
1453 s = null;
1454 }
1455 }
1456 }
1457
1458 if ( s != null )
1459 {
1460 schemaSource = new InputSource();
1461 schemaSource.setPublicId( s.getPublicId() != null ? s.getPublicId() : publicId );
1462 schemaSource.setSystemId( s.getSystemId() );
1463
1464 if ( s.getClasspathId() != null )
1465 {
1466 final URL resource = findResource( s.getClasspathId() );
1467
1468 if ( resource != null )
1469 {
1470 schemaSource.setSystemId( resource.toExternalForm() );
1471 }
1472 else if ( isLoggable( Level.WARNING ) )
1473 {
1474 log( Level.WARNING, getMessage( "resourceNotFound", s.getClasspathId() ), null );
1475 }
1476 }
1477
1478 if ( isLoggable( Level.FINEST ) )
1479 {
1480 log( Level.FINEST, getMessage( "resolutionInfo", publicId + ", " + systemId,
1481 schemaSource.getPublicId() + ", "
1482 + schemaSource.getSystemId() ), null );
1483
1484 }
1485 }
1486
1487 if ( schemaSource == null )
1488 {
1489 final URI systemUri = new URI( systemId );
1490 String schemaName = systemUri.getPath();
1491
1492 if ( schemaName != null )
1493 {
1494 final int lastIndexOfSlash = schemaName.lastIndexOf( '/' );
1495 if ( lastIndexOfSlash != -1 && lastIndexOfSlash < schemaName.length() )
1496 {
1497 schemaName = schemaName.substring( lastIndexOfSlash + 1 );
1498 }
1499
1500 for ( URI uri : getSchemaResources() )
1501 {
1502 if ( uri.getSchemeSpecificPart() != null
1503 && uri.getSchemeSpecificPart().endsWith( schemaName ) )
1504 {
1505 schemaSource = new InputSource();
1506 schemaSource.setPublicId( publicId );
1507 schemaSource.setSystemId( uri.toASCIIString() );
1508
1509 if ( isLoggable( Level.FINEST ) )
1510 {
1511 log( Level.FINEST, getMessage( "resolutionInfo", systemUri.toASCIIString(),
1512 schemaSource.getSystemId() ), null );
1513
1514 }
1515
1516 break;
1517 }
1518 }
1519 }
1520 else
1521 {
1522 if ( isLoggable( Level.WARNING ) )
1523 {
1524 log( Level.WARNING, getMessage( "unsupportedIdUri", systemId,
1525 systemUri.toASCIIString() ), null );
1526
1527 }
1528
1529 schemaSource = null;
1530 }
1531 }
1532 }
1533 catch ( final URISyntaxException e )
1534 {
1535 if ( isLoggable( Level.WARNING ) )
1536 {
1537 log( Level.WARNING, getMessage( "unsupportedIdUri", systemId, getMessage( e ) ), null );
1538 }
1539
1540 schemaSource = null;
1541 }
1542 catch ( final ModelException e )
1543 {
1544 String message = getMessage( e );
1545 if ( message == null )
1546 {
1547 message = "";
1548 }
1549 else if ( message.length() > 0 )
1550 {
1551 message = " " + message;
1552 }
1553
1554 String resource = "";
1555 if ( publicId != null )
1556 {
1557 resource = publicId + ", ";
1558 }
1559 resource += systemId;
1560
1561
1562 throw (IOException) new IOException( getMessage(
1563 "failedResolving", resource, message ) ).initCause( e );
1564
1565 }
1566
1567 return schemaSource;
1568 }
1569
1570 };
1571 }
1572
1573 private LSResourceResolver createResourceResolver( final EntityResolver entityResolver )
1574 {
1575 if ( entityResolver == null )
1576 {
1577 throw new NullPointerException( "entityResolver" );
1578 }
1579
1580 return new LSResourceResolver()
1581 {
1582
1583 public LSInput resolveResource( final String type, final String namespaceURI, final String publicId,
1584 final String systemId, final String baseURI )
1585 {
1586 final String resolvePublicId = namespaceURI == null ? publicId : namespaceURI;
1587 final String resolveSystemId = systemId == null ? "" : systemId;
1588
1589 try
1590 {
1591 if ( XMLConstants.W3C_XML_SCHEMA_NS_URI.equals( type ) )
1592 {
1593 final InputSource schemaSource =
1594 entityResolver.resolveEntity( resolvePublicId, resolveSystemId );
1595
1596 if ( schemaSource != null )
1597 {
1598 return new LSInput()
1599 {
1600
1601 public Reader getCharacterStream()
1602 {
1603 return schemaSource.getCharacterStream();
1604 }
1605
1606 public void setCharacterStream( final Reader characterStream )
1607 {
1608 if ( isLoggable( Level.WARNING ) )
1609 {
1610 log( Level.WARNING, getMessage(
1611 "unsupportedOperation", "setCharacterStream",
1612 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1613
1614 }
1615 }
1616
1617 public InputStream getByteStream()
1618 {
1619 return schemaSource.getByteStream();
1620 }
1621
1622 public void setByteStream( final InputStream byteStream )
1623 {
1624 if ( isLoggable( Level.WARNING ) )
1625 {
1626 log( Level.WARNING, getMessage(
1627 "unsupportedOperation", "setByteStream",
1628 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1629
1630 }
1631 }
1632
1633 public String getStringData()
1634 {
1635 return null;
1636 }
1637
1638 public void setStringData( final String stringData )
1639 {
1640 if ( isLoggable( Level.WARNING ) )
1641 {
1642 log( Level.WARNING, getMessage(
1643 "unsupportedOperation", "setStringData",
1644 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1645
1646 }
1647 }
1648
1649 public String getSystemId()
1650 {
1651 return schemaSource.getSystemId();
1652 }
1653
1654 public void setSystemId( final String systemId )
1655 {
1656 if ( isLoggable( Level.WARNING ) )
1657 {
1658 log( Level.WARNING, getMessage(
1659 "unsupportedOperation", "setSystemId",
1660 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1661
1662 }
1663 }
1664
1665 public String getPublicId()
1666 {
1667 return schemaSource.getPublicId();
1668 }
1669
1670 public void setPublicId( final String publicId )
1671 {
1672 if ( isLoggable( Level.WARNING ) )
1673 {
1674 log( Level.WARNING, getMessage(
1675 "unsupportedOperation", "setPublicId",
1676 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1677
1678 }
1679 }
1680
1681 public String getBaseURI()
1682 {
1683 return baseURI;
1684 }
1685
1686 public void setBaseURI( final String baseURI )
1687 {
1688 if ( isLoggable( Level.WARNING ) )
1689 {
1690 log( Level.WARNING, getMessage(
1691 "unsupportedOperation", "setBaseURI",
1692 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1693
1694 }
1695 }
1696
1697 public String getEncoding()
1698 {
1699 return schemaSource.getEncoding();
1700 }
1701
1702 public void setEncoding( final String encoding )
1703 {
1704 if ( isLoggable( Level.WARNING ) )
1705 {
1706 log( Level.WARNING, getMessage(
1707 "unsupportedOperation", "setEncoding",
1708 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1709
1710 }
1711 }
1712
1713 public boolean getCertifiedText()
1714 {
1715 return false;
1716 }
1717
1718 public void setCertifiedText( final boolean certifiedText )
1719 {
1720 if ( isLoggable( Level.WARNING ) )
1721 {
1722 log( Level.WARNING, getMessage(
1723 "unsupportedOperation", "setCertifiedText",
1724 DefaultModelContext.class.getName() + ".LSResourceResolver" ), null );
1725
1726 }
1727 }
1728
1729 };
1730 }
1731
1732 }
1733 else if ( isLoggable( Level.WARNING ) )
1734 {
1735 log( Level.WARNING, getMessage( "unsupportedResourceType", type ), null );
1736 }
1737 }
1738 catch ( final SAXException e )
1739 {
1740 String message = getMessage( e );
1741 if ( message == null && e.getException() != null )
1742 {
1743 message = getMessage( e.getException() );
1744 }
1745 if ( message == null )
1746 {
1747 message = "";
1748 }
1749 else if ( message.length() > 0 )
1750 {
1751 message = " " + message;
1752 }
1753
1754 String resource = "";
1755 if ( resolvePublicId != null )
1756 {
1757 resource = resolvePublicId + ", ";
1758 }
1759 resource += resolveSystemId;
1760
1761 if ( isLoggable( Level.SEVERE ) )
1762 {
1763 log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e );
1764 }
1765 }
1766 catch ( final IOException e )
1767 {
1768 String message = getMessage( e );
1769 if ( message == null )
1770 {
1771 message = "";
1772 }
1773 else if ( message.length() > 0 )
1774 {
1775 message = " " + message;
1776 }
1777
1778 String resource = "";
1779 if ( resolvePublicId != null )
1780 {
1781 resource = resolvePublicId + ", ";
1782 }
1783 resource += resolveSystemId;
1784
1785 if ( isLoggable( Level.SEVERE ) )
1786 {
1787 log( Level.SEVERE, getMessage( "failedResolving", resource, message ), e );
1788 }
1789 }
1790
1791 return null;
1792 }
1793
1794 };
1795 }
1796
1797 private javax.xml.validation.Schema createSchema( final Schemas schemas, final EntityResolver entityResolver,
1798 final LSResourceResolver resourceResolver, final String model,
1799 final URI publicId ) throws ModelException
1800 {
1801 if ( entityResolver == null )
1802 {
1803 throw new NullPointerException( "entityResolver" );
1804 }
1805 if ( model != null && publicId != null )
1806 {
1807 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
1808 }
1809
1810 try
1811 {
1812 final SchemaFactory f = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
1813 final List<Source> sources = new ArrayList<Source>( schemas != null ? schemas.getSchema().size() : 0 );
1814
1815 if ( schemas != null )
1816 {
1817 for ( Schema s : schemas.getSchema() )
1818 {
1819 final InputSource inputSource = entityResolver.resolveEntity( s.getPublicId(), s.getSystemId() );
1820
1821 if ( inputSource != null )
1822 {
1823 sources.add( new SAXSource( inputSource ) );
1824 }
1825 }
1826 }
1827
1828 if ( sources.isEmpty() )
1829 {
1830 if ( model != null )
1831 {
1832 throw new ModelException( getMessage( "missingSchemasForModel", model ) );
1833 }
1834 if ( publicId != null )
1835 {
1836 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
1837 }
1838 }
1839
1840 f.setResourceResolver( resourceResolver );
1841 f.setErrorHandler( new ErrorHandler()
1842 {
1843
1844
1845 public void warning( final SAXParseException e ) throws SAXException
1846 {
1847 String message = getMessage( e );
1848 if ( message == null && e.getException() != null )
1849 {
1850 message = getMessage( e.getException() );
1851 }
1852
1853 if ( isLoggable( Level.WARNING ) )
1854 {
1855 log( Level.WARNING, message, e );
1856 }
1857 }
1858
1859 public void error( final SAXParseException e ) throws SAXException
1860 {
1861 throw e;
1862 }
1863
1864 public void fatalError( final SAXParseException e ) throws SAXException
1865 {
1866 throw e;
1867 }
1868
1869 } );
1870
1871 if ( this.isLoggable( Level.FINEST ) )
1872 {
1873 final StringBuilder schemaInfo = new StringBuilder( sources.size() * 50 );
1874
1875 for ( Source s : sources )
1876 {
1877 schemaInfo.append( ", " ).append( s.getSystemId() );
1878 }
1879
1880 this.log( Level.FINEST, getMessage( "creatingSchema", schemaInfo.substring( 2 ) ), null );
1881 }
1882
1883 return f.newSchema( sources.toArray( new Source[ sources.size() ] ) );
1884 }
1885 catch ( final IOException e )
1886 {
1887 throw new ModelException( getMessage( e ), e );
1888 }
1889 catch ( final SAXException e )
1890 {
1891 String message = getMessage( e );
1892 if ( message == null && e.getException() != null )
1893 {
1894 message = getMessage( e.getException() );
1895 }
1896
1897 throw new ModelException( message, e );
1898 }
1899 }
1900
1901 private JAXBContext createContext( final Schemas schemas, final String model, final URI publicId )
1902 throws ModelException
1903 {
1904 if ( model != null && publicId != null )
1905 {
1906 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
1907 }
1908
1909 try
1910 {
1911 StringBuilder packageNames = null;
1912
1913 if ( schemas != null )
1914 {
1915 packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
1916
1917 for ( Schema schema : schemas.getSchema() )
1918 {
1919 if ( schema.getContextId() != null )
1920 {
1921 packageNames.append( ':' ).append( schema.getContextId() );
1922 }
1923 }
1924 }
1925
1926 if ( packageNames == null || packageNames.length() == 0 )
1927 {
1928 if ( model != null )
1929 {
1930 throw new ModelException( getMessage( "missingSchemasForModel", model ) );
1931 }
1932 if ( publicId != null )
1933 {
1934 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
1935 }
1936 }
1937
1938 if ( this.isLoggable( Level.FINEST ) )
1939 {
1940 this.log( Level.FINEST, getMessage( "creatingContext", packageNames.substring( 1 ) ), null );
1941 }
1942
1943 return JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() );
1944 }
1945 catch ( final JAXBException e )
1946 {
1947 String message = getMessage( e );
1948 if ( message == null && e.getLinkedException() != null )
1949 {
1950 message = getMessage( e.getLinkedException() );
1951 }
1952
1953 throw new ModelException( message, e );
1954 }
1955 }
1956
1957 private Marshaller createMarshaller( final Schemas schemas, final Services services, final String model,
1958 final URI publicId ) throws ModelException
1959 {
1960 if ( model != null && publicId != null )
1961 {
1962 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
1963 }
1964
1965 try
1966 {
1967 StringBuilder packageNames = null;
1968 StringBuilder schemaLocation = null;
1969
1970 if ( schemas != null )
1971 {
1972 packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
1973 schemaLocation = new StringBuilder( schemas.getSchema().size() * 50 );
1974
1975 for ( Schema schema : schemas.getSchema() )
1976 {
1977 if ( schema.getContextId() != null )
1978 {
1979 packageNames.append( ':' ).append( schema.getContextId() );
1980 }
1981 if ( schema.getPublicId() != null && schema.getSystemId() != null )
1982 {
1983 schemaLocation.append( ' ' ).append( schema.getPublicId() ).append( ' ' ).
1984 append( schema.getSystemId() );
1985
1986 }
1987 }
1988 }
1989
1990 if ( packageNames == null || packageNames.length() == 0 )
1991 {
1992 if ( model != null )
1993 {
1994 throw new ModelException( getMessage( "missingSchemasForModel", model ) );
1995 }
1996 if ( publicId != null )
1997 {
1998 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
1999 }
2000 }
2001
2002 final Marshaller m =
2003 JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createMarshaller();
2004
2005 if ( schemaLocation != null && schemaLocation.length() != 0 )
2006 {
2007 m.setProperty( Marshaller.JAXB_SCHEMA_LOCATION, schemaLocation.substring( 1 ) );
2008 }
2009
2010 MarshallerListenerList listenerList = null;
2011
2012 if ( services != null )
2013 {
2014 for ( Service service : services.getServices( MARSHALLER_LISTENER_SERVICE ) )
2015 {
2016 if ( listenerList == null )
2017 {
2018 listenerList = new MarshallerListenerList();
2019 }
2020
2021 listenerList.getListeners().add( this.createServiceObject( service, Marshaller.Listener.class ) );
2022 }
2023 }
2024
2025 if ( listenerList != null )
2026 {
2027 m.setListener( listenerList );
2028 }
2029
2030 if ( this.isLoggable( Level.FINEST ) )
2031 {
2032 if ( listenerList == null )
2033 {
2034 this.log( Level.FINEST, getMessage( "creatingMarshaller", packageNames.substring( 1 ),
2035 schemaLocation.substring( 1 ) ), null );
2036
2037 }
2038 else
2039 {
2040 final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 );
2041
2042 for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ )
2043 {
2044 b.append( ',' ).append( listenerList.getListeners().get( i ) );
2045 }
2046
2047 this.log( Level.FINEST, getMessage( "creatingMarshallerWithListeners", packageNames.substring( 1 ),
2048 schemaLocation.substring( 1 ), b.substring( 1 ) ), null );
2049
2050 }
2051 }
2052
2053 return m;
2054 }
2055 catch ( final JAXBException e )
2056 {
2057 String message = getMessage( e );
2058 if ( message == null && e.getLinkedException() != null )
2059 {
2060 message = getMessage( e.getLinkedException() );
2061 }
2062
2063 throw new ModelException( message, e );
2064 }
2065 }
2066
2067 private Unmarshaller createUnmarshaller( final Schemas schemas, final Services services, final String model,
2068 final URI publicId ) throws ModelException
2069 {
2070 if ( model != null && publicId != null )
2071 {
2072 throw new IllegalArgumentException( "model=" + model + ", publicId=" + publicId.toASCIIString() );
2073 }
2074
2075 try
2076 {
2077 StringBuilder packageNames = null;
2078
2079 if ( schemas != null )
2080 {
2081 packageNames = new StringBuilder( schemas.getSchema().size() * 25 );
2082
2083 for ( Schema schema : schemas.getSchema() )
2084 {
2085 if ( schema.getContextId() != null )
2086 {
2087 packageNames.append( ':' ).append( schema.getContextId() );
2088 }
2089 }
2090 }
2091
2092 if ( packageNames == null || packageNames.length() == 0 )
2093 {
2094 if ( model != null )
2095 {
2096 throw new ModelException( getMessage( "missingSchemasForModel", model ) );
2097 }
2098 if ( publicId != null )
2099 {
2100 throw new ModelException( getMessage( "missingSchemasForPublicId", publicId ) );
2101 }
2102 }
2103
2104 final Unmarshaller u =
2105 JAXBContext.newInstance( packageNames.substring( 1 ), this.getClassLoader() ).createUnmarshaller();
2106
2107 UnmarshallerListenerList listenerList = null;
2108
2109 if ( services != null )
2110 {
2111 for ( Service service : services.getServices( UNMARSHALLER_LISTENER_SERVICE ) )
2112 {
2113 if ( listenerList == null )
2114 {
2115 listenerList = new UnmarshallerListenerList();
2116 }
2117
2118 listenerList.getListeners().add( this.createServiceObject( service, Unmarshaller.Listener.class ) );
2119 }
2120 }
2121
2122 if ( listenerList != null )
2123 {
2124 u.setListener( listenerList );
2125 }
2126
2127 if ( this.isLoggable( Level.FINEST ) )
2128 {
2129 if ( listenerList == null )
2130 {
2131 this.log( Level.FINEST,
2132 getMessage( "creatingUnmarshaller", packageNames.substring( 1 ) ), null );
2133
2134 }
2135 else
2136 {
2137 final StringBuilder b = new StringBuilder( listenerList.getListeners().size() * 100 );
2138
2139 for ( int i = 0, s0 = listenerList.getListeners().size(); i < s0; i++ )
2140 {
2141 b.append( ',' ).append( listenerList.getListeners().get( i ) );
2142 }
2143
2144 this.log( Level.FINEST, getMessage( "creatingUnmarshallerWithListeners",
2145 packageNames.substring( 1 ), b.substring( 1 ) ), null );
2146
2147 }
2148 }
2149
2150 return u;
2151 }
2152 catch ( final JAXBException e )
2153 {
2154 String message = getMessage( e );
2155 if ( message == null && e.getLinkedException() != null )
2156 {
2157 message = getMessage( e.getLinkedException() );
2158 }
2159
2160 throw new ModelException( message, e );
2161 }
2162 }
2163
2164 private static String getMessage( final String key, final Object... arguments )
2165 {
2166 return MessageFormat.format( ResourceBundle.getBundle(
2167 DefaultModelContext.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
2168
2169 }
2170
2171 private static String getMessage( final Throwable t )
2172 {
2173 return t != null ? t.getMessage() != null ? t.getMessage() : getMessage( t.getCause() ) : null;
2174 }
2175
2176 }
2177
2178
2179
2180
2181
2182
2183
2184 class ModelErrorHandler extends DefaultHandler
2185 {
2186
2187
2188 private ModelContext context;
2189
2190
2191 private ModelValidationReport report;
2192
2193
2194
2195
2196
2197
2198 ModelErrorHandler( final ModelContext context )
2199 {
2200 this( context, null );
2201 }
2202
2203
2204
2205
2206
2207
2208
2209 ModelErrorHandler( final ModelContext context, final ModelValidationReport report )
2210 {
2211 super();
2212 this.context = context;
2213 this.report = report;
2214 }
2215
2216
2217
2218
2219
2220
2221 public ModelValidationReport getReport()
2222 {
2223 if ( this.report == null )
2224 {
2225 this.report = new ModelValidationReport();
2226 }
2227
2228 return this.report;
2229 }
2230
2231 @Override
2232 public void warning( final SAXParseException exception ) throws SAXException
2233 {
2234 String message = getMessage( exception );
2235 if ( message == null && exception.getException() != null )
2236 {
2237 message = getMessage( exception.getException() );
2238 }
2239
2240 if ( this.context != null && this.context.isLoggable( Level.FINE ) )
2241 {
2242 this.context.log( Level.FINE, message, exception );
2243 }
2244
2245 this.getReport().getDetails().add( new ModelValidationReport.Detail(
2246 "W3C XML 1.0 Recommendation - Warning condition", Level.WARNING, message, null ) );
2247
2248 }
2249
2250 @Override
2251 public void error( final SAXParseException exception ) throws SAXException
2252 {
2253 String message = getMessage( exception );
2254 if ( message == null && exception.getException() != null )
2255 {
2256 message = getMessage( exception.getException() );
2257 }
2258
2259 if ( this.context != null && this.context.isLoggable( Level.FINE ) )
2260 {
2261 this.context.log( Level.FINE, message, exception );
2262 }
2263
2264 this.getReport().getDetails().add( new ModelValidationReport.Detail(
2265 "W3C XML 1.0 Recommendation - Section 1.2 - Error", Level.SEVERE, message, null ) );
2266
2267 }
2268
2269 @Override
2270 public void fatalError( final SAXParseException exception ) throws SAXException
2271 {
2272 String message = getMessage( exception );
2273 if ( message == null && exception.getException() != null )
2274 {
2275 message = getMessage( exception.getException() );
2276 }
2277
2278 if ( this.context != null && this.context.isLoggable( Level.FINE ) )
2279 {
2280 this.context.log( Level.FINE, message, exception );
2281 }
2282
2283 this.getReport().getDetails().add( new ModelValidationReport.Detail(
2284 "W3C XML 1.0 Recommendation - Section 1.2 - Fatal Error", Level.SEVERE, message, null ) );
2285
2286 }
2287
2288 private static String getMessage( final Throwable t )
2289 {
2290 return t != null ? t.getMessage() != null ? t.getMessage() : getMessage( t.getCause() ) : null;
2291 }
2292
2293 }
2294
2295
2296
2297
2298
2299
2300
2301
2302 class MarshallerListenerList extends Marshaller.Listener
2303 {
2304
2305
2306 private List<Marshaller.Listener> listeners;
2307
2308
2309 MarshallerListenerList()
2310 {
2311 super();
2312 }
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322 List<Marshaller.Listener> getListeners()
2323 {
2324 if ( this.listeners == null )
2325 {
2326 this.listeners = new ArrayList<Marshaller.Listener>();
2327 }
2328
2329 return this.listeners;
2330 }
2331
2332 @Override
2333 public void beforeMarshal( final Object source )
2334 {
2335 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2336 {
2337 this.getListeners().get( i ).beforeMarshal( source );
2338 }
2339 }
2340
2341 @Override
2342 public void afterMarshal( final Object source )
2343 {
2344 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2345 {
2346 this.getListeners().get( i ).afterMarshal( source );
2347 }
2348 }
2349
2350 }
2351
2352
2353
2354
2355
2356
2357
2358
2359 class UnmarshallerListenerList extends Unmarshaller.Listener
2360 {
2361
2362
2363 private List<Unmarshaller.Listener> listeners;
2364
2365
2366 UnmarshallerListenerList()
2367 {
2368 super();
2369 }
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379 List<Unmarshaller.Listener> getListeners()
2380 {
2381 if ( this.listeners == null )
2382 {
2383 this.listeners = new ArrayList<Unmarshaller.Listener>();
2384 }
2385
2386 return this.listeners;
2387 }
2388
2389 @Override
2390 public void beforeUnmarshal( final Object target, final Object parent )
2391 {
2392 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2393 {
2394 this.getListeners().get( i ).beforeUnmarshal( target, parent );
2395 }
2396 }
2397
2398 @Override
2399 public void afterUnmarshal( final Object target, final Object parent )
2400 {
2401 for ( int i = 0, s0 = this.getListeners().size(); i < s0; i++ )
2402 {
2403 this.getListeners().get( i ).afterUnmarshal( target, parent );
2404 }
2405 }
2406
2407 }