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