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