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