View Javadoc

1   /*
2    * Copyright 2008 FatWire Corporation. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.fatwire.gst.foundation;
18  
19  import java.io.PrintWriter;
20  import java.io.StringWriter;
21  import java.io.Writer;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.util.Collection;
25  import java.util.Enumeration;
26  import java.util.List;
27  import java.util.Map;
28  
29  import COM.FutureTense.Interfaces.ICS;
30  
31  import com.fatwire.assetapi.common.AssetAccessException;
32  import com.fatwire.assetapi.data.AssetData;
33  import com.fatwire.assetapi.data.AssetId;
34  import com.fatwire.assetapi.data.AttributeData;
35  import com.fatwire.assetapi.data.BlobObject;
36  import com.fatwire.assetapi.data.BlobObject.BlobAddress;
37  import com.fatwire.assetapi.def.AssetAssociationDef;
38  import com.fatwire.assetapi.def.AttributeDef;
39  import com.fatwire.assetapi.def.AttributeDefProperties;
40  import com.fatwire.assetapi.def.AttributeTypeEnum;
41  import com.fatwire.mda.Dimension;
42  
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  
46  /**
47   * Various helper methods for debugging.
48   * 
49   * @author Dolf Dijkstra
50   * 
51   */
52  public final class DebugHelper {
53  
54      public static final String TIME_LOGGER = DebugHelper.class.getPackage().getName() + ".debug.time";
55      private static final Log LOG = LogFactory.getLog(DebugHelper.class.getPackage().getName() + ".debug");
56      private static final Log LOG_TIME = LogFactory.getLog(TIME_LOGGER);
57  
58      private DebugHelper() {
59      }
60  
61      public static void dumpVars(final ICS ics) {
62          dumpVars(ics, LOG);
63      }
64  
65      @SuppressWarnings("unchecked")
66      public static void dumpVars(final ICS ics, final Log log) {
67          if (log.isDebugEnabled()) {
68              for (final Enumeration<String> e = ics.GetVars(); e.hasMoreElements();) {
69                  final String n = e.nextElement();
70                  log.debug("ICS variable: " + n + "=" + ics.GetVar(n));
71              }
72          }
73      }
74  
75      @SuppressWarnings("unchecked")
76      public static void dumpVars(final ICS ics, final PrintWriter pw) {
77  
78          for (final Enumeration<String> e = ics.GetVars(); e.hasMoreElements();) {
79              final String n = e.nextElement();
80              pw.println("ICS variable: " + n + "=" + ics.GetVar(n));
81          }
82  
83      }
84  
85      @SuppressWarnings("unchecked")
86      public static void dumpSSVars(final ICS ics, final PrintWriter pw) {
87  
88          for (final Enumeration<String> e = ics.GetSSVars(); e.hasMoreElements();) {
89              final String n = e.nextElement();
90              pw.println("session variable: " + n + "=" + ics.GetSSVar(n));
91          }
92  
93      }
94  
95      /**
96       * Retrieves the root exception of a <code>Throwable</code>.
97       * 
98       * 
99       * @param e the exception with nested exceptions (causes)
100      * @return the root cause
101      */
102     public static Throwable findRootCause(final Throwable e) {
103         Throwable p = e;
104         while (p.getCause() != null) {
105             p = p.getCause();
106             // alternative would be to set the root on e => e.initCause(p);
107         }
108 
109         return p;
110 
111     }
112 
113     /**
114      * 
115      * Converts an elapsed time in micro seconds to a human readable string with
116      * seconds and milliseconds precision on larger elapsed times.
117      * 
118      * @param elapsed the elapsed time in micro seconds (us)
119      * @return A human readable string for the elapsed micro seconds
120      */
121     public static String microToHuman(final long elapsed) {
122         String human = "(" + elapsed + "us) ";
123         if (elapsed > 1000000) {
124             final long e = elapsed / 1000;
125             human += Long.toString(e / 1000) + "." + Long.toString(e % 1000) + "s";
126         } else if (elapsed > 1000) {
127             human += Long.toString(elapsed / 1000) + "." + Long.toString(elapsed % 1000) + "ms";
128         } else {
129             human += Long.toString(elapsed) + "us";
130         }
131         return human;
132 
133     }
134 
135     /**
136      * 
137      * Converts an elapsed time in nano seconds to a human readable string with
138      * microseconds, seconds and milliseconds precision on larger elapsed times.
139      * Precision is dropped to microseconds precision.
140      * 
141      * @param elapsed the elapsed time in nano seconds (us)
142      * @return A human readable string for the elapsed micro seconds
143      */
144     public static String milliToHuman(final long elapsed) {
145         String human = "(" + elapsed + "ms) ";
146         if (elapsed > 1000 * 60L) {
147             // final long e = elapsed / 60000;
148             final long mins = elapsed / 60000L;
149             final long secs = (elapsed - mins * 60000) / 1000L;
150             human += Long.toString(mins) + "m " + Long.toString(secs) + "s";
151         } else if (elapsed > 1000L) {
152             human += Long.toString(elapsed / 1000) + "." + Long.toString(elapsed % 1000) + "ms";
153         } else {
154             human += Long.toString(elapsed) + "ms";
155         }
156         return human;
157 
158     }
159 
160     /**
161      * 
162      * Converts an elapsed time in milli seconds to a human readable string with
163      * minutes and seconds precision on larger elapsed times.
164      * 
165      * @param elapsed the elapsed time in nano seconds (us)
166      * @return A human readable string for the elapsed micro seconds
167      */
168     public static String nanoToHuman(final long elapsed) {
169         return microToHuman(elapsed / 1000L);
170 
171     }
172 
173     /**
174      * Print the elapsed time between the <tt>start</tt> and <tt>end</tt> to the
175      * provided logger in a human readable form.
176      * 
177      * @param log The logger where the message will be printed to.
178      * @param msg The message as an indicator of the operation that was
179      *            monitored.
180      * @param start time in nanoseconds {@link System#nanoTime()}
181      * @param end time in nanoseconds {@link System#nanoTime()}
182      * @see DebugHelper#microToHuman(long)
183      */
184 
185     public static void printTime(final Log log, final String msg, final long start, final long end) {
186         if (start > 0) {
187             final long elapsed = (end - start) / 1000;
188             log.debug(msg + " took " + microToHuman(elapsed));
189         }
190 
191     }
192 
193     /**
194      * 
195      * Print the elapsed time since the <tt>start</tt> to the provided Log.
196      * 
197      * @param log The logger where the message will be printed to.
198      * @param msg The message as an indicator of the operation that was
199      *            monitored.
200      * @param start time in nanoseconds {@link System#nanoTime()}
201      * @see DebugHelper#microToHuman(long)
202      */
203 
204     public static void printTime(final Log log, final String msg, final long start) {
205         if (start > 0) {
206             printTime(log, msg, start, System.nanoTime());
207         }
208     }
209 
210     /**
211      * Print the elapsed time since the <tt>start</tt> to the default time
212      * logger {@link DebugHelper#TIME_LOGGER}.
213      * 
214      * 
215      * @param msg The message as an indicator of the operation that was
216      *            monitored.
217      * @param start time in nanoseconds {@link System#nanoTime()}
218      * @see DebugHelper#microToHuman(long)
219      * 
220      */
221     public static void printTime(final String msg, final long start) {
222         if (start > 0) {
223             printTime(LOG_TIME, msg, start);
224         }
225     }
226 
227     /**
228      * Print the AssetData to a string for debugging purposes.
229      * 
230      * @param ad the asset date
231      * @return String with asset attributes etc
232      * @throws AssetAccessException
233      */
234     @SuppressWarnings("unchecked")
235     public static String printAsset(final AssetData ad) throws AssetAccessException {
236         if (ad == null) {
237             return null;
238         }
239         final StringWriter sw = new StringWriter();
240         final PrintWriter out = new PrintWriter(sw);
241         out.println(ad.getAssetId() + " '" + ad.getAssetTypeDef().getName() + "' '" + ad.getAssetTypeDef().getSubtype()
242                 + "'");
243 
244         out.println("defs --- name (type [meta/valuecount/inherited/derived])");
245         for (final AttributeDef def : ad.getAssetTypeDef().getAttributeDefs()) {
246             final AttributeDefProperties props = def.getProperties();
247 
248             out.println("\t" + def.getName() + " (" + def.getType() + " [" + def.isMetaDataAttribute() + "/"
249                     + props.getValueCount().name() + "/" + props.isInheritedFlexAttribute() + "/"
250                     + props.isDerivedFlexAttribute() + "])");
251         }
252         final List<AttributeDef> parentDefs = ad.getAssetTypeDef().getParentDefs();
253         if (parentDefs != null) {
254             out.println("parent defs --- name (type [meta/valuecount/inherited/derived])");
255             for (final AttributeDef def : parentDefs) {
256                 final AttributeDefProperties props = def.getProperties();
257 
258                 out.println("\t" + def.getName() + " (" + def.getType() + " [" + def.isMetaDataAttribute() + "/"
259                         + props.getValueCount().name() + "/" + props.isInheritedFlexAttribute() + "/"
260                         + props.isDerivedFlexAttribute() + "])");
261             }
262         }
263 
264         out.println("attribute names --- ");
265         out.println("\t" + ad.getAttributeNames());
266         out.println("attributes --- name (type [meta/valuecount/inherited/derived])");
267         for (final AttributeData attr : ad.getAttributeData()) {
268             final AttributeDefProperties props = attr.getAttributeDef().getProperties();
269             // props.getDataMap()
270             out.print("\t" + attr.getAttributeName() + " (" + attr.getType() + " ["
271                     + attr.getAttributeDef().isMetaDataAttribute() + "/" + props.getValueCount().name() + "/"
272                     + props.isInheritedFlexAttribute() + "/" + props.isDerivedFlexAttribute() + "]): ");
273             if (attr.getType() == AttributeTypeEnum.URL || attr.getType() == AttributeTypeEnum.BLOB) {
274                 final BlobObject blob = (BlobObject) attr.getData();
275                 if (blob != null) {
276                     final BlobAddress addr = blob.getBlobAddress();
277                     out.print(addr.getIdentifier());
278                     out.print(" " + addr.getIdentifierColumnName());
279                     out.print(" " + addr.getColumnName());
280                     out.println(" " + addr.getTableName());
281                 } else {
282                     out.println("NULL BLOB");
283                 }
284             } else {
285                 final Object data = attr.getData();
286                 if (data != null) {
287                     out.print(" (" + data.getClass().getName() + ") ");
288                     out.println(data);
289                 } else {
290                     out.println("NULL");
291                 }
292             }
293 
294         }
295         out.println("parents --- ");
296         for (final AssetId parent : ad.getParents()) {
297             out.println("\t" + parent);
298         }
299 
300         out.println("associations --- ");
301         for (final AssetAssociationDef adef : ad.getAssetTypeDef().getAssociations()) {
302             for (final AssetId association : ad.getAssociatedAssets(adef.getName())) {
303                 out.println("\t" + adef.getName() + ":" + association);
304             }
305         }
306 
307         out.println("dimension --- group/name/id");
308         try {
309             final AttributeData locale = ad.getAttributeData("Dimension");
310             if (locale != null) {
311                 for (final Object o1 : locale.getDataAsList()) {
312                     if (o1 instanceof Collection) { // o1 is probably a Set
313                         for (final Object o2 : (Collection<?>) o1) {
314                             if (o2 instanceof Dimension) {
315                                 final Dimension dim2 = (Dimension) o2;
316                                 out.print("\t" + dim2.getGroup());
317                                 out.print("/" + dim2.getName());
318                                 out.println("/" + dim2.getId());
319                             } else {
320                                 out.println("\t" + String.valueOf(o2));
321                             }
322                         }
323                     }
324                 }
325             }
326         } catch (final NullPointerException e) {
327             out.println("\tgetting the dimension attribute threw a " + e.getMessage());
328 
329         }
330         final AttributeData mapping = ad.getAttributeData("Mapping");
331 
332         if (mapping != null) {
333             int i = 0;
334             final List<AttributeData> mappingArray = mapping.getDataAsList();
335             for (final AttributeData s : mappingArray) {
336                 @SuppressWarnings("rawtypes")
337                 final List<Map<String, AttributeData>> structList = (List) s.getData();
338                 for (final Map<String, AttributeData> m : structList) {
339                     final String key = (String) m.get("key").getData();
340                     final String type = (String) m.get("type").getData();
341                     final String value = (String) m.get("value").getData();
342                     final String siteid = (String) m.get("siteid").getData();
343 
344                     out.println("Mapping Entry #" + String.valueOf(i + 1));
345                     out.println("Key: " + key);
346                     out.println("Type: " + type);
347                     out.println("Value: " + value);
348                     out.println("Siteid: " + siteid);
349                 }
350                 i++;
351             }
352         }
353 
354         out.flush();
355         return sw.toString();
356     }
357 
358     /**
359      * Returns the assetid in as a human readable string in the format of
360      * type:id.
361      * 
362      * @param assetId the asset id.
363      * @return a String concatenated with type and id.
364      */
365     public static String toString(final AssetId assetId) {
366         return assetId.getType() + ":" + assetId.getId();
367     }
368 
369     /**
370      * Creates a String from the Throwable.
371      * 
372      * @param t the throwable to print.
373      * @return a string with the message and the stacktrace.
374      */
375     public static String toString(final Throwable t) {
376         if (t == null) {
377             return "null";
378         }
379         final StringWriter sw = new StringWriter();
380         final PrintWriter pw = new PrintWriter(sw);
381         t.printStackTrace(pw);
382         pw.close();
383         return sw.toString();
384 
385     }
386 
387     /**
388      * Prints the StackTrace of the Throwable to the Writer.
389      * 
390      * @param writer writer to write to.
391      * @param t the Throwable to print the stacktrace of.
392      */
393     public static void printStackTrace(final Writer writer, final Throwable t) {
394         if (writer instanceof PrintWriter) {
395             t.printStackTrace((PrintWriter) writer);
396         } else if (writer != null) {
397             t.printStackTrace(new PrintWriter(writer));
398         } else {
399             throw new IllegalArgumentException("Writer cannot be null.");
400         }
401     }
402 
403     /**
404      * Dumps to current ICS state (Content Server variables, session
405      * variables,ICS objects,elementname,page url and stacktrace) as a String.
406      * 
407      * @param ics
408      * @return the state of ICS.
409      */
410     public static String printState(final ICS ics) {
411         final StringWriter sw = new StringWriter();
412         final PrintWriter pw = new PrintWriter(sw);
413         pw.println("page url: " + ics.pageURL());
414         pw.println("elementname: " + ics.ResolveVariables("CS.elementname"));
415         pw.println();
416         dumpVars(ics, pw);
417         pw.println();
418         dumpSSVars(ics, pw);
419         pw.println();
420         dumpObjects(ics, pw);
421         pw.println();
422         dumpAttributes(ics, pw);
423         pw.println();
424         dumpHttpHeaders(ics, pw);
425         pw.println();
426         dumpCgiVars(ics, pw);
427 
428         pw.println();
429         for (final StackTraceElement e : Thread.currentThread().getStackTrace()) {
430             pw.println("  at " + e.toString());
431         }
432 
433         return sw.toString();
434 
435     }
436 
437     @SuppressWarnings("unchecked")
438     private static void dumpAttributes(final ICS ics, final PrintWriter pw) {
439         for (final Enumeration<String> e = ics.getAttributeNames(); e.hasMoreElements();) {
440             final String n = e.nextElement();
441             pw.println("request attribute: " + n + "=" + ics.getAttribute(n));
442         }
443 
444     }
445 
446     @SuppressWarnings({ "unchecked", "deprecation" })
447     private static void dumpHttpHeaders(final ICS ics, final PrintWriter pw) {
448 
449         try {
450             for (Enumeration<String> e = ics.getIServlet().getServletRequest().getHeaderNames(); e.hasMoreElements();) {
451                 String n = e.nextElement();
452                 pw.println("http header: " + n + "=" + ics.ResolveVariables("CS.Header." + n));
453             }
454         } catch (Exception e) {
455             LOG.warn(e.getMessage());
456         }
457     }
458 
459     private static void dumpCgiVars(final ICS ics, final PrintWriter pw) {
460         String[] headers = { "CS.Browser", "CS.HTTPS", "CS.PATH_INFO", "CS.QUERY_STRING", "CS.REMOTE_ADDR",
461                 "CS.REMOTE_HOST", "CS.REQUEST_METHOD", "CS.SERVER_NAME", "CS.SERVER_PORT", "CS.SERVER_PROTOCOL" };
462         for (String n : headers) {
463             pw.println("cgi var: " + n + "=" + ics.ResolveVariables(n));
464         }
465     }
466 
467     private String printClassOrder(Class c) {
468         StringBuilder b = new StringBuilder();
469         b.append("class " + c.getName());
470 
471         if (c.isInterface()) {
472             b.append(" is an interface");
473         }
474         Class<?>[] interfaces = c.getInterfaces();
475         if (interfaces.length > 0) {
476             for (Class<?> i : interfaces) {
477                 b.append(" ");
478                 b.append(i.getName());
479                 b.append(",");
480             }
481         }
482         Class<?> s = c.getSuperclass();
483         while (s != null) {
484             b.append(" extends " + s.getName());
485             s = c.getSuperclass();
486         }
487         return b.toString();
488     }
489 
490     @SuppressWarnings("unchecked")
491     private static void dumpObjects(final ICS ics, final PrintWriter pw) {
492         for (final Method m : ics.getClass().getMethods()) {
493             final Class<?> c = m.getReturnType();
494 
495             if (m.getParameterTypes().length == 0 && Collection.class.isAssignableFrom(c)) {
496                 Object o;
497                 try {
498                     o = m.invoke(ics, new Object[0]);
499                     if (o instanceof Collection) {
500                         for (final String x : (Collection<String>) o) {
501                             Object obj = ics.GetObj(x);
502                             pw.println("object name: '" + x + "' is a "
503                                     + (obj == null ? "null" : obj.getClass().getName()));
504                         }
505                     }
506                 } catch (final IllegalArgumentException e1) {
507                     LOG.warn(e1.getMessage());
508                 } catch (final IllegalAccessException e1) {
509                     LOG.warn(e1.getMessage());
510                 } catch (final InvocationTargetException e1) {
511                     LOG.warn(e1.getMessage());
512                 }
513             }
514         }
515 
516     }
517 }