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