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.logging.Logger;
26  
27  import javax.faces.application.FacesMessage;
28  import javax.faces.component.UIComponent;
29  import javax.faces.component.UIMessage;
30  import javax.faces.component.UIViewRoot;
31  import javax.faces.component.behavior.ClientBehavior;
32  import javax.faces.component.behavior.ClientBehaviorHolder;
33  import javax.faces.component.html.HtmlMessage;
34  import javax.faces.context.FacesContext;
35  import javax.faces.context.ResponseWriter;
36  
37  import org.apache.myfaces.shared.renderkit.JSFAttr;
38  import org.apache.myfaces.shared.renderkit.RendererUtils;
39  
40  public abstract class HtmlMessageRendererBase
41          extends HtmlRenderer
42  {
43      //private static final Log log = LogFactory.getLog(HtmlMessageRendererBase.class);
44      private static final Logger log = Logger.getLogger(HtmlMessageRendererBase.class.getName());
45  
46      protected abstract String getSummary(FacesContext facesContext,
47                                           UIComponent message,
48                                           FacesMessage facesMessage,
49                                           String msgClientId);
50  
51      protected abstract String getDetail(FacesContext facesContext,
52                                          UIComponent message,
53                                          FacesMessage facesMessage,
54                                          String msgClientId);
55  
56  
57      protected void renderMessage(FacesContext facesContext,
58                                   UIComponent message)
59              throws IOException
60      {
61          renderMessage(facesContext, message, false);
62      }
63  
64      protected void renderMessage(FacesContext facesContext, UIComponent message, 
65              boolean alwaysRenderSpan) throws IOException
66      {
67          renderMessage(facesContext, message, alwaysRenderSpan, false);
68      }
69      
70      /**
71       * @param facesContext
72       * @param message
73       * @param alwaysRenderSpan if true will render a span even if there is no message
74       */
75      protected void renderMessage(FacesContext facesContext, UIComponent message, 
76              boolean alwaysRenderSpan, boolean renderDivWhenNoMessagesAndIdSet) throws IOException
77      {
78          String forAttr = getFor(message);
79          if (forAttr == null)
80          {
81              log.severe("Attribute 'for' of UIMessage must not be null");
82              return;
83          }
84  
85          UIComponent forComponent = message.findComponent(forAttr);
86          if (forComponent == null)
87          {
88              log.severe("Could not render Message. Unable to find component '" 
89                      + forAttr + "' (calling findComponent on component '" 
90                      + message.getClientId(facesContext) 
91                      + "'). If the provided id was correct, wrap the message and its " 
92                      + "component into an h:panelGroup or h:panelGrid.");
93              return;
94          }
95  
96          String clientId = forComponent.getClientId(facesContext);
97  
98          Iterator<FacesMessage> messageIterator = facesContext.getMessages(clientId);
99          if (!messageIterator.hasNext())
100         {
101             // No associated message, nothing to render
102             if (alwaysRenderSpan)
103             {
104                 ResponseWriter writer = facesContext.getResponseWriter();
105                 writer.startElement(HTML.SPAN_ELEM, message);
106                 writer.writeAttribute(HTML.ID_ATTR, clientId + "_msgFor", null);
107                 HtmlRendererUtils.renderHTMLStringAttribute(writer, message, JSFAttr.STYLE_ATTR, HTML.STYLE_ATTR);
108                 HtmlRendererUtils.renderHTMLStringAttribute(writer, message, JSFAttr.STYLE_CLASS_ATTR, HTML.CLASS_ATTR);
109                 writer.endElement(HTML.SPAN_ELEM);
110             }
111             else if (renderDivWhenNoMessagesAndIdSet && message.getId() != null && 
112                     !message.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
113             {
114                 // show span anyways in case there's a client side update, ie: ajax
115                 ResponseWriter writer = facesContext.getResponseWriter();
116                 writer.startElement(HTML.SPAN_ELEM, message);
117                 writer.writeAttribute(HTML.ID_ATTR, message.getClientId(facesContext), null);
118                 writer.endElement(HTML.SPAN_ELEM);
119             }
120             return;
121         }
122         
123         // get first message
124         FacesMessage facesMessage = (FacesMessage) messageIterator.next();
125         
126         // check for the redisplay attribute and for the messages which have already been rendered
127         if(!isRedisplay(message)) 
128         {
129             while(facesMessage.isRendered())
130             {
131                 if(messageIterator.hasNext()) 
132                 {
133                     // get the next message
134                     facesMessage = (FacesMessage) messageIterator.next();
135                 }
136                 else 
137                 {
138                     // no more message to be rendered
139                     return; 
140                 }
141             }
142         }
143 
144         // and render it
145         renderSingleFacesMessage(facesContext, message, facesMessage, clientId);
146     }
147 
148 
149     protected void renderSingleFacesMessage(FacesContext facesContext,
150                                             UIComponent message,
151                                             FacesMessage facesMessage,
152                                             String messageClientId)
153             throws IOException
154     {
155         renderSingleFacesMessage(facesContext, message, facesMessage, messageClientId,true);
156     }
157     
158     protected void renderSingleFacesMessage(FacesContext facesContext,
159             UIComponent message,
160             FacesMessage facesMessage,
161             String messageClientId,
162             boolean renderId)
163     throws IOException
164     {
165         renderSingleFacesMessage(facesContext, message, facesMessage, messageClientId, renderId, true);
166     }
167 
168     protected void renderSingleFacesMessage(FacesContext facesContext,
169             UIComponent message,
170             FacesMessage facesMessage,
171             String messageClientId,
172             boolean renderId,
173             boolean renderStyleAndStyleClass)
174     throws IOException
175     {
176         Map<String, List<ClientBehavior>> behaviors = null;
177         if (message instanceof ClientBehaviorHolder)
178         {
179             behaviors = ((ClientBehaviorHolder) message).getClientBehaviors();
180         }
181         boolean wrapSpan = (message.getId() != null && !message.getId().startsWith(UIViewRoot.UNIQUE_ID_PREFIX)) 
182             || (behaviors != null && !behaviors.isEmpty());
183 
184         renderSingleFacesMessage(facesContext, message, facesMessage, messageClientId, 
185                 renderId, renderStyleAndStyleClass, wrapSpan);
186     }
187     
188     protected void renderSingleFacesMessage(FacesContext facesContext,
189                                             UIComponent message,
190                                             FacesMessage facesMessage,
191                                             String messageClientId,
192                                             boolean renderId,
193                                             boolean renderStyleAndStyleClass,
194                                             boolean wrapSpan)
195             throws IOException
196     {
197         // determine style and style class
198         String[] styleAndClass = HtmlMessageRendererBase.getStyleAndStyleClass(
199                 message, facesMessage.getSeverity());
200         String style = styleAndClass[0];
201         String styleClass = styleAndClass[1];
202 
203         String summary = getSummary(facesContext, message, facesMessage, messageClientId);
204         String detail = getDetail(facesContext, message, facesMessage, messageClientId);
205 
206         String title = getTitle(message);
207         boolean tooltip = isTooltip(message);
208 
209         boolean showSummary = isShowSummary(message) && (summary != null);
210         boolean showDetail = isShowDetail(message) && (detail != null);
211         
212         if (title == null && tooltip)
213         {
214             if (showDetail)
215             {
216                 title = detail;
217             }
218             else if (detail != null)
219             {
220                 title = detail;
221             }
222             else
223             {
224                 title = summary;
225             }
226         }
227 
228         ResponseWriter writer = facesContext.getResponseWriter();
229 
230         boolean span = false;
231 
232         Map<String, List<ClientBehavior>> behaviors = null;
233         if (message instanceof ClientBehaviorHolder)
234         {
235             behaviors = ((ClientBehaviorHolder) message).getClientBehaviors();
236             // If there is a behavior registered, force wrapSpan
237             wrapSpan = wrapSpan || !behaviors.isEmpty();
238         }
239         
240         if ( wrapSpan )
241         {
242             span = true;
243 
244             writer.startElement(HTML.SPAN_ELEM, message);
245 
246             if (behaviors != null && !behaviors.isEmpty())
247             {
248                 //force id rendering, because the client behavior could require it
249                 writer.writeAttribute(HTML.ID_ATTR, message.getClientId(facesContext),null);
250             }
251             else if (renderId)
252             {
253                 HtmlRendererUtils.writeIdIfNecessary(writer, message, facesContext);
254             }
255             if (message instanceof ClientBehaviorHolder)
256             {
257                 behaviors = ((ClientBehaviorHolder) message).getClientBehaviors();
258                 if (behaviors.isEmpty() && isCommonPropertiesOptimizationEnabled(facesContext))
259                 {
260                     CommonPropertyUtils.renderEventProperties(writer, 
261                             CommonPropertyUtils.getCommonPropertiesMarked(message), message);
262                 }
263                 else
264                 {
265                     if (isCommonEventsOptimizationEnabled(facesContext))
266                     {
267                         CommonEventUtils.renderBehaviorizedEventHandlers(facesContext, writer, 
268                                CommonPropertyUtils.getCommonPropertiesMarked(message),
269                                CommonEventUtils.getCommonEventsMarked(message), message, behaviors);
270                     }
271                     else
272                     {
273                         HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, message, behaviors);
274                     }
275                 }
276                 HtmlRendererUtils.renderHTMLAttributes(writer, message, 
277                         HTML.UNIVERSAL_ATTRIBUTES_WITHOUT_STYLE_AND_TITLE);
278             }
279             else
280             {
281                 HtmlRendererUtils.renderHTMLAttributes(writer, message, 
282                         HTML.MESSAGE_PASSTHROUGH_ATTRIBUTES_WITHOUT_TITLE_STYLE_AND_STYLE_CLASS);
283             }
284         }
285         else
286         {
287             span = HtmlRendererUtils.renderHTMLAttributesWithOptionalStartElement(
288                     writer, message, HTML.SPAN_ELEM, 
289                     HTML.MESSAGE_PASSTHROUGH_ATTRIBUTES_WITHOUT_TITLE_STYLE_AND_STYLE_CLASS);
290         }
291 
292         span |= HtmlRendererUtils.renderHTMLAttributeWithOptionalStartElement(
293                 writer, message, HTML.SPAN_ELEM, HTML.TITLE_ATTR, title, span);
294         if (renderStyleAndStyleClass)
295         {
296             span |= HtmlRendererUtils.renderHTMLAttributeWithOptionalStartElement(
297                     writer, message, HTML.SPAN_ELEM, HTML.STYLE_ATTR, style, span);
298             span |= HtmlRendererUtils.renderHTMLAttributeWithOptionalStartElement(
299                     writer, message, HTML.SPAN_ELEM, HTML.STYLE_CLASS_ATTR, styleClass, span);
300             // Remember if renderStyleAndStyleClass is true, it means style and styleClass
301             // are rendered on the outer tag, and in that sense, role attribute should
302             // be rendered there too.
303             span |= HtmlRendererUtils.renderHTMLAttributeWithOptionalStartElement(
304                     writer, message, HTML.ROLE_ATTR, HTML.ROLE_ATTR, 
305                     message.getAttributes().get(HTML.ROLE_ATTR), span);
306         }
307 
308         if (showSummary && !(title == null && tooltip))
309         {
310             writer.writeText(summary, null);
311             if (showDetail)
312             {
313                 writer.writeText(" ", null);
314             }
315         }
316 
317         if (showDetail)
318         {
319             writer.writeText(detail, null);
320         }
321 
322         if (span)
323         {
324             writer.endElement(org.apache.myfaces.shared.renderkit.html.HTML.SPAN_ELEM);
325         }
326         
327         // note that this FacesMessage already has been rendered 
328         facesMessage.rendered();
329     }
330 
331 
332     public static String[] getStyleAndStyleClass(UIComponent message,
333                                                  FacesMessage.Severity severity)
334     {
335         String style = null;
336         String styleClass = null;
337         if (message instanceof HtmlMessage)
338         {
339             if (severity == FacesMessage.SEVERITY_INFO)
340             {
341                 style = ((HtmlMessage) message).getInfoStyle();
342                 styleClass = ((HtmlMessage) message).getInfoClass();
343             }
344             else if (severity == FacesMessage.SEVERITY_WARN)
345             {
346                 style = ((HtmlMessage) message).getWarnStyle();
347                 styleClass = ((HtmlMessage) message).getWarnClass();
348             }
349             else if (severity == FacesMessage.SEVERITY_ERROR)
350             {
351                 style = ((HtmlMessage) message).getErrorStyle();
352                 styleClass = ((HtmlMessage) message).getErrorClass();
353             }
354             else if (severity == FacesMessage.SEVERITY_FATAL)
355             {
356                 style = ((HtmlMessage) message).getFatalStyle();
357                 styleClass = ((HtmlMessage) message).getFatalClass();
358             }
359 
360             if (style == null)
361             {
362                 style = ((HtmlMessage) message).getStyle();
363             }
364 
365             if (styleClass == null)
366             {
367                 styleClass = ((HtmlMessage) message).getStyleClass();
368             }
369         }
370         else
371         {
372             Map<String, Object> attr = message.getAttributes();
373             if (severity == FacesMessage.SEVERITY_INFO)
374             {
375                 style = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.INFO_STYLE_ATTR);
376                 styleClass = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.INFO_CLASS_ATTR);
377             }
378             else if (severity == FacesMessage.SEVERITY_WARN)
379             {
380                 style = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.WARN_STYLE_ATTR);
381                 styleClass = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.WARN_CLASS_ATTR);
382             }
383             else if (severity == FacesMessage.SEVERITY_ERROR)
384             {
385                 style = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.ERROR_STYLE_ATTR);
386                 styleClass = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.ERROR_CLASS_ATTR);
387             }
388             else if (severity == FacesMessage.SEVERITY_FATAL)
389             {
390                 style = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.FATAL_STYLE_ATTR);
391                 styleClass = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.FATAL_CLASS_ATTR);
392             }
393 
394             if (style == null)
395             {
396                 style = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.STYLE_ATTR);
397             }
398 
399             if (styleClass == null)
400             {
401                 styleClass = (String) attr.get(org.apache.myfaces.shared.renderkit.JSFAttr.STYLE_CLASS_ATTR);
402             }
403         }
404 
405         return new String[]{style, styleClass};
406     }
407 
408     protected String getFor(UIComponent component)
409     {
410         if (component instanceof UIMessage)
411         {
412             return ((UIMessage) component).getFor();
413         }
414  
415         return (String) component.getAttributes().get(JSFAttr.FOR_ATTR);
416         
417     }
418 
419     protected String getTitle(UIComponent component)
420     {
421         if (component instanceof HtmlMessage)
422         {
423             return ((HtmlMessage) component).getTitle();
424         }
425 
426         return (String) component.getAttributes().get(JSFAttr.TITLE_ATTR);
427         
428     }
429 
430     protected boolean isTooltip(UIComponent component)
431     {
432         if (component instanceof HtmlMessage)
433         {
434             return ((HtmlMessage) component).isTooltip();
435         }
436 
437         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(component, 
438                 org.apache.myfaces.shared.renderkit.JSFAttr.TOOLTIP_ATTR, false);
439         
440     }
441 
442     protected boolean isShowSummary(UIComponent component)
443     {
444         if (component instanceof UIMessage)
445         {
446             return ((UIMessage) component).isShowSummary();
447         }
448 
449         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(component, 
450                 org.apache.myfaces.shared.renderkit.JSFAttr.SHOW_SUMMARY_ATTR, false);
451         
452     }
453 
454     protected boolean isShowDetail(UIComponent component)
455     {
456         if (component instanceof UIMessage)
457         {
458             return ((UIMessage) component).isShowDetail();
459         }
460 
461         return RendererUtils.getBooleanAttribute(component, 
462                 org.apache.myfaces.shared.renderkit.JSFAttr.SHOW_DETAIL_ATTR, false);
463         
464     }
465     
466     protected boolean isRedisplay(UIComponent component)
467     {
468         if (component instanceof UIMessage)
469         {
470             return ((UIMessage) component).isRedisplay();
471         }
472 
473         return org.apache.myfaces.shared.renderkit.RendererUtils.getBooleanAttribute(component, 
474                 org.apache.myfaces.shared.renderkit.JSFAttr.REDISPLAY_ATTR, true);
475         
476     }
477 
478 }