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.renderkit.html;
20  
21  import java.io.IOException;
22  import java.util.Collections;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.NoSuchElementException;
28  import java.util.Set;
29  import java.util.logging.Level;
30  import java.util.logging.Logger;
31  
32  import javax.faces.application.FacesMessage;
33  import javax.faces.component.UIComponent;
34  import javax.faces.component.UIMessages;
35  import javax.faces.component.UIViewRoot;
36  import javax.faces.component.behavior.ClientBehavior;
37  import javax.faces.component.behavior.ClientBehaviorHolder;
38  import javax.faces.component.html.HtmlMessages;
39  import javax.faces.component.search.SearchExpressionContext;
40  import javax.faces.component.search.SearchExpressionHandler;
41  import javax.faces.component.search.SearchExpressionHint;
42  import javax.faces.context.FacesContext;
43  import javax.faces.context.ResponseWriter;
44  
45  import org.apache.myfaces.shared.renderkit.JSFAttr;
46  import org.apache.myfaces.shared.renderkit.RendererUtils;
47  
48  public abstract class HtmlMessagesRendererBase
49          extends HtmlMessageRendererBase
50  {
51      //private static final Log log = LogFactory.getLog(HtmlMessagesRendererBase.class);
52      private static final Logger log = Logger.getLogger(HtmlMessagesRendererBase.class.getName());
53  
54      protected static final String LAYOUT_LIST  = "list";
55      protected static final String LAYOUT_TABLE = "table";
56  
57      protected void renderMessages(FacesContext facesContext,
58                                    UIComponent messages)
59              throws IOException
60      {
61          renderMessages(facesContext, messages, false);
62      }
63  
64      protected void renderMessages(FacesContext facesContext,
65              UIComponent messages, boolean alwaysRenderSpan)
66              throws IOException
67      {
68          renderMessages(facesContext, messages, alwaysRenderSpan, false);
69      }
70  
71      protected void renderMessages(FacesContext facesContext,
72                                    UIComponent messages, boolean alwaysRenderSpan, 
73                                    boolean renderDivWhenNoMessagesAndIdSet)
74              throws IOException
75      {
76          // check the for attribute
77          String forAttr = getFor(messages);
78          //UIComponent forComponent = null;
79          String clientId = null;
80          if(forAttr != null && !"".equals(forAttr))
81          {
82              /*
83              forComponent = messages.findComponent(forAttr);
84              if (forComponent == null)
85              {
86                  log.severe("Could not render Messages. Unable to find component '"
87                          + forAttr + "' (calling findComponent on component '" 
88                          + messages.getClientId(facesContext)
89                          + "'). If the provided id was correct, wrap the message and its "
90                          + "component into an h:panelGroup or h:panelGrid.");
91                  return;
92              }*/
93              SearchExpressionHandler searchExpressionHandler = 
94                      facesContext.getApplication().getSearchExpressionHandler();
95              Set<SearchExpressionHint> expressionHints = new HashSet<SearchExpressionHint>();
96              expressionHints.add(SearchExpressionHint.IGNORE_NO_RESULT);
97              clientId = searchExpressionHandler.resolveClientId(
98                      SearchExpressionContext.createSearchExpressionContext(
99                              facesContext, messages, expressionHints, null), forAttr);
100             if (clientId == null)
101             {
102                 log.severe("Could not render Message. Unable to find component '" 
103                         + forAttr + "' (calling findComponent on component '" 
104                         + clientId
105                         + "'). If the provided id was correct, wrap the message and its " 
106                         + "component into an h:panelGroup or h:panelGrid.");
107                 return;
108             }
109         }
110         
111         MessagesIterator messagesIterator = new MessagesIterator(facesContext,
112                 isGlobalOnly(messages), isRedisplay(messages), clientId);
113 
114         if (messagesIterator.hasNext())
115         {
116             String layout = getLayout(messages);
117             if (layout == null)
118             {
119                 if (log.isLoggable(Level.FINE))
120                 {
121                     log.fine("No messages layout given, using default layout 'list'.");
122                 }
123                 renderList(facesContext, messages, messagesIterator);
124             }
125             else if (layout.equalsIgnoreCase(LAYOUT_TABLE))
126             {
127                 renderTable(facesContext, messages, messagesIterator);
128             }
129             else
130             {
131                 if (log.isLoggable(Level.WARNING) && !layout.equalsIgnoreCase(LAYOUT_LIST))
132                 {
133                     log.warning("Unsupported messages layout '" + layout + "' - using default layout 'list'.");
134                 }
135                 renderList(facesContext, messages, messagesIterator);
136             }
137         }
138         else
139         {
140             if (renderDivWhenNoMessagesAndIdSet && messages.getId() != null && 
141                     !messages.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
142             {
143                 ResponseWriter writer = facesContext.getResponseWriter();
144                 writer.startElement(HTML.DIV_ELEM, messages);
145                 writer.writeAttribute(HTML.ID_ATTR, messages.getClientId(facesContext), null);
146                 writer.endElement(HTML.DIV_ELEM);
147             }
148         }
149         
150         if (!renderDivWhenNoMessagesAndIdSet && alwaysRenderSpan)
151         {
152             Object forceSpan = messages.getAttributes().get("forceSpan");
153             boolean b = forceSpan instanceof Boolean ? (Boolean) forceSpan : Boolean.valueOf(forceSpan.toString());
154             if (b)
155             {
156                 ResponseWriter writer = facesContext.getResponseWriter();
157     
158                 writer.startElement(HTML.SPAN_ELEM, null);
159                 writer.writeAttribute(HTML.ID_ATTR,messages.getClientId(facesContext),null);
160                 if(messages.getAttributes().get(JSFAttr.STYLE_CLASS_ATTR)!=null)
161                 {
162                     writer.writeAttribute(
163                             HTML.CLASS_ATTR, messages.getAttributes().get(JSFAttr.STYLE_CLASS_ATTR), null);
164                 }
165                 if(messages.getAttributes().get(JSFAttr.STYLE_ATTR)!=null)
166                 {
167                     writer.writeAttribute(HTML.STYLE_ATTR, messages.getAttributes().get(JSFAttr.STYLE_ATTR), null);
168                 }
169                 writer.endElement(HTML.SPAN_ELEM);
170             }
171         }
172     }
173 
174 
175     private void renderList(FacesContext facesContext,
176                             UIComponent messages,
177                             MessagesIterator messagesIterator)
178             throws IOException
179     {
180         ResponseWriter writer = facesContext.getResponseWriter();
181 
182         writer.startElement(HTML.UL_ELEM, messages);
183 
184         Map<String, List<ClientBehavior>> behaviors = null;
185         if (messages instanceof ClientBehaviorHolder)
186         {
187             behaviors = ((ClientBehaviorHolder) messages).getClientBehaviors();
188         }
189         
190         if (behaviors != null && !behaviors.isEmpty())
191         {
192             writer.writeAttribute(HTML.ID_ATTR, messages.getClientId(facesContext), null);
193         }
194         else
195         {
196             HtmlRendererUtils.writeIdIfNecessary(writer, messages, facesContext);
197         }         
198         HtmlRendererUtils.renderHTMLAttributes(writer, messages, HTML.UNIVERSAL_ATTRIBUTES_WITHOUT_STYLE);
199 
200         HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_ATTR, HTML.STYLE_ATTR, getComponentStyle(messages));
201         HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_CLASS_ATTR, HTML.STYLE_CLASS_ATTR, 
202                 getComponentStyleClass(messages));
203 
204         while(messagesIterator.hasNext())
205         {
206             writer.startElement(org.apache.myfaces.shared.renderkit.html.HTML.LI_ELEM, null); //messages);
207             
208             FacesMessage facesMessage = (FacesMessage)messagesIterator.next();
209             // determine style and style class
210             String[] styleAndClass = getStyleAndStyleClass(messages, facesMessage.getSeverity());
211             String style = styleAndClass[0];
212             String styleClass = styleAndClass[1];
213             
214             HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_ATTR, HTML.STYLE_ATTR, style);
215             HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_CLASS_ATTR, HTML.STYLE_CLASS_ATTR, styleClass);
216             
217             renderSingleFacesMessage(facesContext,
218                     messages,
219                     facesMessage,
220                     messagesIterator.getClientId(),false,false,false);
221             writer.endElement(HTML.LI_ELEM);
222         }
223 
224         writer.endElement(HTML.UL_ELEM);
225     }
226 
227 
228     private void renderTable(FacesContext facesContext,
229                              UIComponent messages,
230                              MessagesIterator messagesIterator)
231             throws IOException
232     {
233         ResponseWriter writer = facesContext.getResponseWriter();
234 
235         writer.startElement(HTML.TABLE_ELEM, messages);
236         
237         Map<String, List<ClientBehavior>> behaviors = null;
238         if (messages instanceof ClientBehaviorHolder)
239         {
240             behaviors = ((ClientBehaviorHolder) messages).getClientBehaviors();
241         }
242         
243         if (behaviors != null && !behaviors.isEmpty())
244         {
245             writer.writeAttribute(HTML.ID_ATTR, messages.getClientId(facesContext), null);
246         }
247         else
248         {
249             HtmlRendererUtils.writeIdIfNecessary(writer, messages, facesContext);
250         }         
251         HtmlRendererUtils.renderHTMLAttributes(writer, messages, HTML.UNIVERSAL_ATTRIBUTES_WITHOUT_STYLE);
252         
253         HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_ATTR, HTML.STYLE_ATTR, getComponentStyle(messages));
254         HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_CLASS_ATTR, HTML.STYLE_CLASS_ATTR, 
255                 getComponentStyleClass(messages));
256         
257         while(messagesIterator.hasNext())
258         {
259             writer.startElement(HTML.TR_ELEM, null); // messages);
260             writer.startElement(HTML.TD_ELEM, null); // messages);
261             
262             FacesMessage facesMessage = (FacesMessage)messagesIterator.next();
263             // determine style and style class
264             String[] styleAndClass = getStyleAndStyleClass(messages, facesMessage.getSeverity());
265             String style = styleAndClass[0];
266             String styleClass = styleAndClass[1];
267             
268             HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_ATTR, HTML.STYLE_ATTR, style);
269             HtmlRendererUtils.renderHTMLAttribute(writer, HTML.STYLE_CLASS_ATTR, HTML.STYLE_CLASS_ATTR, styleClass);
270             
271             renderSingleFacesMessage(facesContext,
272                     messages,
273                     facesMessage,
274                     messagesIterator.getClientId(),false,false,false);
275 
276             writer.endElement(HTML.TD_ELEM);
277             writer.endElement(HTML.TR_ELEM);
278         }
279 
280         writer.endElement(HTML.TABLE_ELEM);
281     }
282 
283 
284     public static String[] getStyleAndStyleClass(UIComponent messages,
285                                              FacesMessage.Severity severity)
286     {
287         String style = null;
288         String styleClass = null;
289         if (messages instanceof HtmlMessages)
290         {
291             if (severity == FacesMessage.SEVERITY_INFO)
292             {
293                 style = ((HtmlMessages)messages).getInfoStyle();
294                 styleClass = ((HtmlMessages)messages).getInfoClass();
295             }
296             else if (severity == FacesMessage.SEVERITY_WARN)
297             {
298                 style = ((HtmlMessages)messages).getWarnStyle();
299                 styleClass = ((HtmlMessages)messages).getWarnClass();
300             }
301             else if (severity == FacesMessage.SEVERITY_ERROR)
302             {
303                 style = ((HtmlMessages)messages).getErrorStyle();
304                 styleClass = ((HtmlMessages)messages).getErrorClass();
305             }
306             else if (severity == FacesMessage.SEVERITY_FATAL)
307             {
308                 style = ((HtmlMessages)messages).getFatalStyle();
309                 styleClass = ((HtmlMessages)messages).getFatalClass();
310             }
311 
312             //if (style == null)
313             //{
314             //    style = ((HtmlMessages)messages).getStyle();
315             //}
316 
317             //if (styleClass == null)
318             //{
319             //    styleClass = ((HtmlMessages)messages).getStyleClass();
320             //}
321         }
322         else
323         {
324             Map attr = messages.getAttributes();
325             if (severity == FacesMessage.SEVERITY_INFO)
326             {
327                 style = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.INFO_STYLE_ATTR);
328                 styleClass = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.INFO_CLASS_ATTR);
329             }
330             else if (severity == FacesMessage.SEVERITY_WARN)
331             {
332                 style = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.WARN_STYLE_ATTR);
333                 styleClass = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.WARN_CLASS_ATTR);
334             }
335             else if (severity == FacesMessage.SEVERITY_ERROR)
336             {
337                 style = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.ERROR_STYLE_ATTR);
338                 styleClass = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.ERROR_CLASS_ATTR);
339             }
340             else if (severity == FacesMessage.SEVERITY_FATAL)
341             {
342                 style = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.FATAL_STYLE_ATTR);
343                 styleClass = (String)attr.get(JSFAttr.FATAL_CLASS_ATTR);
344             }
345 
346             //if (style == null)
347             //{
348             //    style = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.STYLE_ATTR);
349             //}
350 
351             //if (styleClass == null)
352             //{
353             //    styleClass = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.STYLE_CLASS_ATTR);
354             //}
355         }
356 
357         return new String[] {style, styleClass};
358     }
359     
360     protected String getComponentStyleClass(UIComponent messages)
361     {
362         String styleClass = null;
363         if (messages instanceof HtmlMessages)
364         {
365             styleClass = ((HtmlMessages)messages).getStyleClass();
366         }
367         else
368         {
369             Map attr = messages.getAttributes();
370             styleClass = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.STYLE_CLASS_ATTR);
371         }
372         return styleClass;
373     }
374     
375     protected String getComponentStyle(UIComponent messages)
376     {
377         String style = null;
378         if (messages instanceof HtmlMessages)
379         {
380             style = ((HtmlMessages)messages).getStyle();
381         }
382         else
383         {
384             Map attr = messages.getAttributes();
385             style = (String)attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.STYLE_ATTR);
386         }
387         return style;
388     }
389 
390     protected String getTitle(UIComponent component)
391     {
392         if (component instanceof HtmlMessages)
393         {
394             return ((HtmlMessages)component).getTitle();
395         }
396         else
397         {
398             return (String)component.getAttributes().get(org.apache.myfaces.shared.renderkit.JSFAttr.TITLE_ATTR);
399         }
400     }
401 
402     protected boolean isTooltip(UIComponent component)
403     {
404         if (component instanceof HtmlMessages)
405         {
406             return ((HtmlMessages)component).isTooltip();
407         }
408         else
409         {
410             return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(component, 
411                     org.apache.myfaces.shared.renderkit.JSFAttr.TOOLTIP_ATTR, false);
412         }
413     }
414 
415     protected boolean isShowSummary(UIComponent component)
416     {
417         if (component instanceof UIMessages)
418         {
419             return ((UIMessages)component).isShowSummary();
420         }
421         else
422         {
423             return RendererUtils.getBooleanAttribute(component, JSFAttr.SHOW_SUMMARY_ATTR, false);
424         }
425     }
426 
427     protected boolean isShowDetail(UIComponent component)
428     {
429         if (component instanceof UIMessages)
430         {
431             return ((UIMessages)component).isShowDetail();
432         }
433         else
434         {
435             return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
436                     component, JSFAttr.SHOW_DETAIL_ATTR, false);
437         }
438     }
439 
440     protected boolean isGlobalOnly(UIComponent component)
441     {
442         if (component instanceof UIMessages)
443         {
444             return ((UIMessages)component).isGlobalOnly();
445         }
446         else
447         {
448             return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
449                     component, JSFAttr.GLOBAL_ONLY_ATTR, false);
450         }
451     }
452 
453     protected String getLayout(UIComponent component)
454     {
455         if (component instanceof HtmlMessages)
456         {
457             return ((HtmlMessages)component).getLayout();
458         }
459         else
460         {
461             return (String)component.getAttributes().get(JSFAttr.LAYOUT_ATTR);
462         }
463     }
464     
465     protected String getFor(UIComponent component)
466     {
467         if (component instanceof UIMessages)
468         {
469             return ((UIMessages) component).getFor();
470         }
471  
472         return (String) component.getAttributes().get(JSFAttr.FOR_ATTR); 
473     }
474 
475     protected boolean isRedisplay(UIComponent component)
476     {
477         if (component instanceof UIMessages)
478         {
479             return ((UIMessages) component).isRedisplay();
480         }
481 
482         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(
483                 component, org.apache.myfaces.shared.renderkit.JSFAttr.REDISPLAY_ATTR, true);
484         
485     }
486 
487     private static class MessagesIterator implements Iterator
488     {
489         private FacesContext _facesContext;
490         private Iterator _globalMessagesIterator;
491         private Iterator _clientIdsWithMessagesIterator;
492         private Iterator _componentMessagesIterator = null;
493         private String _clientId = null;
494         private boolean _redisplay;
495         private Object _next;
496 
497         public MessagesIterator(FacesContext facesContext, boolean globalOnly, boolean redisplay,
498                 String clientId)
499         {
500             _facesContext = facesContext;
501             // The for attribute is mutually exclusive with globalOnly and take precedence if used.
502             if(clientId != null)
503             {
504                 _clientId = clientId;
505                 _componentMessagesIterator = facesContext.getMessages(_clientId);
506                 _globalMessagesIterator = Collections.emptyIterator();
507                 _clientIdsWithMessagesIterator = Collections.emptyIterator();
508             }
509             else 
510             {
511                 if (globalOnly)
512                 {
513                     _globalMessagesIterator = facesContext.getMessages(null);
514                     _clientIdsWithMessagesIterator = Collections.emptyIterator();
515                 }
516                 else
517                 {
518                     _globalMessagesIterator = Collections.emptyIterator();
519                     _clientIdsWithMessagesIterator = facesContext.getClientIdsWithMessages();
520                 }
521                 _componentMessagesIterator = null;
522                 _clientId = null;
523             }
524             
525             _redisplay = redisplay;
526             _next = null;
527         }
528 
529         public boolean hasNext()
530         {
531             if(_next != null)
532             {
533                 return true;
534             }
535             if(_globalMessagesIterator.hasNext()) 
536             {
537                 do
538                 {
539                     _next = _globalMessagesIterator.next();
540                     if(_redisplay || !((FacesMessage)_next).isRendered())
541                     {
542                         return true;
543                     }
544                 }
545                 while(_globalMessagesIterator.hasNext());
546             }
547             if(_componentMessagesIterator != null && _componentMessagesIterator.hasNext()) 
548             {
549                 do
550                 {
551                     _next = _componentMessagesIterator.next();
552                     if(_redisplay || !((FacesMessage)_next).isRendered())
553                     {
554                         return true;
555                     }
556                 }
557                 while(_componentMessagesIterator.hasNext());
558             }
559             if(_clientIdsWithMessagesIterator.hasNext()) 
560             {
561                 do
562                 {
563                     _clientId = (String) _clientIdsWithMessagesIterator.next();
564                     _componentMessagesIterator = _facesContext.getMessages(_clientId);
565                     while(_componentMessagesIterator.hasNext()) 
566                     {
567                         _next = _componentMessagesIterator.next();
568                         if(_redisplay || !((FacesMessage)_next).isRendered())
569                         {
570                             return true;
571                         }
572                     }
573                 }
574                 while(_clientIdsWithMessagesIterator.hasNext());
575                 
576             }
577             _next = null;
578             return false;
579         }
580 
581         public Object next()
582         {
583             if(this.hasNext()) 
584             {
585                 Object ret = _next;
586                 _next = null;
587                 return ret;
588             }
589             throw new NoSuchElementException();
590         }
591 
592         public void remove()
593         {
594             throw new UnsupportedOperationException(this.getClass().getName() + " UnsupportedOperationException");
595         }
596 
597         public String getClientId()
598         {
599             return _clientId;
600         }
601     }
602 
603 }