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