View Javadoc

1   /*
2    *   Copyright (C) Christian Schulte, 2005-206
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 4613 2012-09-22 10:07:08Z schulte $
29   *
30   */
31  package org.jomc.modlet;
32  
33  import java.net.URL;
34  import java.text.MessageFormat;
35  import java.util.Enumeration;
36  import java.util.ResourceBundle;
37  import java.util.logging.Level;
38  import javax.xml.bind.JAXBContext;
39  import javax.xml.bind.JAXBElement;
40  import javax.xml.bind.JAXBException;
41  import javax.xml.bind.UnmarshalException;
42  import javax.xml.bind.Unmarshaller;
43  
44  /**
45   * Default {@code ModletProvider} implementation.
46   *
47   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
48   * @version $JOMC: DefaultModletProvider.java 4613 2012-09-22 10:07:08Z schulte $
49   * @see ModelContext#findModlets()
50   */
51  public class DefaultModletProvider implements ModletProvider
52  {
53  
54      /**
55       * Constant for the name of the model context attribute backing property {@code enabled}.
56       * @see #findModlets(org.jomc.modlet.ModelContext)
57       * @see ModelContext#getAttribute(java.lang.String)
58       * @since 1.2
59       */
60      public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.modlet.DefaultModletProvider.enabledAttribute";
61  
62      /**
63       * Constant for the name of the system property controlling property {@code defaultEnabled}.
64       * @see #isDefaultEnabled()
65       * @since 1.2
66       */
67      private static final String DEFAULT_ENABLED_PROPERTY_NAME =
68          "org.jomc.modlet.DefaultModletProvider.defaultEnabled";
69  
70      /**
71       * Default value of the flag indicating the provider is enabled by default.
72       * @see #isDefaultEnabled()
73       * @since 1.2
74       */
75      private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;
76  
77      /** Flag indicating the provider is enabled by default. */
78      private static volatile Boolean defaultEnabled;
79  
80      /** Flag indicating the provider is enabled. */
81      private Boolean enabled;
82  
83      /**
84       * Constant for the name of the model context attribute backing property {@code modletLocation}.
85       * @see #findModlets(org.jomc.modlet.ModelContext)
86       * @see ModelContext#getAttribute(java.lang.String)
87       * @since 1.2
88       */
89      public static final String MODLET_LOCATION_ATTRIBUTE_NAME =
90          "org.jomc.modlet.DefaultModletProvider.modletLocationAttribute";
91  
92      /**
93       * Constant for the name of the system property controlling property {@code defaultModletLocation}.
94       * @see #getDefaultModletLocation()
95       * @since 1.2
96       */
97      private static final String DEFAULT_MODLET_LOCATION_PROPERTY_NAME =
98          "org.jomc.modlet.DefaultModletProvider.defaultModletLocation";
99  
100     /**
101      * Class path location searched for {@code Modlets} by default.
102      * @see #getDefaultModletLocation()
103      */
104     private static final String DEFAULT_MODLET_LOCATION = "META-INF/jomc-modlet.xml";
105 
106     /** Default {@code Modlet} location. */
107     private static volatile String defaultModletLocation;
108 
109     /** Modlet location of the instance. */
110     private String modletLocation;
111 
112     /**
113      * Constant for the name of the model context attribute backing property {@code validating}.
114      * @see #findModlets(org.jomc.modlet.ModelContext, java.lang.String)
115      * @see ModelContext#getAttribute(java.lang.String)
116      * @since 1.2
117      */
118     public static final String VALIDATING_ATTRIBUTE_NAME =
119         "org.jomc.modlet.DefaultModletProvider.validatingAttribute";
120 
121     /**
122      * Constant for the name of the system property controlling property {@code defaultValidating}.
123      * @see #isDefaultValidating()
124      * @since 1.2
125      */
126     private static final String DEFAULT_VALIDATING_PROPERTY_NAME =
127         "org.jomc.modlet.DefaultModletProvider.defaultValidating";
128 
129     /**
130      * Default value of the flag indicating the provider is validating resources by default.
131      * @see #isDefaultValidating()
132      * @since 1.2
133      */
134     private static final Boolean DEFAULT_VALIDATING = Boolean.TRUE;
135 
136     /**
137      * Flag indicating the provider is validating resources by default.
138      * @since 1.2
139      */
140     private static volatile Boolean defaultValidating;
141 
142     /**
143      * Flag indicating the provider is validating resources.
144      * @since 1.2
145      */
146     private Boolean validating;
147 
148     /** Creates a new {@code DefaultModletProvider} instance. */
149     public DefaultModletProvider()
150     {
151         super();
152     }
153 
154     /**
155      * Gets a flag indicating the provider is enabled by default.
156      * <p>The default enabled flag is controlled by system property
157      * {@code org.jomc.modlet.DefaultModletProvider.defaultEnabled} holding a value indicating the provider is
158      * enabled by default. If that property is not set, the {@code true} default is returned.</p>
159      *
160      * @return {@code true}, if the provider is enabled by default; {@code false}, if the provider is disabled by
161      * default.
162      *
163      * @see #isEnabled()
164      * @see #setDefaultEnabled(java.lang.Boolean)
165      */
166     public static boolean isDefaultEnabled()
167     {
168         if ( defaultEnabled == null )
169         {
170             defaultEnabled = Boolean.valueOf( System.getProperty(
171                 DEFAULT_ENABLED_PROPERTY_NAME, Boolean.toString( DEFAULT_ENABLED ) ) );
172 
173         }
174 
175         return defaultEnabled;
176     }
177 
178     /**
179      * Sets the flag indicating the provider is enabled by default.
180      *
181      * @param value The new value of the flag indicating the provider is enabled by default or {@code null}.
182      *
183      * @see #isDefaultEnabled()
184      */
185     public static void setDefaultEnabled( final Boolean value )
186     {
187         defaultEnabled = value;
188     }
189 
190     /**
191      * Gets a flag indicating the provider is enabled.
192      *
193      * @return {@code true}, if the provider is enabled; {@code false}, if the provider is disabled.
194      *
195      * @see #isDefaultEnabled()
196      * @see #setEnabled(java.lang.Boolean)
197      */
198     public final boolean isEnabled()
199     {
200         if ( this.enabled == null )
201         {
202             this.enabled = isDefaultEnabled();
203         }
204 
205         return this.enabled;
206     }
207 
208     /**
209      * Sets the flag indicating the provider is enabled.
210      *
211      * @param value The new value of the flag indicating the provider is enabled or {@code null}.
212      *
213      * @see #isEnabled()
214      */
215     public final void setEnabled( final Boolean value )
216     {
217         this.enabled = value;
218     }
219 
220     /**
221      * Gets the default location searched for {@code Modlet} resources.
222      * <p>The default {@code Modlet} location is controlled by system property
223      * {@code org.jomc.modlet.DefaultModletProvider.defaultModletLocation} holding the location to search for
224      * {@code Modlet} resources by default. If that property is not set, the {@code META-INF/jomc-modlet.xml} default is
225      * returned.</p>
226      *
227      * @return The location searched for {@code Modlet} resources by default.
228      *
229      * @see #setDefaultModletLocation(java.lang.String)
230      */
231     public static String getDefaultModletLocation()
232     {
233         if ( defaultModletLocation == null )
234         {
235             defaultModletLocation = System.getProperty(
236                 DEFAULT_MODLET_LOCATION_PROPERTY_NAME, DEFAULT_MODLET_LOCATION );
237 
238         }
239 
240         return defaultModletLocation;
241     }
242 
243     /**
244      * Sets the default location searched for {@code Modlet} resources.
245      *
246      * @param value The new default location to search for {@code Modlet} resources or {@code null}.
247      *
248      * @see #getDefaultModletLocation()
249      */
250     public static void setDefaultModletLocation( final String value )
251     {
252         defaultModletLocation = value;
253     }
254 
255     /**
256      * Gets the location searched for {@code Modlet} resources.
257      *
258      * @return The location searched for {@code Modlet} resources.
259      *
260      * @see #getDefaultModletLocation()
261      * @see #setModletLocation(java.lang.String)
262      */
263     public final String getModletLocation()
264     {
265         if ( this.modletLocation == null )
266         {
267             this.modletLocation = getDefaultModletLocation();
268         }
269 
270         return this.modletLocation;
271     }
272 
273     /**
274      * Sets the location searched for {@code Modlet} resources.
275      *
276      * @param value The new location to search for {@code Modlet} resources or {@code null}.
277      *
278      * @see #getModletLocation()
279      */
280     public final void setModletLocation( final String value )
281     {
282         this.modletLocation = value;
283     }
284 
285     /**
286      * Gets a flag indicating the provider is validating resources by default.
287      * <p>The default validating flag is controlled by system property
288      * {@code org.jomc.modlet.DefaultModletProvider.defaultValidating} holding a value indicating the provider is
289      * validating resources by default. If that property is not set, the {@code true} default is returned.</p>
290      *
291      * @return {@code true}, if the provider is validating resources by default; {@code false}, if the provider is not
292      * validating resources by default.
293      *
294      * @see #isValidating()
295      * @see #setDefaultValidating(java.lang.Boolean)
296      *
297      * @since 1.2
298      */
299     public static boolean isDefaultValidating()
300     {
301         if ( defaultValidating == null )
302         {
303             defaultValidating = Boolean.valueOf( System.getProperty(
304                 DEFAULT_VALIDATING_PROPERTY_NAME, Boolean.toString( DEFAULT_VALIDATING ) ) );
305 
306         }
307 
308         return defaultValidating;
309     }
310 
311     /**
312      * Sets the flag indicating the provider is validating resources by default.
313      *
314      * @param value The new value of the flag indicating the provider is validating resources by default or
315      * {@code null}.
316      *
317      * @see #isDefaultValidating()
318      *
319      * @since 1.2
320      */
321     public static void setDefaultValidating( final Boolean value )
322     {
323         defaultValidating = value;
324     }
325 
326     /**
327      * Gets a flag indicating the provider is validating resources.
328      *
329      * @return {@code true}, if the provider is validating resources; {@code false}, if the provider is not validating
330      * resources.
331      *
332      * @see #isDefaultValidating()
333      * @see #setValidating(java.lang.Boolean)
334      *
335      * @since 1.2
336      */
337     public final boolean isValidating()
338     {
339         if ( this.validating == null )
340         {
341             this.validating = isDefaultValidating();
342         }
343 
344         return this.validating;
345     }
346 
347     /**
348      * Sets the flag indicating the provider is validating resources.
349      *
350      * @param value The new value of the flag indicating the provider is validating resources or {@code null}.
351      *
352      * @see #isValidating()
353      *
354      * @since 1.2
355      */
356     public final void setValidating( final Boolean value )
357     {
358         this.validating = value;
359     }
360 
361     /**
362      * Searches a given context for {@code Modlets}.
363      *
364      * @param context The context to search for {@code Modlets}.
365      * @param location The location to search at.
366      *
367      * @return The {@code Modlets} found at {@code location} in {@code context} or {@code null}, if no {@code Modlets}
368      * are found.
369      *
370      * @throws NullPointerException if {@code context} or {@code location} is {@code null}.
371      * @throws ModelException if searching the context fails.
372      *
373      * @see #isValidating()
374      * @see #VALIDATING_ATTRIBUTE_NAME
375      */
376     public Modlets findModlets( final ModelContext context, final String location ) throws ModelException
377     {
378         if ( context == null )
379         {
380             throw new NullPointerException( "context" );
381         }
382         if ( location == null )
383         {
384             throw new NullPointerException( "location" );
385         }
386 
387         URL url = null;
388 
389         try
390         {
391             boolean contextValidating = this.isValidating();
392             if ( DEFAULT_VALIDATING == contextValidating
393                  && context.getAttribute( VALIDATING_ATTRIBUTE_NAME ) instanceof Boolean )
394             {
395                 contextValidating = (Boolean) context.getAttribute( VALIDATING_ATTRIBUTE_NAME );
396             }
397 
398             Modlets modlets = null;
399             final long t0 = System.currentTimeMillis();
400             final JAXBContext ctx = context.createContext( ModletObject.MODEL_PUBLIC_ID );
401             final Unmarshaller u = ctx.createUnmarshaller();
402             final Enumeration<URL> e = context.findResources( location );
403 
404             if ( contextValidating )
405             {
406                 u.setSchema( context.createSchema( ModletObject.MODEL_PUBLIC_ID ) );
407             }
408 
409             while ( e.hasMoreElements() )
410             {
411                 url = e.nextElement();
412                 Object content = u.unmarshal( url );
413                 if ( content instanceof JAXBElement<?> )
414                 {
415                     content = ( (JAXBElement<?>) content ).getValue();
416                 }
417 
418                 if ( content instanceof Modlet )
419                 {
420                     if ( modlets == null )
421                     {
422                         modlets = new Modlets();
423                     }
424 
425                     modlets.getModlet().add( (Modlet) content );
426                 }
427                 else if ( content instanceof Modlets )
428                 {
429                     if ( modlets == null )
430                     {
431                         modlets = new Modlets();
432                     }
433 
434                     modlets.getModlet().addAll( ( (Modlets) content ).getModlet() );
435                 }
436             }
437 
438             if ( context.isLoggable( Level.FINE ) )
439             {
440                 context.log( Level.FINE, getMessage( "contextReport",
441                                                      modlets != null ? modlets.getModlet().size() : 0,
442                                                      location, System.currentTimeMillis() - t0 ), null );
443 
444             }
445 
446             return modlets == null || modlets.getModlet().isEmpty() ? null : modlets;
447         }
448         catch ( final UnmarshalException e )
449         {
450             String message = getMessage( e );
451             if ( message == null && e.getLinkedException() != null )
452             {
453                 message = getMessage( e.getLinkedException() );
454             }
455 
456             if ( url != null )
457             {
458                 message = getMessage( "unmarshalException", url.toExternalForm(),
459                                       message != null ? " " + message : "" );
460 
461             }
462 
463             throw new ModelException( message, e );
464         }
465         catch ( final JAXBException e )
466         {
467             String message = getMessage( e );
468             if ( message == null && e.getLinkedException() != null )
469             {
470                 message = getMessage( e.getLinkedException() );
471             }
472 
473             throw new ModelException( message, e );
474         }
475     }
476 
477     /**
478      * {@inheritDoc}
479      *
480      * @return The {@code Modlets} found in the context or {@code null}, if no {@code Modlets} are found or the provider
481      * is disabled.
482      *
483      * @see #isEnabled()
484      * @see #getModletLocation()
485      * @see #findModlets(org.jomc.modlet.ModelContext, java.lang.String)
486      * @see #ENABLED_ATTRIBUTE_NAME
487      * @see #MODLET_LOCATION_ATTRIBUTE_NAME
488      */
489     public Modlets findModlets( final ModelContext context ) throws ModelException
490     {
491         if ( context == null )
492         {
493             throw new NullPointerException( "context" );
494         }
495 
496         Modlets found = null;
497 
498         boolean contextEnabled = this.isEnabled();
499         if ( DEFAULT_ENABLED == contextEnabled && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
500         {
501             contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME );
502         }
503 
504         String contextModletLocation = this.getModletLocation();
505         if ( DEFAULT_MODLET_LOCATION.equals( contextModletLocation )
506              && context.getAttribute( MODLET_LOCATION_ATTRIBUTE_NAME ) instanceof String )
507         {
508             contextModletLocation = (String) context.getAttribute( MODLET_LOCATION_ATTRIBUTE_NAME );
509         }
510 
511         if ( contextEnabled )
512         {
513             found = this.findModlets( context, contextModletLocation );
514         }
515         else if ( context.isLoggable( Level.FINER ) )
516         {
517             context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName() ), null );
518         }
519 
520         return found;
521     }
522 
523     private static String getMessage( final String key, final Object... arguments )
524     {
525         return MessageFormat.format( ResourceBundle.getBundle(
526             DefaultModletProvider.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
527 
528     }
529 
530     private static String getMessage( final Throwable t )
531     {
532         return t != null ? t.getMessage() != null ? t.getMessage() : getMessage( t.getCause() ) : null;
533     }
534 
535 }