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.ByteArrayInputStream;
34 import java.io.ByteArrayOutputStream;
35 import java.io.IOException;
36 import java.lang.reflect.UndeclaredThrowableException;
37 import java.net.URI;
38 import java.net.URISyntaxException;
39 import java.net.URL;
40 import java.text.MessageFormat;
41 import java.util.ArrayList;
42 import java.util.Enumeration;
43 import java.util.HashSet;
44 import java.util.LinkedList;
45 import java.util.List;
46 import java.util.Locale;
47 import java.util.Map;
48 import java.util.Properties;
49 import java.util.ResourceBundle;
50 import java.util.Set;
51 import java.util.concurrent.Callable;
52 import java.util.concurrent.CancellationException;
53 import java.util.concurrent.ExecutionException;
54 import java.util.concurrent.Future;
55 import java.util.logging.Level;
56 import javax.xml.bind.JAXBContext;
57 import javax.xml.bind.JAXBElement;
58 import javax.xml.bind.JAXBException;
59 import javax.xml.bind.util.JAXBResult;
60 import javax.xml.bind.util.JAXBSource;
61 import javax.xml.transform.ErrorListener;
62 import javax.xml.transform.Transformer;
63 import javax.xml.transform.TransformerConfigurationException;
64 import javax.xml.transform.TransformerException;
65 import javax.xml.transform.TransformerFactory;
66 import javax.xml.transform.stream.StreamSource;
67
68
69
70
71
72
73
74
75
76 public class DefaultModletProcessor implements ModletProcessor
77 {
78
79
80
81
82
83
84
85 public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.modlet.DefaultModletProcessor.enabledAttribute";
86
87
88
89
90
91
92 private static final String DEFAULT_ENABLED_PROPERTY_NAME =
93 "org.jomc.modlet.DefaultModletProcessor.defaultEnabled";
94
95
96
97
98
99
100 private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;
101
102
103
104
105 private static volatile Boolean defaultEnabled;
106
107
108
109
110 private volatile Boolean enabled;
111
112
113
114
115
116
117 private static final String DEFAULT_ORDINAL_PROPERTY_NAME =
118 "org.jomc.modlet.DefaultModletProcessor.defaultOrdinal";
119
120
121
122
123
124
125 private static final Integer DEFAULT_ORDINAL = 0;
126
127
128
129
130 private static volatile Integer defaultOrdinal;
131
132
133
134
135 private volatile Integer ordinal;
136
137
138
139
140
141
142
143
144 public static final String TRANSFORMER_LOCATION_ATTRIBUTE_NAME =
145 "org.jomc.modlet.DefaultModletProcessor.transformerLocationAttribute";
146
147
148
149
150
151
152 private static final String DEFAULT_TRANSFORMER_LOCATION_PROPERTY_NAME =
153 "org.jomc.modlet.DefaultModletProcessor.defaultTransformerLocation";
154
155
156
157
158
159
160 private static final String DEFAULT_TRANSFORMER_LOCATION = "META-INF/jomc-modlet.xsl";
161
162
163
164
165 private static volatile String defaultTransformerLocation;
166
167
168
169
170 private volatile String transformerLocation;
171
172
173
174
175 public DefaultModletProcessor()
176 {
177 super();
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 public static boolean isDefaultEnabled()
195 {
196 if ( defaultEnabled == null )
197 {
198 defaultEnabled = Boolean.valueOf( System.getProperty(
199 DEFAULT_ENABLED_PROPERTY_NAME, Boolean.toString( DEFAULT_ENABLED ) ) );
200
201 }
202
203 return defaultEnabled;
204 }
205
206
207
208
209
210
211
212
213 public static void setDefaultEnabled( final Boolean value )
214 {
215 defaultEnabled = value;
216 }
217
218
219
220
221
222
223
224
225
226 public final boolean isEnabled()
227 {
228 if ( this.enabled == null )
229 {
230 this.enabled = isDefaultEnabled();
231 }
232
233 return this.enabled;
234 }
235
236
237
238
239
240
241
242
243 public final void setEnabled( final Boolean value )
244 {
245 this.enabled = value;
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260 public static int getDefaultOrdinal()
261 {
262 if ( defaultOrdinal == null )
263 {
264 defaultOrdinal = Integer.getInteger( DEFAULT_ORDINAL_PROPERTY_NAME, DEFAULT_ORDINAL );
265 }
266
267 return defaultOrdinal;
268 }
269
270
271
272
273
274
275
276
277 public static void setDefaultOrdinal( final Integer value )
278 {
279 defaultOrdinal = value;
280 }
281
282
283
284
285
286
287
288
289
290 public final int getOrdinal()
291 {
292 if ( this.ordinal == null )
293 {
294 this.ordinal = getDefaultOrdinal();
295 }
296
297 return this.ordinal;
298 }
299
300
301
302
303
304
305
306
307 public final void setOrdinal( final Integer value )
308 {
309 this.ordinal = value;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 public static String getDefaultTransformerLocation()
326 {
327 if ( defaultTransformerLocation == null )
328 {
329 defaultTransformerLocation =
330 System.getProperty( DEFAULT_TRANSFORMER_LOCATION_PROPERTY_NAME, DEFAULT_TRANSFORMER_LOCATION );
331
332 }
333
334 return defaultTransformerLocation;
335 }
336
337
338
339
340
341
342
343
344 public static void setDefaultTransformerLocation( final String value )
345 {
346 defaultTransformerLocation = value;
347 }
348
349
350
351
352
353
354
355
356
357 public final String getTransformerLocation()
358 {
359 if ( this.transformerLocation == null )
360 {
361 this.transformerLocation = getDefaultTransformerLocation();
362 }
363
364 return this.transformerLocation;
365 }
366
367
368
369
370
371
372
373
374 public final void setTransformerLocation( final String value )
375 {
376 this.transformerLocation = value;
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390
391 public List<Transformer> findTransformers( final ModelContext context, final String location ) throws ModelException
392 {
393 if ( context == null )
394 {
395 throw new NullPointerException( "context" );
396 }
397 if ( location == null )
398 {
399 throw new NullPointerException( "location" );
400 }
401
402 try
403 {
404 final long t0 = System.nanoTime();
405 final List<Transformer> transformers = new LinkedList<Transformer>();
406 final Enumeration<URL> transformerResourceEnumeration = context.findResources( location );
407 final Set<URI> transformerResources = new HashSet<URI>();
408 while ( transformerResourceEnumeration.hasMoreElements() )
409 {
410 transformerResources.add( transformerResourceEnumeration.nextElement().toURI() );
411 }
412
413 if ( !transformerResources.isEmpty() )
414 {
415 final ErrorListener errorListener = new ErrorListener()
416 {
417
418 public void warning( final TransformerException exception ) throws TransformerException
419 {
420 if ( context.isLoggable( Level.WARNING ) )
421 {
422 context.log( Level.WARNING, getMessage( exception ), exception );
423 }
424 }
425
426 public void error( final TransformerException exception ) throws TransformerException
427 {
428 if ( context.isLoggable( Level.SEVERE ) )
429 {
430 context.log( Level.SEVERE, getMessage( exception ), exception );
431 }
432
433 throw exception;
434 }
435
436 public void fatalError( final TransformerException exception ) throws TransformerException
437 {
438 if ( context.isLoggable( Level.SEVERE ) )
439 {
440 context.log( Level.SEVERE, getMessage( exception ), exception );
441 }
442
443 throw exception;
444 }
445
446 };
447
448 final Properties transformerParameters = this.getTransformerParameters( context );
449
450 if ( context.getExecutorService() != null && transformerResources.size() > 1 )
451 {
452 final ThreadLocal<TransformerFactory> threadLocalTransformerFactory =
453 new ThreadLocal<TransformerFactory>();
454
455 final List<Callable<Transformer>> tasks =
456 new ArrayList<Callable<Transformer>>( transformerResources.size() );
457
458 for ( final URI transformerResource : transformerResources )
459 {
460 tasks.add( new Callable<Transformer>()
461 {
462
463 public Transformer call() throws TransformerConfigurationException, URISyntaxException
464 {
465 TransformerFactory transformerFactory = threadLocalTransformerFactory.get();
466 if ( transformerFactory == null )
467 {
468 transformerFactory = TransformerFactory.newInstance();
469 threadLocalTransformerFactory.set( transformerFactory );
470 }
471
472 return createTransformer( context, transformerFactory, transformerParameters,
473 transformerResource );
474
475 }
476
477 } );
478 }
479
480 for ( final Future<Transformer> task : context.getExecutorService().invokeAll( tasks ) )
481 {
482 transformers.add( task.get() );
483 }
484 }
485 else
486 {
487 final TransformerFactory transformerFactory = TransformerFactory.newInstance();
488 transformerFactory.setErrorListener( errorListener );
489
490 for ( final URI transformerResource : transformerResources )
491 {
492 transformers.add( this.createTransformer( context, transformerFactory, transformerParameters,
493 transformerResource ) );
494
495 }
496 }
497 }
498
499 if ( context.isLoggable( Level.FINE ) )
500 {
501 context.log( Level.FINE, getMessage( "contextReport", transformerResources.size(), location,
502 System.nanoTime() - t0 ), null );
503
504 }
505
506 return transformers.isEmpty() ? null : transformers;
507 }
508 catch ( final CancellationException e )
509 {
510 throw new ModelException( getMessage( e ), e );
511 }
512 catch ( final InterruptedException e )
513 {
514 throw new ModelException( getMessage( e ), e );
515 }
516 catch ( final IOException e )
517 {
518 throw new ModelException( getMessage( e ), e );
519 }
520 catch ( final URISyntaxException e )
521 {
522 throw new ModelException( getMessage( e ), e );
523 }
524 catch ( final TransformerConfigurationException e )
525 {
526 String message = getMessage( e );
527 if ( message == null && e.getException() != null )
528 {
529 message = getMessage( e.getException() );
530 }
531
532 throw new ModelException( message, e );
533 }
534 catch ( final ExecutionException e )
535 {
536 if ( e.getCause() instanceof URISyntaxException )
537 {
538 throw new ModelException( getMessage( e.getCause() ), e.getCause() );
539 }
540 else if ( e.getCause() instanceof TransformerConfigurationException )
541 {
542 String message = getMessage( e.getCause() );
543 if ( message == null && ( (TransformerConfigurationException) e.getCause() ).getException() != null )
544 {
545 message = getMessage( ( (TransformerConfigurationException) e.getCause() ).getException() );
546 }
547
548 throw new ModelException( message, e.getCause() );
549 }
550 else if ( e.getCause() instanceof RuntimeException )
551 {
552
553
554 if ( e.getCause().getCause() instanceof TransformerConfigurationException )
555 {
556 String message = getMessage( e.getCause().getCause() );
557 if ( message == null
558 && ( (TransformerConfigurationException) e.getCause().getCause() ).getException() != null )
559 {
560 message = getMessage( ( (TransformerConfigurationException) e.getCause().getCause() ).
561 getException() );
562
563 }
564
565 throw new ModelException( message, e.getCause().getCause() );
566 }
567 else if ( e.getCause().getCause() instanceof URISyntaxException )
568 {
569 throw new ModelException( getMessage( e.getCause().getCause() ), e.getCause().getCause() );
570 }
571 else if ( e.getCause().getCause() instanceof RuntimeException )
572 {
573 throw (RuntimeException) e.getCause().getCause();
574 }
575 else if ( e.getCause().getCause() instanceof Error )
576 {
577 throw (Error) e.getCause().getCause();
578 }
579 else if ( e.getCause().getCause() instanceof Exception )
580 {
581
582 throw new UndeclaredThrowableException( e.getCause().getCause() );
583 }
584 else
585 {
586 throw (RuntimeException) e.getCause();
587 }
588 }
589 else if ( e.getCause() instanceof Error )
590 {
591 throw (Error) e.getCause();
592 }
593 else
594 {
595
596 throw new UndeclaredThrowableException( e.getCause() );
597 }
598 }
599 }
600
601
602
603
604
605
606
607
608
609
610 public Modlets processModlets( final ModelContext context, final Modlets modlets ) throws ModelException
611 {
612 if ( context == null )
613 {
614 throw new NullPointerException( "context" );
615 }
616 if ( modlets == null )
617 {
618 throw new NullPointerException( "modlets" );
619 }
620
621 try
622 {
623 Modlets processed = null;
624
625 boolean contextEnabled = this.isEnabled();
626 if ( DEFAULT_ENABLED == contextEnabled
627 && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
628 {
629 contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME );
630 }
631
632 String contextTransformerLocation = this.getTransformerLocation();
633 if ( DEFAULT_TRANSFORMER_LOCATION.equals( contextTransformerLocation )
634 && context.getAttribute( TRANSFORMER_LOCATION_ATTRIBUTE_NAME ) instanceof String )
635 {
636 contextTransformerLocation = (String) context.getAttribute( TRANSFORMER_LOCATION_ATTRIBUTE_NAME );
637 }
638
639 if ( contextEnabled )
640 {
641 final org.jomc.modlet.ObjectFactory objectFactory = new org.jomc.modlet.ObjectFactory();
642 final JAXBContext jaxbContext = context.createContext( ModletObject.MODEL_PUBLIC_ID );
643 final List<Transformer> transformers = this.findTransformers( context, contextTransformerLocation );
644
645 if ( transformers != null )
646 {
647 processed = modlets.clone();
648
649 for ( int i = 0, s0 = transformers.size(); i < s0; i++ )
650 {
651 final JAXBElement<Modlets> e = objectFactory.createModlets( processed );
652 final JAXBSource source = new JAXBSource( jaxbContext, e );
653 final JAXBResult result = new JAXBResult( jaxbContext );
654 transformers.get( i ).transform( source, result );
655
656 if ( result.getResult() instanceof JAXBElement<?>
657 && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Modlets )
658 {
659 processed = (Modlets) ( (JAXBElement<?>) result.getResult() ).getValue();
660 }
661 else
662 {
663 throw new ModelException( getMessage( "illegalTransformationResult" ) );
664 }
665 }
666 }
667 }
668 else if ( context.isLoggable( Level.FINER ) )
669 {
670 context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName() ), null );
671 }
672
673 return processed;
674 }
675 catch ( final TransformerException e )
676 {
677 String message = getMessage( e );
678 if ( message == null && e.getException() != null )
679 {
680 message = getMessage( e.getException() );
681 }
682
683 throw new ModelException( message, e );
684 }
685 catch ( final JAXBException e )
686 {
687 String message = getMessage( e );
688 if ( message == null && e.getLinkedException() != null )
689 {
690 message = getMessage( e.getLinkedException() );
691 }
692
693 throw new ModelException( message, e );
694 }
695 }
696
697 private Transformer createTransformer( final ModelContext context, final TransformerFactory transformerFactory,
698 final Map<Object, Object> parameters, final URI transformerResource )
699 throws TransformerConfigurationException, URISyntaxException
700 {
701 if ( context.isLoggable( Level.FINEST ) )
702 {
703 context.log( Level.FINEST, getMessage( "processing", transformerResource.toString() ), null );
704 }
705
706 final Transformer transformer =
707 transformerFactory.newTransformer( new StreamSource( transformerResource.toASCIIString() ) );
708
709 transformer.setErrorListener( transformerFactory.getErrorListener() );
710
711 for ( final Map.Entry<Object, Object> e : parameters.entrySet() )
712 {
713 transformer.setParameter( e.getKey().toString(), e.getValue() );
714 }
715
716 return transformer;
717 }
718
719 private Properties getTransformerParameters( final ModelContext context ) throws IOException
720 {
721 final Properties properties = new Properties();
722
723 if ( context.getExecutorService() != null )
724 {
725 ByteArrayInputStream in = null;
726 ByteArrayOutputStream out = null;
727 try
728 {
729 out = new ByteArrayOutputStream();
730 System.getProperties().store( out, this.getClass().getName() );
731 out.close();
732 final byte[] bytes = out.toByteArray();
733 out = null;
734
735 in = new ByteArrayInputStream( bytes );
736 properties.load( in );
737 in.close();
738 in = null;
739 }
740 finally
741 {
742 try
743 {
744 if ( out != null )
745 {
746 out.close();
747 }
748 }
749 catch ( final IOException e )
750 {
751
752 }
753 finally
754 {
755 try
756 {
757 if ( in != null )
758 {
759 in.close();
760 }
761 }
762 catch ( final IOException e )
763 {
764
765 }
766 }
767 }
768 }
769 else
770 {
771 properties.putAll( System.getProperties() );
772 }
773
774 return properties;
775 }
776
777 private static String getMessage( final String key, final Object... args )
778 {
779 return MessageFormat.format( ResourceBundle.getBundle(
780 DefaultModletProcessor.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args );
781
782 }
783
784 private static String getMessage( final Throwable t )
785 {
786 return t != null
787 ? t.getMessage() != null && t.getMessage().trim().length() > 0
788 ? t.getMessage()
789 : getMessage( t.getCause() )
790 : null;
791
792 }
793
794 }