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.util;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  
24  import javax.faces.FacesException;
25  import javax.faces.component.*;
26  import javax.faces.context.FacesContext;
27  import javax.faces.el.MethodBinding;
28  import javax.faces.el.ValueBinding;
29  import javax.faces.event.FacesListener;
30  import javax.faces.validator.Validator;
31  import java.beans.BeanInfo;
32  import java.beans.IntrospectionException;
33  import java.beans.Introspector;
34  import java.beans.PropertyDescriptor;
35  import java.io.ByteArrayOutputStream;
36  import java.io.IOException;
37  import java.io.PrintStream;
38  import java.util.HashSet;
39  import java.util.Iterator;
40  import java.util.Map;
41  
42  
43  /**
44   * Utilities for logging.
45   *
46   * @author Manfred Geiler (latest modification by $Author: skitching $)
47   * @version $Revision: 673803 $ $Date: 2008-07-03 16:07:46 -0500 (Thu, 03 Jul 2008) $
48   */
49  public class DebugUtils
50  {
51      private static final Log log = LogFactory.getLog(DebugUtils.class);
52  
53      //Attributes that should not be printed
54      private static final HashSet IGNORE_ATTRIBUTES;
55      static
56      {
57          IGNORE_ATTRIBUTES = new HashSet();
58          IGNORE_ATTRIBUTES.add("attributes");
59          IGNORE_ATTRIBUTES.add("children");
60          IGNORE_ATTRIBUTES.add("childCount");
61          IGNORE_ATTRIBUTES.add("class");
62          IGNORE_ATTRIBUTES.add("facets");
63          IGNORE_ATTRIBUTES.add("facetsAndChildren");
64          IGNORE_ATTRIBUTES.add("parent");
65          IGNORE_ATTRIBUTES.add("actionListeners");
66          IGNORE_ATTRIBUTES.add("valueChangeListeners");
67          IGNORE_ATTRIBUTES.add("validators");
68          IGNORE_ATTRIBUTES.add("rowData");
69          IGNORE_ATTRIBUTES.add("javax.faces.webapp.COMPONENT_IDS");
70          IGNORE_ATTRIBUTES.add("javax.faces.webapp.FACET_NAMES");
71          IGNORE_ATTRIBUTES.add("javax.faces.webapp.CURRENT_VIEW_ROOT");
72      }
73  
74      private static final String JSF_COMPONENT_PACKAGE = "javax.faces.component.";
75      private static final String MYFACES_COMPONENT_PACKAGE = "org.apache.myfaces.component.";
76  
77  
78      private DebugUtils()
79      {
80          // hide from public access
81      }
82  
83      public static void assertError(boolean condition, Log log_, String msg)
84              throws FacesException
85      {
86          if (!condition)
87          {
88              log_.error(msg);
89              throw new FacesException(msg);
90          }
91      }
92  
93      public static void assertFatal(boolean condition, Log log_, String msg)
94          throws FacesException
95      {
96          if (!condition)
97          {
98              log_.fatal(msg);
99              throw new FacesException(msg);
100         }
101     }
102 
103 
104 
105     public static void traceView(String additionalMsg)
106     {
107         if (log.isTraceEnabled())
108         {
109             FacesContext facesContext = FacesContext.getCurrentInstance();
110             if (facesContext == null)
111             {
112                 log.error("Cannot not print view to console (no FacesContext).");
113                 return;
114             }
115             UIViewRoot viewRoot = facesContext.getViewRoot();
116             if (viewRoot == null)
117             {
118                 log.error("Cannot not print view to console (no ViewRoot in FacesContext).");
119                 return;
120             }
121 
122             traceView(additionalMsg, viewRoot);
123         }
124     }
125 
126     /**
127      * Be careful, when using this version of traceView:
128      * Some component properties (e.g. getRenderer) assume, that there is a
129      * valid viewRoot set in the FacesContext!
130      * @param additionalMsg
131      * @param viewRoot
132      */
133     private static void traceView(String additionalMsg, UIViewRoot viewRoot)
134     {
135         ByteArrayOutputStream baos = new ByteArrayOutputStream();
136         PrintStream ps = new PrintStream(baos);
137         if (additionalMsg != null)
138         {
139             ps.println(additionalMsg);
140         }
141         ps.println("========================================");
142         printView(viewRoot, ps);
143         ps.println("========================================");
144         ps.close();
145         log.trace(baos.toString());
146     }
147 
148     public static void printView(UIViewRoot uiViewRoot, PrintStream stream)
149     {
150         printComponent(uiViewRoot, stream, 0, true, null);
151     }
152 
153     public static void printComponent(UIComponent comp, PrintStream stream)
154     {
155         printComponent(comp, stream, 0, false, null);
156     }
157 
158     private static void printComponent(UIComponent comp,
159                                        PrintStream stream,
160                                        int indent,
161                                        boolean withChildrenAndFacets,
162                                        String facetName)
163     {
164         printIndent(stream, indent);
165         stream.print('<');
166 
167         String compType = comp.getClass().getName();
168         if (compType.startsWith(JSF_COMPONENT_PACKAGE))
169         {
170             compType = compType.substring(JSF_COMPONENT_PACKAGE.length());
171         }
172         else if (compType.startsWith(MYFACES_COMPONENT_PACKAGE))
173         {
174             compType = compType.substring(MYFACES_COMPONENT_PACKAGE.length());
175         }
176         stream.print(compType);
177 
178         printAttribute(stream, "id", comp.getId());
179 
180         if (facetName != null)
181         {
182             printAttribute(stream, "facetName", facetName);
183         }
184 
185         for (Iterator it = comp.getAttributes().entrySet().iterator(); it.hasNext(); )
186         {
187             Map.Entry entry = (Map.Entry)it.next();
188             if (!"id".equals(entry.getKey()))
189             {
190                 printAttribute(stream, (String)entry.getKey(), entry.getValue());
191             }
192         }
193 
194         //HACK: comp.getAttributes() only returns attributes, that are NOT backed
195         //by a corresponding component property. So, we must explicitly get the
196         //available properties by Introspection:
197         BeanInfo beanInfo;
198         try
199         {
200             beanInfo = Introspector.getBeanInfo(comp.getClass());
201         }
202         catch (IntrospectionException e)
203         {
204             throw new RuntimeException(e);
205         }
206 
207         PropertyDescriptor propDescriptors[] = beanInfo.getPropertyDescriptors();
208         for (int i = 0; i < propDescriptors.length; i++)
209         {
210             if (propDescriptors[i].getReadMethod() != null)
211             {
212                 String name = propDescriptors[i].getName();
213                 if (!"id".equals(name))
214                 {
215                     ValueBinding vb = comp.getValueBinding(name);
216                     if (vb != null)
217                     {
218                         printAttribute(stream, name, vb.getExpressionString());
219                     }
220                     else
221                     {
222                         if (name.equals("value") && comp instanceof ValueHolder)
223                         {
224                             //-> localValue
225                         }
226                         else if (!IGNORE_ATTRIBUTES.contains(name))
227                         {
228                             try
229                             {
230                                 Object value = comp.getAttributes().get(name);
231                                 printAttribute(stream, name, value);
232                             }
233                             catch (Exception e)
234                             {
235                                 log.error(e);
236                                 printAttribute(stream, name, null);
237                             }
238                         }
239                     }
240                 }
241             }
242         }
243 
244         boolean mustClose = true;
245         boolean nestedObjects = false;
246 
247         if (comp instanceof UICommand)
248         {
249             FacesListener[] listeners = ((UICommand)comp).getActionListeners();
250             if (listeners != null && listeners.length > 0)
251             {
252                 nestedObjects = true;
253                 stream.println('>'); mustClose = false;
254                 for (int i = 0; i < listeners.length; i++)
255                 {
256                     FacesListener listener = listeners[i];
257                     printIndent(stream, indent + 1);
258                     stream.print('<');
259                     stream.print(listener.getClass().getName());
260                     stream.println("/>");
261                 }
262             }
263         }
264 
265         if (comp instanceof UIInput)
266         {
267             FacesListener[] listeners = ((UIInput)comp).getValueChangeListeners();
268             if (listeners != null && listeners.length > 0)
269             {
270                 nestedObjects = true;
271                 stream.println('>'); mustClose = false;
272                 for (int i = 0; i < listeners.length; i++)
273                 {
274                     FacesListener listener = listeners[i];
275                     printIndent(stream, indent + 1);
276                     stream.print('<');
277                     stream.print(listener.getClass().getName());
278                     stream.println("/>");
279                 }
280             }
281 
282             Validator[] validators = ((UIInput)comp).getValidators();
283             if (validators != null && validators.length > 0)
284             {
285                 nestedObjects = true;
286                 stream.println('>'); mustClose = false;
287                 for (int i = 0; i < validators.length; i++)
288                 {
289                     Validator validator = validators[i];
290                     printIndent(stream, indent + 1);
291                     stream.print('<');
292                     stream.print(validator.getClass().getName());
293                     stream.println("/>");
294                 }
295             }
296         }
297 
298         if (withChildrenAndFacets)
299         {
300             int childCount = comp.getChildCount();
301             Map facetsMap = comp.getFacets();
302             if (childCount > 0 || !facetsMap.isEmpty())
303             {
304                 nestedObjects = true;
305                 if (mustClose)
306                 {
307                     stream.println('>');
308                     mustClose = false;
309                 }
310 
311                 if (childCount > 0)
312                 {
313                     for (Iterator it = comp.getChildren().iterator(); it.hasNext(); )
314                     {
315                         UIComponent child = (UIComponent)it.next();
316                         printComponent(child, stream, indent + 1, true, null);
317                     }
318                 }
319 
320                 for (Iterator it = facetsMap.entrySet().iterator(); it.hasNext(); )
321                 {
322                     Map.Entry entry = (Map.Entry)it.next();
323                     printComponent((UIComponent)entry.getValue(),
324                                    stream, indent + 1, true,
325                                    (String)entry.getKey());
326                 }
327             }
328         }
329 
330         if (nestedObjects)
331         {
332             if (mustClose)
333             {
334                 stream.println("/>");
335             }
336             else
337             {
338                 printIndent(stream, indent);
339                 stream.print("</");
340                 stream.print(compType);
341                 stream.println('>');
342             }
343         }
344         else
345         {
346             stream.println("/>");
347         }
348     }
349 
350     private static void printAttribute(PrintStream stream,
351                                        String name,
352                                        Object value)
353     {
354         if (IGNORE_ATTRIBUTES.contains(name)) return;
355         if (name.startsWith("javax.faces.webapp.UIComponentTag."))
356         {
357             name = name.substring("javax.faces.webapp.UIComponentTag.".length());
358         }
359         stream.print(' ');
360         stream.print(name.toString());
361         stream.print("=\"");
362         if (value != null)
363         {
364             if (value instanceof UIComponent)
365             {
366                 stream.print("[id:");
367                 stream.print(((UIComponent)value).getId());
368                 stream.print(']');
369             }
370             else if (value instanceof MethodBinding)
371             {
372                 stream.print(((MethodBinding)value).getExpressionString());
373             }
374             else
375             {
376                 stream.print(value.toString());
377             }
378         }
379         else
380         {
381             stream.print("NULL");
382         }
383         stream.print('"');
384     }
385 
386 
387     private static void printIndent(PrintStream stream, int depth)
388     {
389         for (int i = 0; i < depth; i++)
390         {
391             stream.print("  ");
392         }
393     }
394 
395     public static String componentAsString(UIComponent comp)
396     {
397         try
398         {
399             ByteArrayOutputStream baos = new ByteArrayOutputStream();
400             printComponent(comp, new PrintStream(baos));
401             baos.close();
402             return baos.toString();
403         }
404         catch (IOException e)
405         {
406             throw new RuntimeException(e);
407         }
408     }
409 }