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