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.renderkit.html.ext;
20  
21  import java.io.IOException;
22  import java.text.MessageFormat;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.faces.application.FacesMessage;
29  import javax.faces.component.NamingContainer;
30  import javax.faces.component.UIColumn;
31  import javax.faces.component.UIComponent;
32  import javax.faces.component.ValueHolder;
33  import javax.faces.component.html.HtmlOutputLabel;
34  import javax.faces.component.html.HtmlOutputText;
35  import javax.faces.context.FacesContext;
36  import javax.faces.context.ResponseWriter;
37  
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  import org.apache.myfaces.component.html.ext.HtmlMessage;
41  import org.apache.myfaces.component.html.ext.HtmlMessages;
42  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
43  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
44  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlMessageRendererBase;
45  
46  /**
47   * @JSFRenderer
48   *   renderKitId = "HTML_BASIC"
49   *   family = "javax.faces.Message"
50   *   type = "org.apache.myfaces.Message"
51   * 
52   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
53   * @version $Revision: 940144 $ $Date: 2010-05-01 20:39:32 -0500 (Sat, 01 May 2010) $
54   */
55  public class HtmlMessageRenderer
56          extends HtmlMessageRendererBase
57  {
58      private static final Log log = LogFactory.getLog(HtmlMessageRenderer.class);
59  
60      private static final String OUTPUT_LABEL_MAP = HtmlMessageRenderer.class.getName() + ".OUTPUT_LABEL_MAP";
61  
62      public void encodeEnd(FacesContext facesContext, UIComponent component)
63              throws IOException
64      {
65          super.encodeEnd(facesContext, component);   //check for NP
66          renderMessage(facesContext, component);
67  
68          if (component instanceof HtmlMessage
69                  && ((HtmlMessage)component).getForceSpan())
70          {
71              String forAttr = getFor(component);
72              HtmlMessage htmlMessage = (HtmlMessage) component;
73  
74              UIComponent forComponent = component.findComponent(forAttr);
75  
76              if (forComponent != null)
77              {
78                  String forCompclientId = forComponent.getClientId(facesContext);
79  
80                  ResponseWriter writer = facesContext.getResponseWriter();
81                  writer.startElement(HTML.SPAN_ELEM, null);
82                  writer.writeAttribute(HTML.ID_ATTR, forCompclientId + "_msgFor", null);
83                  if(htmlMessage.getStyleClass()!=null)
84                  writer.writeAttribute(HTML.CLASS_ATTR,htmlMessage.getStyleClass(),null);
85                  if(htmlMessage.getStyle()!=null)
86                  writer.writeAttribute(HTML.STYLE_ATTR,htmlMessage.getStyle(),null);
87                  writer.endElement(HTML.SPAN_ELEM);
88              }
89          }
90      }
91  
92      protected String getSummary(FacesContext facesContext,
93                                  UIComponent message,
94                                  FacesMessage facesMessage,
95                                  String msgClientId)
96      {
97          String msgSummary = facesMessage.getSummary();
98          if (msgSummary == null) return null;
99  
100         String inputLabel = null;
101         if (msgClientId != null) inputLabel = findInputLabel(facesContext, msgClientId);
102         if (inputLabel == null) inputLabel = "";
103 
104         if(((message instanceof HtmlMessages && ((HtmlMessages) message).isReplaceIdWithLabel()) ||
105                 (message instanceof HtmlMessage && ((HtmlMessage) message).isReplaceIdWithLabel()))&&
106                 inputLabel.length()!=0)
107             msgSummary = msgSummary.replaceAll(findInputId(facesContext, msgClientId),inputLabel);
108 
109 
110         String summaryFormat;
111         if (message instanceof HtmlMessage)
112         {
113             summaryFormat = ((HtmlMessage)message).getSummaryFormat();
114         }
115         else
116         {
117             summaryFormat = (String)message.getAttributes().get("summaryFormat");
118         }
119 
120         if (summaryFormat == null) return msgSummary;
121 
122         MessageFormat format = new MessageFormat(summaryFormat, facesContext.getViewRoot().getLocale());
123 
124         return format.format(new Object[] {msgSummary, inputLabel});
125     }
126 
127     protected String getDetail(FacesContext facesContext,
128                                UIComponent message,
129                                FacesMessage facesMessage,
130                                String msgClientId)
131     {
132         String msgDetail = facesMessage.getDetail();
133         if (msgDetail == null) return null;
134 
135         String inputLabel = null;
136         if (msgClientId != null) inputLabel = findInputLabel(facesContext, msgClientId);
137         if (inputLabel == null) inputLabel = "";
138 
139         if(((message instanceof HtmlMessages && ((HtmlMessages) message).isReplaceIdWithLabel()) ||
140                 (message instanceof HtmlMessage && ((HtmlMessage) message).isReplaceIdWithLabel()))&&
141                 inputLabel.length()!=0)
142             msgDetail = msgDetail.replaceAll(findInputId(facesContext, msgClientId),inputLabel);
143 
144         String detailFormat;
145         if (message instanceof HtmlMessage)
146         {
147             detailFormat = ((HtmlMessage)message).getDetailFormat();
148         }
149         else
150         {
151             detailFormat = (String)message.getAttributes().get("detailFormat");
152         }
153 
154         if (detailFormat == null) return msgDetail;
155 
156         MessageFormat format = new MessageFormat(detailFormat, facesContext.getViewRoot().getLocale());
157         return format.format(new Object[] {msgDetail, inputLabel});
158     }
159 
160 
161     public static String findInputLabel(FacesContext facesContext, String inputClientId)
162     {
163         Map<String, MessageLabelInfo> outputLabelMap = getOutputLabelMap(facesContext);
164         MessageLabelInfo info = ((MessageLabelInfo)outputLabelMap.get(inputClientId));
165 
166         if(info == null)
167         {
168             UIComponent comp = facesContext.getViewRoot().findComponent(inputClientId);
169 
170             UIComponent parent=comp;
171 
172             while(parent != null && !((parent=parent.getParent())instanceof UIColumn));
173 
174             if(parent != null)
175             {
176                 UIColumn column = (UIColumn) parent;
177 
178                 if(column.getHeader()!=null)
179                 {
180                     UIComponent header = column.getHeader();
181 
182                     return getComponentText(facesContext, header);
183                 }
184             }
185         }
186 
187         return info==null?null:info.getText(facesContext);
188     }
189 
190     public static String findInputId(FacesContext facesContext, String inputClientId)
191     {
192         Map<String, MessageLabelInfo> outputLabelMap = getOutputLabelMap(facesContext);
193         MessageLabelInfo info = ((MessageLabelInfo)outputLabelMap.get(inputClientId));
194 
195         UIComponent comp = null;
196         
197         if(info == null)
198         {
199             comp = facesContext.getViewRoot().findComponent(inputClientId);
200         }
201         else
202         {
203             comp = info.getForComponent();
204         }
205         
206         if ( comp == null ) return null;
207 
208         if ( inputClientId.contains(NamingContainer.SEPARATOR_CHAR + "") ) {
209             // Full client id is being used
210             //
211             return comp.getClientId(facesContext);
212         }
213         else {
214             // Id is being used (or client id is one level deep, which means it doesn't matter)
215             //
216             return comp.getId();
217         }
218     }
219 
220     /**
221      * @param facesContext
222      * @return a Map that reversely maps clientIds of components to their
223      *         corresponding OutputLabel component
224      */
225     @SuppressWarnings("unchecked")
226     private static Map<String, MessageLabelInfo> getOutputLabelMap(FacesContext facesContext)
227     {
228         Map<String, MessageLabelInfo> map = (Map<String, MessageLabelInfo>) facesContext.getExternalContext().getRequestMap().get(OUTPUT_LABEL_MAP);
229         if (map == null)
230         {
231             map = new HashMap<String, MessageLabelInfo>();
232             createOutputLabelMap(facesContext, facesContext.getViewRoot(), map);
233             facesContext.getExternalContext().getRequestMap().put(OUTPUT_LABEL_MAP, map);
234         }
235         return map;
236     }
237 
238     private static void createOutputLabelMap(FacesContext facesContext,
239                                              UIComponent root,
240                                              Map<String, MessageLabelInfo> map)
241     {
242         for (Iterator<UIComponent> it = root.getFacetsAndChildren(); it.hasNext(); )
243         {
244             UIComponent child = (UIComponent)it.next();
245             if (child instanceof HtmlOutputLabel)
246             {
247                 String forAttr = ((HtmlOutputLabel)child).getFor();
248                 if (forAttr != null)
249                 {
250                     UIComponent input = child.findComponent(forAttr);
251                     if (input == null)
252                     {
253                         log.warn("Unable to find component '" + forAttr + "' (calling findComponent on component '" + child.getClientId(facesContext) + "')");
254                     }
255                     else
256                     {
257                         if (child.getValueExpression("value") == null)
258                         {
259                             // If the child uses a ValueExpression, do not evaluate the text
260                             // right now. When getText(FacesContext) is called, do it there.
261                             map.put(input.getClientId(facesContext),
262                                     new MessageDefferedLabelInfo(
263                                             input, child));                            
264                         }
265                         else
266                         {
267                             map.put(input.getClientId(facesContext),
268                                     new MessageTextLabelInfo(
269                                             input,getComponentText(facesContext, (HtmlOutputLabel)child)));
270                         }
271                     }
272                 }
273             }
274             else
275             {
276                 createOutputLabelMap(facesContext, child, map);
277             }
278         }
279     }
280 
281     private static String getComponentText(FacesContext facesContext, UIComponent component)
282     {
283         String text = null;
284 
285         if(component instanceof ValueHolder)
286         {
287             text= RendererUtils.getStringValue(facesContext, component);
288         }
289 
290         if (text == null || text.length() < 1)
291         {
292             StringBuffer buf = new StringBuffer();
293             List<UIComponent> li = component.getChildren();
294 
295             for (int i = 0; i < li.size(); i++)
296             {
297                 UIComponent child = (UIComponent) li.get(i);
298 
299                 if(child instanceof HtmlOutputText)
300                 {
301                     String str = RendererUtils.getStringValue(facesContext, child);
302 
303                     if(str!=null)
304                         buf.append(str);
305                 }
306             }
307 
308             text = buf.toString();
309         }
310         return text;
311     }
312 
313     public static interface MessageLabelInfo
314     {
315         public UIComponent getForComponent();
316         public String getText(FacesContext context);
317     }
318     
319     public final static class MessageTextLabelInfo implements MessageLabelInfo
320     {
321         private final UIComponent _forComponent;
322         private final String _text;
323 
324         public MessageTextLabelInfo(final UIComponent forComponent, final String text)
325         {
326             _forComponent = forComponent;
327             _text = text;
328         }
329 
330         public UIComponent getForComponent()
331         {
332             return _forComponent;
333         }
334 
335         public String getText(FacesContext context)
336         {
337             return _text;
338         }
339     }
340     
341     public final static class MessageDefferedLabelInfo implements MessageLabelInfo
342     {
343         private final UIComponent _forComponent;
344         private final UIComponent _labelComponent;
345         private String _text;
346         
347         public MessageDefferedLabelInfo(final UIComponent forComponent, final UIComponent labelComponent)
348         {
349             _forComponent = forComponent;
350             _labelComponent = labelComponent;
351         }
352 
353         
354         public UIComponent getForComponent()
355         {
356             return _forComponent;
357         }
358 
359         public String getText(FacesContext context)
360         {
361             if (_text == null)
362             {
363                 _text = getComponentText(context, (HtmlOutputLabel)_labelComponent); 
364             }
365             return _text; 
366         }
367     }
368 }