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