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