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 }