View Javadoc
1   /*
2    *   Copyright (C) 2005 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: DefaultModletProvider.java 5351 2016-09-05 04:22:17Z schulte $
29   *
30   */
31  package org.jomc.modlet;
32  
33  import java.lang.reflect.UndeclaredThrowableException;
34  import java.net.URL;
35  import java.text.MessageFormat;
36  import java.util.Enumeration;
37  import java.util.LinkedList;
38  import java.util.List;
39  import java.util.ResourceBundle;
40  import java.util.concurrent.Callable;
41  import java.util.concurrent.CancellationException;
42  import java.util.concurrent.ExecutionException;
43  import java.util.concurrent.Future;
44  import java.util.logging.Level;
45  import javax.xml.bind.JAXBContext;
46  import javax.xml.bind.JAXBElement;
47  import javax.xml.bind.JAXBException;
48  import javax.xml.bind.UnmarshalException;
49  import javax.xml.bind.Unmarshaller;
50  
51  /**
52   * Default {@code ModletProvider} implementation.
53   *
54   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
55   * @version $JOMC: DefaultModletProvider.java 5351 2016-09-05 04:22:17Z schulte $
56   * @see ModelContext#findModlets(org.jomc.modlet.Modlets)
57   */
58  public class DefaultModletProvider implements ModletProvider
59  {
60  
61      /**
62       * Constant for the name of the model context attribute backing property {@code enabled}.
63       *
64       * @see #findModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
65       * @see ModelContext#getAttribute(java.lang.String)
66       * @since 1.2
67       */
68      public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.modlet.DefaultModletProvider.enabledAttribute";
69  
70      /**
71       * Constant for the name of the system property controlling property {@code defaultEnabled}.
72       *
73       * @see #isDefaultEnabled()
74       * @since 1.2
75       */
76      private static final String DEFAULT_ENABLED_PROPERTY_NAME =
77          "org.jomc.modlet.DefaultModletProvider.defaultEnabled";
78  
79      /**
80       * Default value of the flag indicating the provider is enabled by default.
81       *
82       * @see #isDefaultEnabled()
83       * @since 1.2
84       */
85      private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;
86  
87      /**
88       * Flag indicating the provider is enabled by default.
89       */
90      private static volatile Boolean defaultEnabled;
91  
92      /**
93       * Flag indicating the provider is enabled.
94       */
95      private volatile Boolean enabled;
96  
97      /**
98       * Constant for the name of the model context attribute backing property {@code modletLocation}.
99       *
100      * @see #findModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)
101      * @see ModelContext#getAttribute(java.lang.String)
102      * @since 1.2
103      */
104     public static final String MODLET_LOCATION_ATTRIBUTE_NAME =
105         "org.jomc.modlet.DefaultModletProvider.modletLocationAttribute";
106 
107     /**
108      * Constant for the name of the system property controlling property {@code defaultModletLocation}.
109      *
110      * @see #getDefaultModletLocation()
111      * @since 1.2
112      */
113     private static final String DEFAULT_MODLET_LOCATION_PROPERTY_NAME =
114         "org.jomc.modlet.DefaultModletProvider.defaultModletLocation";
115 
116     /**
117      * Class path location searched for {@code Modlets} by default.
118      *
119      * @see #getDefaultModletLocation()
120      */
121     private static final String DEFAULT_MODLET_LOCATION = "META-INF/jomc-modlet.xml";
122 
123     /**
124      * Default {@code Modlet} location.
125      */
126     private static volatile String defaultModletLocation;
127 
128     /**
129      * Modlet location of the instance.
130      */
131     private volatile String modletLocation;
132 
133     /**
134      * Constant for the name of the model context attribute backing property {@code validating}.
135      *
136      * @see #findModlets(org.jomc.modlet.ModelContext, java.lang.String)
137      * @see ModelContext#getAttribute(java.lang.String)
138      * @since 1.2
139      */
140     public static final String VALIDATING_ATTRIBUTE_NAME =
141         "org.jomc.modlet.DefaultModletProvider.validatingAttribute";
142 
143     /**
144      * Constant for the name of the system property controlling property {@code defaultValidating}.
145      *
146      * @see #isDefaultValidating()
147      * @since 1.2
148      */
149     private static final String DEFAULT_VALIDATING_PROPERTY_NAME =
150         "org.jomc.modlet.DefaultModletProvider.defaultValidating";
151 
152     /**
153      * Default value of the flag indicating the provider is validating resources by default.
154      *
155      * @see #isDefaultValidating()
156      * @since 1.2
157      */
158     private static final Boolean DEFAULT_VALIDATING = Boolean.TRUE;
159 
160     /**
161      * Flag indicating the provider is validating resources by default.
162      *
163      * @since 1.2
164      */
165     private static volatile Boolean defaultValidating;
166 
167     /**
168      * Flag indicating the provider is validating resources.
169      *
170      * @since 1.2
171      */
172     private volatile Boolean validating;
173 
174     /**
175      * Constant for the name of the system property controlling property {@code defaultOrdinal}.
176      *
177      * @see #getDefaultOrdinal()
178      * @since 1.6
179      */
180     private static final String DEFAULT_ORDINAL_PROPERTY_NAME =
181         "org.jomc.modlet.DefaultModletProvider.defaultOrdinal";
182 
183     /**
184      * Default value of the ordinal number of the provider.
185      *
186      * @see #getDefaultOrdinal()
187      * @since 1.6
188      */
189     private static final Integer DEFAULT_ORDINAL = 0;
190 
191     /**
192      * Default ordinal number of the provider.
193      *
194      * @since 1.6
195      */
196     private static volatile Integer defaultOrdinal;
197 
198     /**
199      * Ordinal number of the provider.
200      *
201      * @since 1.6
202      */
203     private volatile Integer ordinal;
204 
205     /**
206      * Creates a new {@code DefaultModletProvider} instance.
207      */
208     public DefaultModletProvider()
209     {
210         super();
211     }
212 
213     /**
214      * Gets a flag indicating the provider is enabled by default.
215      * <p>
216      * The default enabled flag is controlled by system property
217      * {@code org.jomc.modlet.DefaultModletProvider.defaultEnabled} holding a value indicating the provider is
218      * enabled by default. If that property is not set, the {@code true} default is returned.
219      * </p>
220      *
221      * @return {@code true}, if the provider is enabled by default; {@code false}, if the provider is disabled by
222      * default.
223      *
224      * @see #isEnabled()
225      * @see #setDefaultEnabled(java.lang.Boolean)
226      */
227     public static boolean isDefaultEnabled()
228     {
229         if ( defaultEnabled == null )
230         {
231             defaultEnabled = Boolean.valueOf( System.getProperty(
232                 DEFAULT_ENABLED_PROPERTY_NAME, Boolean.toString( DEFAULT_ENABLED ) ) );
233 
234         }
235 
236         return defaultEnabled;
237     }
238 
239     /**
240      * Sets the flag indicating the provider is enabled by default.
241      *
242      * @param value The new value of the flag indicating the provider is enabled by default or {@code null}.
243      *
244      * @see #isDefaultEnabled()
245      */
246     public static void setDefaultEnabled( final Boolean value )
247     {
248         defaultEnabled = value;
249     }
250 
251     /**
252      * Gets a flag indicating the provider is enabled.
253      *
254      * @return {@code true}, if the provider is enabled; {@code false}, if the provider is disabled.
255      *
256      * @see #isDefaultEnabled()
257      * @see #setEnabled(java.lang.Boolean)
258      */
259     public final boolean isEnabled()
260     {
261         if ( this.enabled == null )
262         {
263             this.enabled = isDefaultEnabled();
264         }
265 
266         return this.enabled;
267     }
268 
269     /**
270      * Sets the flag indicating the provider is enabled.
271      *
272      * @param value The new value of the flag indicating the provider is enabled or {@code null}.
273      *
274      * @see #isEnabled()
275      */
276     public final void setEnabled( final Boolean value )
277     {
278         this.enabled = value;
279     }
280 
281     /**
282      * Gets the default location searched for {@code Modlet} resources.
283      * <p>
284      * The default {@code Modlet} location is controlled by system property
285      * {@code org.jomc.modlet.DefaultModletProvider.defaultModletLocation} holding the location to search for
286      * {@code Modlet} resources by default. If that property is not set, the {@code META-INF/jomc-modlet.xml} default is
287      * returned.
288      * </p>
289      *
290      * @return The location searched for {@code Modlet} resources by default.
291      *
292      * @see #setDefaultModletLocation(java.lang.String)
293      */
294     public static String getDefaultModletLocation()
295     {
296         if ( defaultModletLocation == null )
297         {
298             defaultModletLocation = System.getProperty(
299                 DEFAULT_MODLET_LOCATION_PROPERTY_NAME, DEFAULT_MODLET_LOCATION );
300 
301         }
302 
303         return defaultModletLocation;
304     }
305 
306     /**
307      * Sets the default location searched for {@code Modlet} resources.
308      *
309      * @param value The new default location to search for {@code Modlet} resources or {@code null}.
310      *
311      * @see #getDefaultModletLocation()
312      */
313     public static void setDefaultModletLocation( final String value )
314     {
315         defaultModletLocation = value;
316     }
317 
318     /**
319      * Gets the location searched for {@code Modlet} resources.
320      *
321      * @return The location searched for {@code Modlet} resources.
322      *
323      * @see #getDefaultModletLocation()
324      * @see #setModletLocation(java.lang.String)
325      */
326     public final String getModletLocation()
327     {
328         if ( this.modletLocation == null )
329         {
330             this.modletLocation = getDefaultModletLocation();
331         }
332 
333         return this.modletLocation;
334     }
335 
336     /**
337      * Sets the location searched for {@code Modlet} resources.
338      *
339      * @param value The new location to search for {@code Modlet} resources or {@code null}.
340      *
341      * @see #getModletLocation()
342      */
343     public final void setModletLocation( final String value )
344     {
345         this.modletLocation = value;
346     }
347 
348     /**
349      * Gets a flag indicating the provider is validating resources by default.
350      * <p>
351      * The default validating flag is controlled by system property
352      * {@code org.jomc.modlet.DefaultModletProvider.defaultValidating} holding a value indicating the provider is
353      * validating resources by default. If that property is not set, the {@code true} default is returned.
354      * </p>
355      *
356      * @return {@code true}, if the provider is validating resources by default; {@code false}, if the provider is not
357      * validating resources by default.
358      *
359      * @see #isValidating()
360      * @see #setDefaultValidating(java.lang.Boolean)
361      *
362      * @since 1.2
363      */
364     public static boolean isDefaultValidating()
365     {
366         if ( defaultValidating == null )
367         {
368             defaultValidating = Boolean.valueOf( System.getProperty(
369                 DEFAULT_VALIDATING_PROPERTY_NAME, Boolean.toString( DEFAULT_VALIDATING ) ) );
370 
371         }
372 
373         return defaultValidating;
374     }
375 
376     /**
377      * Sets the flag indicating the provider is validating resources by default.
378      *
379      * @param value The new value of the flag indicating the provider is validating resources by default or
380      * {@code null}.
381      *
382      * @see #isDefaultValidating()
383      *
384      * @since 1.2
385      */
386     public static void setDefaultValidating( final Boolean value )
387     {
388         defaultValidating = value;
389     }
390 
391     /**
392      * Gets a flag indicating the provider is validating resources.
393      *
394      * @return {@code true}, if the provider is validating resources; {@code false}, if the provider is not validating
395      * resources.
396      *
397      * @see #isDefaultValidating()
398      * @see #setValidating(java.lang.Boolean)
399      *
400      * @since 1.2
401      */
402     public final boolean isValidating()
403     {
404         if ( this.validating == null )
405         {
406             this.validating = isDefaultValidating();
407         }
408 
409         return this.validating;
410     }
411 
412     /**
413      * Sets the flag indicating the provider is validating resources.
414      *
415      * @param value The new value of the flag indicating the provider is validating resources or {@code null}.
416      *
417      * @see #isValidating()
418      *
419      * @since 1.2
420      */
421     public final void setValidating( final Boolean value )
422     {
423         this.validating = value;
424     }
425 
426     /**
427      * Gets the default ordinal number of the provider.
428      * <p>
429      * The default ordinal number is controlled by system property
430      * {@code org.jomc.modlet.DefaultModletProvider.defaultOrdinal} holding the default ordinal number of the provider.
431      * If that property is not set, the {@code 0} default is returned.
432      * </p>
433      *
434      * @return The default ordinal number of the provider.
435      *
436      * @see #setDefaultOrdinal(java.lang.Integer)
437      *
438      * @since 1.6
439      */
440     public static int getDefaultOrdinal()
441     {
442         if ( defaultOrdinal == null )
443         {
444             defaultOrdinal = Integer.getInteger( DEFAULT_ORDINAL_PROPERTY_NAME, DEFAULT_ORDINAL );
445         }
446 
447         return defaultOrdinal;
448     }
449 
450     /**
451      * Sets the default ordinal number of the provider.
452      *
453      * @param value The new default ordinal number of the provider or {@code null}.
454      *
455      * @see #getDefaultOrdinal()
456      *
457      * @since 1.6
458      */
459     public static void setDefaultOrdinal( final Integer value )
460     {
461         defaultOrdinal = value;
462     }
463 
464     /**
465      * Gets the ordinal number of the provider.
466      *
467      * @return The ordinal number of the provider.
468      *
469      * @see #getDefaultOrdinal()
470      * @see #setOrdinal(java.lang.Integer)
471      *
472      * @since 1.6
473      */
474     public final int getOrdinal()
475     {
476         if ( this.ordinal == null )
477         {
478             this.ordinal = getDefaultOrdinal();
479         }
480 
481         return this.ordinal;
482     }
483 
484     /**
485      * Sets the ordinal number of the provider.
486      *
487      * @param value The new ordinal number of the provider or {@code null}.
488      *
489      * @see #getOrdinal()
490      *
491      * @since 1.6
492      */
493     public final void setOrdinal( final Integer value )
494     {
495         this.ordinal = value;
496     }
497 
498     /**
499      * Searches a given context for {@code Modlets}.
500      *
501      * @param context The context to search for {@code Modlets}.
502      * @param location The location to search at.
503      *
504      * @return The {@code Modlets} found at {@code location} in {@code context} or {@code null}, if no {@code Modlets}
505      * are found.
506      *
507      * @throws NullPointerException if {@code context} or {@code location} is {@code null}.
508      * @throws ModelException if searching the context fails.
509      *
510      * @see #isValidating()
511      * @see #VALIDATING_ATTRIBUTE_NAME
512      */
513     public Modlets findModlets( final ModelContext context, final String location ) throws ModelException
514     {
515         if ( context == null )
516         {
517             throw new NullPointerException( "context" );
518         }
519         if ( location == null )
520         {
521             throw new NullPointerException( "location" );
522         }
523 
524         URL url = null;
525         try
526         {
527             boolean contextValidating = this.isValidating();
528             if ( DEFAULT_VALIDATING == contextValidating
529                      && context.getAttribute( VALIDATING_ATTRIBUTE_NAME ) instanceof Boolean )
530             {
531                 contextValidating = (Boolean) context.getAttribute( VALIDATING_ATTRIBUTE_NAME );
532             }
533 
534             final Modlets modlets = new Modlets();
535             final long t0 = System.nanoTime();
536             final Enumeration<URL> modletResourceEnumeration = context.findResources( location );
537             final JAXBContext ctx = context.createContext( ModletObject.MODEL_PUBLIC_ID );
538             final javax.xml.validation.Schema schema = contextValidating
539                                                            ? context.createSchema( ModletObject.MODEL_PUBLIC_ID )
540                                                            : null;
541 
542             final ThreadLocal<Unmarshaller> threadLocalUnmarshaller = new ThreadLocal<Unmarshaller>();
543 
544             class UnmarshalTask implements Callable<Modlets>
545             {
546 
547                 final URL resource;
548 
549                 final javax.xml.validation.Schema schema;
550 
551                 UnmarshalTask( final URL resource, final javax.xml.validation.Schema schema )
552                 {
553                     super();
554                     this.resource = resource;
555                     this.schema = schema;
556                 }
557 
558                 public Modlets call() throws ModelException
559                 {
560                     try
561                     {
562                         final Modlets modlets = new Modlets();
563                         Unmarshaller unmarshaller = threadLocalUnmarshaller.get();
564                         if ( unmarshaller == null )
565                         {
566                             unmarshaller = ctx.createUnmarshaller();
567                             unmarshaller.setSchema( this.schema );
568 
569                             threadLocalUnmarshaller.set( unmarshaller );
570                         }
571 
572                         Object content = unmarshaller.unmarshal( this.resource );
573                         if ( content instanceof JAXBElement<?> )
574                         {
575                             content = ( (JAXBElement<?>) content ).getValue();
576                         }
577 
578                         if ( content instanceof Modlet )
579                         {
580                             modlets.getModlet().add( (Modlet) content );
581                         }
582                         else if ( content instanceof Modlets )
583                         {
584                             modlets.getModlet().addAll( ( (Modlets) content ).getModlet() );
585                         }
586 
587                         return modlets;
588                     }
589                     catch ( final UnmarshalException e )
590                     {
591                         String message = getMessage( e );
592                         if ( message == null && e.getLinkedException() != null )
593                         {
594                             message = getMessage( e.getLinkedException() );
595                         }
596 
597                         message = getMessage( "unmarshalException", this.resource.toExternalForm(),
598                                               message != null ? " " + message : "" );
599 
600                         throw new ModelException( message, e );
601                     }
602                     catch ( final JAXBException e )
603                     {
604                         String message = getMessage( e );
605                         if ( message == null && e.getLinkedException() != null )
606                         {
607                             message = getMessage( e.getLinkedException() );
608                         }
609 
610                         throw new ModelException( message, e );
611                     }
612                 }
613 
614             }
615 
616             final List<UnmarshalTask> tasks = new LinkedList<UnmarshalTask>();
617 
618             while ( modletResourceEnumeration.hasMoreElements() )
619             {
620                 tasks.add( new UnmarshalTask( modletResourceEnumeration.nextElement(), schema ) );
621             }
622 
623             if ( context.getExecutorService() != null && tasks.size() > 1 )
624             {
625                 for ( final Future<Modlets> task : context.getExecutorService().invokeAll( tasks ) )
626                 {
627                     modlets.getModlet().addAll( task.get().getModlet() );
628                 }
629             }
630             else
631             {
632                 for ( final UnmarshalTask task : tasks )
633                 {
634                     modlets.getModlet().addAll( task.call().getModlet() );
635                 }
636             }
637 
638             if ( context.isLoggable( Level.FINE ) )
639             {
640                 context.log( Level.FINE, getMessage( "contextReport",
641                                                      modlets.getModlet().size(),
642                                                      location, System.nanoTime() - t0 ), null );
643 
644             }
645 
646             return modlets.getModlet().isEmpty() ? null : modlets;
647         }
648         catch ( final CancellationException e )
649         {
650             throw new ModelException( getMessage( e ), e );
651         }
652         catch ( final InterruptedException e )
653         {
654             throw new ModelException( getMessage( e ), e );
655         }
656         catch ( final ExecutionException e )
657         {
658             if ( e.getCause() instanceof ModelException )
659             {
660                 throw (ModelException) e.getCause();
661             }
662             else if ( e.getCause() instanceof RuntimeException )
663             {
664                 // The fork-join framework breaks the exception handling contract of Callable by re-throwing any
665                 // exception caught using a runtime exception.
666                 if ( e.getCause().getCause() instanceof ModelException )
667                 {
668                     throw (ModelException) e.getCause().getCause();
669                 }
670                 else if ( e.getCause().getCause() instanceof RuntimeException )
671                 {
672                     throw (RuntimeException) e.getCause().getCause();
673                 }
674                 else if ( e.getCause().getCause() instanceof Error )
675                 {
676                     throw (Error) e.getCause().getCause();
677                 }
678                 else if ( e.getCause().getCause() instanceof Exception )
679                 {
680                     // Checked exception not declared to be thrown by the Callable's 'call' method.
681                     throw new UndeclaredThrowableException( e.getCause().getCause() );
682                 }
683                 else
684                 {
685                     throw (RuntimeException) e.getCause();
686                 }
687             }
688             else if ( e.getCause() instanceof Error )
689             {
690                 throw (Error) e.getCause();
691             }
692             else
693             {
694                 // Checked exception not declared to be thrown by the Callable's 'call' method.
695                 throw new UndeclaredThrowableException( e.getCause() );
696             }
697         }
698     }
699 
700     /**
701      * {@inheritDoc}
702      *
703      * @return The {@code Modlets} found in the context or {@code null}, if no {@code Modlets} are found or the provider
704      * is disabled.
705      *
706      * @see #isEnabled()
707      * @see #getModletLocation()
708      * @see #findModlets(org.jomc.modlet.ModelContext, java.lang.String)
709      * @see #ENABLED_ATTRIBUTE_NAME
710      * @see #MODLET_LOCATION_ATTRIBUTE_NAME
711      * @deprecated As of JOMC 1.6, this method has been replaced by {@link #findModlets(org.jomc.modlet.ModelContext, org.jomc.modlet.Modlets)}.
712      * This method will be removed in JOMC 2.0.
713      */
714     @Deprecated
715     public Modlets findModlets( final ModelContext context ) throws ModelException
716     {
717         if ( context == null )
718         {
719             throw new NullPointerException( "context" );
720         }
721 
722         return this.findModlets( context, new Modlets() );
723     }
724 
725     /**
726      * {@inheritDoc}
727      *
728      * @return The {@code Modlets} found in the context or {@code null}, if no {@code Modlets} are found or the provider
729      * is disabled.
730      *
731      * @see #isEnabled()
732      * @see #getModletLocation()
733      * @see #findModlets(org.jomc.modlet.ModelContext, java.lang.String)
734      * @see #ENABLED_ATTRIBUTE_NAME
735      * @see #MODLET_LOCATION_ATTRIBUTE_NAME
736      * @since 1.6
737      */
738     public Modlets findModlets( final ModelContext context, final Modlets modlets ) throws ModelException
739     {
740         if ( context == null )
741         {
742             throw new NullPointerException( "context" );
743         }
744         if ( modlets == null )
745         {
746             throw new NullPointerException( "context" );
747         }
748 
749         Modlets provided = null;
750 
751         boolean contextEnabled = this.isEnabled();
752         if ( DEFAULT_ENABLED == contextEnabled && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
753         {
754             contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME );
755         }
756 
757         String contextModletLocation = this.getModletLocation();
758         if ( DEFAULT_MODLET_LOCATION.equals( contextModletLocation )
759                  && context.getAttribute( MODLET_LOCATION_ATTRIBUTE_NAME ) instanceof String )
760         {
761             contextModletLocation = (String) context.getAttribute( MODLET_LOCATION_ATTRIBUTE_NAME );
762         }
763 
764         if ( contextEnabled )
765         {
766             final Modlets found = this.findModlets( context, contextModletLocation );
767 
768             if ( found != null )
769             {
770                 provided = modlets.clone();
771                 provided.getModlet().addAll( found.getModlet() );
772             }
773         }
774         else if ( context.isLoggable( Level.FINER ) )
775         {
776             context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName() ), null );
777         }
778 
779         return provided;
780     }
781 
782     private static String getMessage( final String key, final Object... arguments )
783     {
784         return MessageFormat.format( ResourceBundle.getBundle(
785             DefaultModletProvider.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
786 
787     }
788 
789     private static String getMessage( final Throwable t )
790     {
791         return t != null
792                    ? t.getMessage() != null && t.getMessage().trim().length() > 0
793                          ? t.getMessage()
794                          : getMessage( t.getCause() )
795                    : null;
796 
797     }
798 
799 }