View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.shared.util;
20  
21  import java.text.MessageFormat;
22  import java.util.Locale;
23  import java.util.MissingResourceException;
24  import java.util.ResourceBundle;
25  import java.util.logging.Level;
26  import java.util.logging.Logger;
27  
28  import javax.el.ValueExpression;
29  import javax.faces.FactoryFinder;
30  import javax.faces.application.Application;
31  import javax.faces.application.ApplicationFactory;
32  import javax.faces.application.FacesMessage;
33  import javax.faces.component.UIComponent;
34  import javax.faces.context.FacesContext;
35  
36  /**
37   * Utility class to support multilingual FacesMessages using ResourceBundles.
38   * Standard messages are stored at <code>DEFAULT_BUNDLE</code>.<br>
39   * The summary of the message is stored at the requested key value. The detail
40   * of the message is stored at &lt;messageId&gt;_detail.
41   *
42   * @see FacesMessage
43   * @see java.util.ResourceBundle
44   *
45   * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
46   * @author Manfred Geiler
47   * @author Sean Schofield
48   * @author Stpehan Strittmatter
49   * @version $Revision: 1378433 $ $Date: 2012-08-28 22:19:33 -0500 (Tue, 28 Aug 2012) $
50   */
51  public final class MessageUtils
52  {
53      /** Utility class, do not instatiate */
54      private MessageUtils()
55      {
56          // nope
57      }
58  
59      /** Default bundle for messages (<code>javax.faces.Messages</code>) */
60      private static final String DEFAULT_BUNDLE = "javax.faces.Messages";
61  
62      /** Suffix for message details (<code>_detail</code>)*/
63      private static final String DETAIL_SUFFIX = "_detail";
64      //private static Log log = LogFactory.getLog(MessageUtils.class);
65      private static Logger log = Logger.getLogger(MessageUtils.class.getName());
66  
67      /**
68       * @param severity serverity of message
69       * @param messageId id of message
70       * @param arg arument of message
71       *
72       * @return generated FacesMessage
73       */
74      public static FacesMessage getMessage(FacesMessage.Severity severity,
75                                            String messageId,
76                                            Object arg)
77      {
78          return getMessage(severity,
79                            messageId,
80                            new Object[]{arg},
81                            FacesContext.getCurrentInstance());
82      }
83      
84      public static FacesMessage getMessage(String bundleBaseName, 
85              FacesMessage.Severity severity,
86              String messageId,
87              Object arg)
88      {
89          return getMessage(bundleBaseName,
90                            severity,
91                            messageId,
92                            new Object[]{arg},
93                            FacesContext.getCurrentInstance());
94      }
95  
96      /**
97       * @param severity serverity of message
98       * @param messageId id of message
99       * @param args aruments of message
100      *
101      * @return generated FacesMessage
102      */
103     public static FacesMessage getMessage(FacesMessage.Severity severity,
104                                           String messageId,
105                                           Object[] args)
106     {
107         return getMessage(severity,
108                           messageId,
109                           args,
110                           FacesContext.getCurrentInstance());
111     }
112     
113     public static FacesMessage getMessage(String bundleBaseName, 
114             FacesMessage.Severity severity,
115             String messageId,
116             Object[] args)
117     {
118         return getMessage(bundleBaseName,
119                           severity,
120                           messageId,
121                           args,
122                           FacesContext.getCurrentInstance());
123     }    
124 
125     public static FacesMessage getMessage(FacesMessage.Severity severity,
126                                           String messageId,
127                                           Object[] args,
128                                           FacesContext facesContext)
129     {
130         FacesMessage message = getMessage(facesContext, messageId, args);
131         message.setSeverity(severity);
132 
133         return message;
134     }
135 
136     public static FacesMessage getMessage(String bundleBaseName,
137             FacesMessage.Severity severity,
138             String messageId,
139             Object[] args,
140             FacesContext facesContext)
141     {
142         FacesMessage message = getMessage(bundleBaseName, facesContext, messageId, args);
143         message.setSeverity(severity);
144         
145         return message;
146     }
147 
148     public static void addMessage(FacesMessage.Severity severity,
149                                   String messageId,
150                                   Object[] args)
151     {
152         addMessage(severity, messageId, args, null, FacesContext.getCurrentInstance());
153     }
154 
155     public static void addMessage(String bundleBaseName, 
156             FacesMessage.Severity severity,
157             String messageId,
158             Object[] args)
159     {
160         addMessage(bundleBaseName, severity, messageId, args, null, FacesContext.getCurrentInstance());
161     }
162 
163     public static void addMessage(FacesMessage.Severity severity,
164                                   String messageId,
165                                   Object[] args,
166                                   FacesContext facesContext)
167     {
168         addMessage(severity, messageId, args, null, facesContext);
169     }
170 
171     public static void addMessage(String bundleBaseName, 
172             FacesMessage.Severity severity,
173             String messageId,
174             Object[] args,
175             FacesContext facesContext)
176     {
177         addMessage(bundleBaseName, severity, messageId, args, null, facesContext);
178     }
179 
180     public static void addMessage(FacesMessage.Severity severity,
181                                   String messageId,
182                                   Object[] args,
183                                   String forClientId)
184     {
185         addMessage(severity, messageId, args, forClientId, FacesContext.getCurrentInstance());
186     }
187 
188     public static void addMessage(String bundleBaseName,
189             FacesMessage.Severity severity,
190             String messageId,
191             Object[] args,
192             String forClientId)
193     {
194         addMessage(bundleBaseName, severity, messageId, args, forClientId, FacesContext.getCurrentInstance());
195     }
196 
197     public static void addMessage(FacesMessage.Severity severity,
198                                   String messageId,
199                                   Object[] args,
200                                   String forClientId,
201                                   FacesContext facesContext)
202     {
203         if(log.isLoggable(Level.FINEST))
204         {
205           log.finest("adding message " + messageId + " for clientId " + forClientId);
206         }
207         facesContext.addMessage(forClientId,
208                                 getMessage(severity, messageId, args, facesContext));
209     }
210 
211     public static void addMessage(String bundleBaseName,
212             FacesMessage.Severity severity,
213             String messageId,
214             Object[] args,
215             String forClientId,
216             FacesContext facesContext)
217     {
218         if(log.isLoggable(Level.FINEST))
219         {
220           log.finest("adding message " + messageId + " for clientId " + forClientId);
221         }
222         facesContext.addMessage(forClientId,
223                   getMessage(bundleBaseName, severity, messageId, args, facesContext));
224     }
225 
226     /**
227      * Uses <code>MessageFormat</code> and the supplied parameters to fill in the param placeholders in the String.
228      *
229      * @param locale The <code>Locale</code> to use when performing the substitution.
230      * @param msgtext The original parameterized String.
231      * @param params The params to fill in the String with.
232      * @return The updated String.
233      */
234     public static String substituteParams(Locale locale, String msgtext, Object params[])
235     {
236         String localizedStr = null;
237         if(params == null || msgtext == null)
238         {
239             return msgtext;
240         }
241 
242         if(locale != null)
243         {
244             MessageFormat mf = new MessageFormat(msgtext,locale);            
245             localizedStr = mf.format(params);
246         }
247         return localizedStr;
248     }
249 
250     public static FacesMessage getMessage(String messageId, Object params[])
251     {
252         Locale locale = getCurrentLocale();
253         return getMessage(locale, messageId, params);
254     }
255 
256     public static FacesMessage getMessageFromBundle(String bundleBaseName, String messageId, Object params[])
257     {
258         Locale locale = null;
259         FacesContext context = FacesContext.getCurrentInstance();
260         if(context != null && context.getViewRoot() != null)
261         {
262             locale = context.getViewRoot().getLocale();
263             if(locale == null)
264             {
265                 locale = Locale.getDefault();
266             }
267         }
268         else
269         {
270             locale = Locale.getDefault();
271         }
272         return getMessageFromBundle(bundleBaseName, context , locale, messageId, params);
273     }
274 
275     public static FacesMessage getMessage(Locale locale, String messageId, Object params[])
276     {
277         String summary = null;
278         String detail = null;
279         String bundleName = getApplication().getMessageBundle();
280         ResourceBundle bundle = null;
281 
282         if (bundleName != null)
283         {
284             try
285             {
286                 bundle = ResourceBundle.getBundle(bundleName, locale, 
287                         org.apache.myfaces.shared.util.ClassUtils.getCurrentLoader(bundleName));
288                 summary = bundle.getString(messageId);
289             }
290             catch (MissingResourceException e)
291             {
292                 // NoOp
293             }
294         }
295 
296         if (summary == null)
297         {
298             try
299             {
300                 bundle = ResourceBundle.getBundle(DEFAULT_BUNDLE, locale, 
301                         org.apache.myfaces.shared.util.ClassUtils.getCurrentLoader(DEFAULT_BUNDLE));
302                 if(bundle == null)
303                 {
304                     throw new NullPointerException();
305                 }
306                 summary = bundle.getString(messageId);
307             }
308             catch(MissingResourceException e)
309             {
310                 // NoOp
311             }
312         }
313 
314         if(summary == null)
315         {
316             summary = messageId;
317         }
318 
319         if (bundle == null)
320         {
321             throw new NullPointerException(
322                 "Unable to locate ResourceBundle: bundle is null");
323         }
324         if (params != null && locale != null)
325         {
326             try
327             {
328                 detail = bundle.getString(messageId + DETAIL_SUFFIX);
329             }
330             catch(MissingResourceException e)
331             {
332                 // NoOp
333             }
334             return new ParametrizableFacesMessage(summary, detail, params, locale);
335         }
336         else
337         {
338             summary = substituteParams(locale, summary, params);
339             try
340             {
341                 detail = substituteParams(locale,
342                     bundle.getString(messageId + DETAIL_SUFFIX), params);
343             }
344             catch(MissingResourceException e)
345             {
346                 // NoOp
347             }
348             return new FacesMessage(summary, detail);
349         }
350     }
351     
352     public static FacesMessage getMessageFromBundle(String bundleBaseName, 
353             FacesContext context, Locale locale, String messageId, Object params[])
354     {
355         String summary = null;
356         String detail = null;
357         String bundleName = context.getApplication().getMessageBundle();
358         ResourceBundle bundle = null;
359 
360         if (bundleName != null)
361         {
362             try
363             {
364                 bundle = ResourceBundle.getBundle(bundleName, locale, 
365                         org.apache.myfaces.shared.util.ClassUtils.getCurrentLoader(bundleName));
366                 summary = bundle.getString(messageId);
367             }
368             catch (MissingResourceException e)
369             {
370                 // NoOp
371             }
372         }
373 
374         if (summary == null)
375         {
376             try
377             {
378                 bundle = ResourceBundle.getBundle(bundleBaseName, locale, 
379                         org.apache.myfaces.shared.util.ClassUtils.getCurrentLoader(bundleBaseName));
380                 if(bundle == null)
381                 {
382                     throw new NullPointerException();
383                 }
384                 summary = bundle.getString(messageId);
385             }
386             catch(MissingResourceException e)
387             {
388                 // NoOp
389             }
390         }
391         
392         if (summary == null)
393         {
394             try
395             {
396                 bundle = ResourceBundle.getBundle(DEFAULT_BUNDLE, locale, 
397                         org.apache.myfaces.shared.util.ClassUtils.getCurrentLoader(DEFAULT_BUNDLE));
398                 if(bundle == null)
399                 {
400                     throw new NullPointerException();
401                 }
402                 summary = bundle.getString(messageId);
403             }
404             catch(MissingResourceException e)
405             {
406                 // NoOp
407             }
408         }
409 
410         if(summary == null)
411         {
412             summary = messageId;
413         }
414 
415         if (bundle == null)
416         {
417             throw new NullPointerException(
418                 "Unable to locate ResourceBundle: bundle is null");
419         }
420         
421         if (params != null && locale != null)
422         {
423             try
424             {
425                 detail = bundle.getString(messageId + DETAIL_SUFFIX);
426             }
427             catch(MissingResourceException e)
428             {
429                 // NoOp
430             }
431             return new ParametrizableFacesMessage(summary, detail, params, locale);
432         }
433         else
434         {
435             summary = substituteParams(locale, summary, params);
436             try
437             {
438                 detail = substituteParams(locale,
439                     bundle.getString(messageId + DETAIL_SUFFIX), params);
440             }
441             catch(MissingResourceException e)
442             {
443                 // NoOp
444             }
445             return new FacesMessage(summary, detail);
446         }
447     }
448 
449     /**
450      *  Retrieve the message from a specific bundle. It does not look on application message bundle
451      * or default message bundle. If it is required to look on those bundles use getMessageFromBundle instead
452      * 
453      * @param bundleBaseName baseName of ResourceBundle to load localized messages
454      * @param messageId id of message
455      * @param params parameters to set at localized message
456      * @return generated FacesMessage
457      */
458     public static FacesMessage getMessage(String bundleBaseName, String messageId, Object params[])
459     {
460         return getMessage(bundleBaseName, getCurrentLocale(), messageId, params);
461     }
462     
463     /**
464      * 
465      * @return  currently applicable Locale for this request.
466      */
467     public static Locale getCurrentLocale()
468     {
469         return getCurrentLocale(FacesContext.getCurrentInstance());
470     }
471     
472     public static Locale getCurrentLocale(FacesContext context)
473     {
474         Locale locale;
475         if(context != null && context.getViewRoot() != null)
476         {
477             locale = context.getViewRoot().getLocale();
478             if(locale == null)
479             {
480                 locale = Locale.getDefault();
481             }
482         }
483         else
484         {
485             locale = Locale.getDefault();
486         }
487         
488         return locale;
489     }
490 
491     /**
492      * @param severity severity of message
493      * @param bundleBaseName baseName of ResourceBundle to load localized messages
494      * @param messageId id of message
495      * @param params parameters to set at localized message
496      * @return generated FacesMessage
497      */
498     public static FacesMessage getMessage(FacesMessage.Severity severity, String bundleBaseName, 
499             String messageId, Object params[])
500     {
501       FacesMessage msg = getMessage(bundleBaseName, messageId, params);
502       msg.setSeverity(severity);
503 
504       return msg;
505     }
506 
507     /**
508      *  Retrieve the message from a specific bundle. It does not look on application message bundle
509      * or default message bundle. If it is required to look on those bundles use getMessageFromBundle instead
510      * 
511      * @param bundleBaseName baseName of ResourceBundle to load localized messages
512      * @param locale current locale
513      * @param messageId id of message
514      * @param params parameters to set at localized message
515      * @return generated FacesMessage
516      */
517     public static FacesMessage getMessage(String bundleBaseName, Locale locale, String messageId, Object params[])
518     {
519       if (bundleBaseName == null)
520       {
521           throw new NullPointerException(
522               "Unable to locate ResourceBundle: bundle is null");
523       }
524 
525       ResourceBundle bundle = ResourceBundle.getBundle(bundleBaseName, locale);
526 
527       return getMessage(bundle, messageId, params);
528     }
529     /**
530      * @param bundle ResourceBundle to load localized messages
531      * @param messageId id of message
532      * @param params parameters to set at localized message
533      * @return generated FacesMessage
534      */
535     public static FacesMessage getMessage(ResourceBundle bundle, String messageId, Object params[])
536     {
537 
538       String summary = null;
539       String detail = null;
540 
541       try
542       {
543           summary = bundle.getString(messageId);
544       }
545       catch (MissingResourceException e)
546       {
547         // NoOp
548       }
549 
550 
551       if(summary == null)
552       {
553           summary = messageId;
554       }
555 
556       summary = substituteParams(bundle.getLocale(), summary, params);
557 
558       try
559       {
560           detail = substituteParams(bundle.getLocale(),
561               bundle.getString(messageId + DETAIL_SUFFIX), params);
562       }
563       catch(MissingResourceException e)
564       {
565         // NoOp
566       }
567 
568       return new FacesMessage(summary, detail);
569     }
570 
571     /**
572      *
573      * @param context
574      * @param messageId
575      * @return generated FacesMessage
576      */
577     public static FacesMessage getMessage(FacesContext context, String messageId)
578     {
579         return getMessage(context, messageId, ((Object []) (null)));
580     }
581     
582     public static FacesMessage getMessage(String bundleBaseName, FacesContext context, String messageId)
583     {
584         return getMessage(bundleBaseName, context, messageId, ((Object []) (null)));
585     }
586 
587     /**
588      *
589      * @param context
590      * @param messageId
591      * @param params
592      * @return generated FacesMessage
593      */
594     public static FacesMessage getMessage(FacesContext context, String messageId, Object params[])
595     {
596         if(context == null || messageId == null)
597         {
598             throw new NullPointerException(" context " + context + " messageId " + messageId);
599         }
600         Locale locale = getCurrentLocale(context);
601         if(null == locale)
602         {
603             throw new NullPointerException(" locale " + locale);
604         }
605         FacesMessage message = getMessage(locale, messageId, params);
606         if(message != null)
607         {
608             return message;
609         } 
610         else
611         {
612             // TODO /FIX:  Note that this has fallback behavior to default Locale for message,
613             // but similar behavior above does not.  The methods should probably behave
614             locale = Locale.getDefault();
615             return getMessage(locale, messageId, params);
616         }
617     }
618     
619     public static FacesMessage getMessage(String bundleBaseName, FacesContext context, 
620             String messageId, Object params[])
621     {
622         if(context == null || messageId == null)
623         {
624             throw new NullPointerException(" context " + context + " messageId " + messageId);
625         }
626         Locale locale = getCurrentLocale(context);
627         if(null == locale)
628         {
629             throw new NullPointerException(" locale " + locale);
630         }
631         FacesMessage message = getMessageFromBundle(bundleBaseName, context, locale, messageId, params);
632         if(message != null)
633         {
634             return message;
635         } 
636         else
637         {
638             // TODO /FIX:  Note that this has fallback behavior to default Locale for message,
639             // but similar behavior above does not.  The methods should probably behave
640             locale = Locale.getDefault();
641             return getMessageFromBundle(bundleBaseName, context, locale, messageId, params);
642         }
643     }
644     
645     public static Object getLabel(FacesContext facesContext, UIComponent component)
646     {
647         Object label = component.getAttributes().get("label");
648         ValueExpression expression = null;
649         if (label != null && 
650             label instanceof String && ((String)label).length() == 0 )
651         {
652             // Note component.getAttributes().get("label") internally try to 
653             // evaluate the EL expression for the label, but in some cases, 
654             // when PSS is disabled and f:loadBundle is used, when the view is 
655             // restored the bundle is not set to the EL expression returns an 
656             // empty String. It is not possible to check if there is a 
657             // hardcoded label, but we can check if there is
658             // an EL expression set, so the best in this case is use that, and if
659             // there is an EL expression set, use it, otherwise use the hardcoded
660             // value. See MYFACES-3591 for details.
661             expression = component.getValueExpression("label");
662             if (expression != null)
663             {
664                 // Set the label to null and use the EL expression instead.
665                 label = null;
666             }
667         }
668             
669         if(label != null)
670         {
671             return label;
672         }
673         
674         expression = (expression == null) ? component.getValueExpression("label") : expression;
675         if(expression != null)
676         {
677             return expression;
678         }
679         
680         //If no label is not specified, use clientId
681         return component.getClientId( facesContext );
682     }
683 
684     private static Application getApplication()
685     {
686         FacesContext context = FacesContext.getCurrentInstance();
687         if(context != null)
688         {
689             return context.getApplication();
690         }
691         else
692         {
693             ApplicationFactory afactory = (ApplicationFactory)FactoryFinder.getFactory(
694                     "javax.faces.application.ApplicationFactory");
695             return afactory.getApplication();
696         }
697     }
698 }