View Javadoc
1   /*
2    *   Copyright (C) 2014 Christian Schulte <cs@schulte.it>
3    *   All rights reserved.
4    *
5    *   Redistribution and use in source and binary forms, with or without
6    *   modification, are permitted provided that the following conditions
7    *   are met:
8    *
9    *     o Redistributions of source code must retain the above copyright
10   *       notice, this list of conditions and the following disclaimer.
11   *
12   *     o Redistributions in binary form must reproduce the above copyright
13   *       notice, this list of conditions and the following disclaimer in
14   *       the documentation and/or other materials provided with the
15   *       distribution.
16   *
17   *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18   *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20   *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21   *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27   *
28   *   $JOMC: DefaultModletProcessor.java 5293 2016-08-29 17:41:51Z schulte $
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   * Default {@code ModletProcessor} implementation.
70   *
71   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
72   * @version $JOMC: DefaultModletProcessor.java 5293 2016-08-29 17:41:51Z schulte $
73   * @see ModelContext#processModlets(org.jomc.modlet.Modlets)
74   * @since 1.6
75   */
76  public class DefaultModletProcessor implements ModletProcessor
77  {
78  
79      /**
80       * Constant for the name of the model context attribute backing property {@code enabled}.
81       *
82       * @see #processModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
83       * @see ModelContext#getAttribute(java.lang.String)
84       */
85      public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.modlet.DefaultModletProcessor.enabledAttribute";
86  
87      /**
88       * Constant for the name of the system property controlling property {@code defaultEnabled}.
89       *
90       * @see #isDefaultEnabled()
91       */
92      private static final String DEFAULT_ENABLED_PROPERTY_NAME =
93          "org.jomc.modlet.DefaultModletProcessor.defaultEnabled";
94  
95      /**
96       * Default value of the flag indicating the processor is enabled by default.
97       *
98       * @see #isDefaultEnabled()
99       */
100     private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;
101 
102     /**
103      * Flag indicating the processor is enabled by default.
104      */
105     private static volatile Boolean defaultEnabled;
106 
107     /**
108      * Flag indicating the processor is enabled.
109      */
110     private volatile Boolean enabled;
111 
112     /**
113      * Constant for the name of the system property controlling property {@code defaultOrdinal}.
114      *
115      * @see #getDefaultOrdinal()
116      */
117     private static final String DEFAULT_ORDINAL_PROPERTY_NAME =
118         "org.jomc.modlet.DefaultModletProcessor.defaultOrdinal";
119 
120     /**
121      * Default value of the ordinal number of the processor.
122      *
123      * @see #getDefaultOrdinal()
124      */
125     private static final Integer DEFAULT_ORDINAL = 0;
126 
127     /**
128      * Default ordinal number of the processor.
129      */
130     private static volatile Integer defaultOrdinal;
131 
132     /**
133      * Ordinal number of the processor.
134      */
135     private volatile Integer ordinal;
136 
137     /**
138      * Constant for the name of the model context attribute backing property {@code transformerLocation}.
139      *
140      * @see #processModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
141      * @see ModelContext#getAttribute(java.lang.String)
142      * @since 1.2
143      */
144     public static final String TRANSFORMER_LOCATION_ATTRIBUTE_NAME =
145         "org.jomc.modlet.DefaultModletProcessor.transformerLocationAttribute";
146 
147     /**
148      * Constant for the name of the system property controlling property {@code defaultTransformerLocation}.
149      *
150      * @see #getDefaultTransformerLocation()
151      */
152     private static final String DEFAULT_TRANSFORMER_LOCATION_PROPERTY_NAME =
153         "org.jomc.modlet.DefaultModletProcessor.defaultTransformerLocation";
154 
155     /**
156      * Class path location searched for transformers by default.
157      *
158      * @see #getDefaultTransformerLocation()
159      */
160     private static final String DEFAULT_TRANSFORMER_LOCATION = "META-INF/jomc-modlet.xsl";
161 
162     /**
163      * Default transformer location.
164      */
165     private static volatile String defaultTransformerLocation;
166 
167     /**
168      * Transformer location of the instance.
169      */
170     private volatile String transformerLocation;
171 
172     /**
173      * Creates a new {@code DefaultModletProcessor} instance.
174      */
175     public DefaultModletProcessor()
176     {
177         super();
178     }
179 
180     /**
181      * Gets a flag indicating the processor is enabled by default.
182      * <p>
183      * The default enabled flag is controlled by system property
184      * {@code org.jomc.modlet.DefaultModletProcessor.defaultEnabled} holding a value indicating the processor is
185      * enabled by default. If that property is not set, the {@code true} default is returned.
186      * </p>
187      *
188      * @return {@code true}, if the processor is enabled by default; {@code false}, if the processor is disabled by
189      * default.
190      *
191      * @see #isEnabled()
192      * @see #setDefaultEnabled(java.lang.Boolean)
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      * Sets the flag indicating the processor is enabled by default.
208      *
209      * @param value The new value of the flag indicating the processor is enabled by default or {@code null}.
210      *
211      * @see #isDefaultEnabled()
212      */
213     public static void setDefaultEnabled( final Boolean value )
214     {
215         defaultEnabled = value;
216     }
217 
218     /**
219      * Gets a flag indicating the processor is enabled.
220      *
221      * @return {@code true}, if the processor is enabled; {@code false}, if the processor is disabled.
222      *
223      * @see #isDefaultEnabled()
224      * @see #setEnabled(java.lang.Boolean)
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      * Sets the flag indicating the processor is enabled.
238      *
239      * @param value The new value of the flag indicating the processor is enabled or {@code null}.
240      *
241      * @see #isEnabled()
242      */
243     public final void setEnabled( final Boolean value )
244     {
245         this.enabled = value;
246     }
247 
248     /**
249      * Gets the default ordinal number of the processor.
250      * <p>
251      * The default ordinal number is controlled by system property
252      * {@code org.jomc.modlet.DefaultModletProvider.defaultOrdinal} holding the default ordinal number of the processor.
253      * If that property is not set, the {@code 0} default is returned.
254      * </p>
255      *
256      * @return The default ordinal number of the processor.
257      *
258      * @see #setDefaultOrdinal(java.lang.Integer)
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      * Sets the default ordinal number of the processor.
272      *
273      * @param value The new default ordinal number of the processor or {@code null}.
274      *
275      * @see #getDefaultOrdinal()
276      */
277     public static void setDefaultOrdinal( final Integer value )
278     {
279         defaultOrdinal = value;
280     }
281 
282     /**
283      * Gets the ordinal number of the processor.
284      *
285      * @return The ordinal number of the processor.
286      *
287      * @see #getDefaultOrdinal()
288      * @see #setOrdinal(java.lang.Integer)
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      * Sets the ordinal number of the processor.
302      *
303      * @param value The new ordinal number of the processor or {@code null}.
304      *
305      * @see #getOrdinal()
306      */
307     public final void setOrdinal( final Integer value )
308     {
309         this.ordinal = value;
310     }
311 
312     /**
313      * Gets the default location searched for transformer resources.
314      * <p>
315      * The default transformer location is controlled by system property
316      * {@code org.jomc.modlet.DefaultModletProcessor.defaultTransformerLocation} holding the location to search
317      * for transformer resources by default. If that property is not set, the {@code META-INF/jomc-modlet.xsl} default
318      * is returned.
319      * </p>
320      *
321      * @return The location searched for transformer resources by default.
322      *
323      * @see #setDefaultTransformerLocation(java.lang.String)
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      * Sets the default location searched for transformer resources.
339      *
340      * @param value The new default location to search for transformer resources or {@code null}.
341      *
342      * @see #getDefaultTransformerLocation()
343      */
344     public static void setDefaultTransformerLocation( final String value )
345     {
346         defaultTransformerLocation = value;
347     }
348 
349     /**
350      * Gets the location searched for transformer resources.
351      *
352      * @return The location searched for transformer resources.
353      *
354      * @see #getDefaultTransformerLocation()
355      * @see #setTransformerLocation(java.lang.String)
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      * Sets the location searched for transformer resources.
369      *
370      * @param value The new location to search for transformer resources or {@code null}.
371      *
372      * @see #getTransformerLocation()
373      */
374     public final void setTransformerLocation( final String value )
375     {
376         this.transformerLocation = value;
377     }
378 
379     /**
380      * Searches a given context for transformers.
381      *
382      * @param context The context to search for transformers.
383      * @param location The location to search at.
384      *
385      * @return The transformers found at {@code location} in {@code context} or {@code null}, if no transformers are
386      * found.
387      *
388      * @throws NullPointerException if {@code context} or {@code location} is {@code null}.
389      * @throws ModelException if getting the transformers fails.
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                 // The fork-join framework breaks the exception handling contract of Callable by re-throwing any
553                 // exception caught using a runtime exception.
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                     // Checked exception not declared to be thrown by the Callable's 'call' method.
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                 // Checked exception not declared to be thrown by the Callable's 'call' method.
596                 throw new UndeclaredThrowableException( e.getCause() );
597             }
598         }
599     }
600 
601     /**
602      * {@inheritDoc}
603      *
604      * @see #isEnabled()
605      * @see #getTransformerLocation()
606      * @see #findTransformers(org.jomc.modlet.ModelContext, java.lang.String)
607      * @see #ENABLED_ATTRIBUTE_NAME
608      * @see #TRANSFORMER_LOCATION_ATTRIBUTE_NAME
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                     // Suppressed.
752                 }
753                 finally
754                 {
755                     try
756                     {
757                         if ( in != null )
758                         {
759                             in.close();
760                         }
761                     }
762                     catch ( final IOException e )
763                     {
764                         // Suppressed.
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 }