1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.fulcrum.yaafi.interceptor.util;
21
22 import java.io.PrintWriter;
23 import java.io.StringWriter;
24 import java.util.Collection;
25 import java.util.Dictionary;
26 import java.util.Iterator;
27
28 import org.apache.fulcrum.yaafi.framework.util.StringUtils;
29
30 /**
31 * Creates a string representation of method argument.
32 *
33 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
34 */
35 public class ArgumentToStringBuilderImpl implements InterceptorToStringBuilder
36 {
37 /** include the class name in the result */
38 public static final int INCLUDE_CLASSNAME = 0x1;
39
40 /** include the hashcode in the result */
41 public static final int INCLUDE_HASHCODE = 0x02;
42
43 /** the default mode using class names and hashcode */
44 private static int defaultMode = INCLUDE_CLASSNAME & INCLUDE_HASHCODE;
45
46 /** our current formatting mode */
47 private int mode;
48
49 /** the maximum length of a dumped argument */
50 private static final int MAX_LINE_LENGTH = 2000;
51
52 /** seperator for the arguments in the logfile */
53 private static final char SEPERATOR = ';';
54
55 /** the output for a NULL value **/
56 private static final String NULL_STRING = "<null>";
57
58 /** the output for a length string **/
59 private static final String LENGTH_STRING = "length=";
60
61 /** the output for a value string **/
62 private static final String VALUE_STRING = "value=";
63
64 /** maximum line length for dumping arguments */
65 private int maxArgLength;
66
67 /** the result of the invocation */
68 private StringBuffer buffer;
69
70 /** the target object */
71 private Object target;
72
73 /**
74 * Constructor
75 */
76 public ArgumentToStringBuilderImpl()
77 {
78 this.mode = ArgumentToStringBuilderImpl.defaultMode;
79 this.maxArgLength = MAX_LINE_LENGTH;
80 this.buffer = new StringBuffer();
81 }
82
83 /**
84 * Constructor
85 *
86 * @param target the object to print
87 */
88 public ArgumentToStringBuilderImpl(Object target)
89 {
90 this(target,MAX_LINE_LENGTH);
91 }
92
93 /**
94 * Constructor
95 *
96 * @param target the object to print
97 * @param maxArgLength the maximum length
98 */
99 public ArgumentToStringBuilderImpl(Object target, int maxArgLength)
100 {
101 this(target,
102 MAX_LINE_LENGTH,
103 ArgumentToStringBuilderImpl.defaultMode
104 );
105 }
106
107 /**
108 * Constructor
109 *
110 * @param target the object to print
111 * @param maxArgLength the maximum length
112 * @param mode the formatting mode to use
113 */
114 public ArgumentToStringBuilderImpl(Object target, int maxArgLength, int mode)
115 {
116 this.buffer = new StringBuffer();
117 this.target = target;
118 this.maxArgLength = maxArgLength;
119 this.mode = mode;
120 }
121
122 /**
123 * @see org.apache.fulcrum.yaafi.interceptor.util.InterceptorToStringBuilder#setMaxArgLength(int)
124 */
125 public void setMaxArgLength(int maxArgLength)
126 {
127 this.maxArgLength = maxArgLength;
128 }
129
130 /**
131 * @see org.apache.fulcrum.yaafi.interceptor.util.InterceptorToStringBuilder#setTarget(java.lang.Object)
132 */
133 public void setTarget(Object target)
134 {
135 this.target = target;
136 }
137
138 /**
139 * @see org.apache.fulcrum.yaafi.interceptor.util.InterceptorToStringBuilder#setMode(int)
140 */
141 public void setMode(int mode)
142 {
143 this.mode = mode;
144 }
145
146 /**
147 * @return Returns the mode.
148 */
149 public int getMode()
150 {
151 return this.mode;
152 }
153
154 /**
155 * @see java.lang.Object#toString()
156 */
157 public String toString()
158 {
159 try
160 {
161 if( this.target == null )
162 {
163 this.buffer.append(NULL_STRING);
164 }
165 else if( this.target instanceof Object[] )
166 {
167 this.appendClassName(target);
168 this.appendHashCode(target);
169 this.appendChar('[');
170 this.append( this.toString((Object[]) this.target) );
171 this.appendChar(']');
172 }
173 else if( this.target instanceof boolean[] )
174 {
175 this.appendClassName(target);
176 this.appendHashCode(target);
177 this.appendChar('[');
178 this.append( this.toString((boolean[]) this.target) );
179 this.appendChar(']');
180 }
181 else if( this.target instanceof char[] )
182 {
183 this.appendClassName(target);
184 this.appendHashCode(target);
185 this.appendChar('[');
186 this.append( this.toString((char[]) this.target) );
187 this.appendChar(']');
188 }
189 else if( this.target instanceof byte[] )
190 {
191 this.appendClassName(target);
192 this.appendHashCode(target);
193 this.appendChar('[');
194 this.append( this.toString((byte[]) this.target) );
195 this.appendChar(']');
196 }
197 else if( this.target instanceof short[] )
198 {
199 this.appendClassName(target);
200 this.appendHashCode(target);
201 this.appendChar('[');
202 this.append( this.toString((short[]) this.target) );
203 this.appendChar(']');
204 }
205 else if( this.target instanceof int[] )
206 {
207 this.appendClassName(target);
208 this.appendHashCode(target);
209 this.appendChar('[');
210 this.append( this.toString((int[]) this.target) );
211 this.appendChar(']');
212 }
213 else if( this.target instanceof long[] )
214 {
215 this.appendClassName(target);
216 this.appendHashCode(target);
217 this.appendChar('[');
218 this.append( this.toString((long[]) this.target) );
219 this.appendChar(']');
220 }
221 else if( this.target instanceof float[] )
222 {
223 this.appendClassName(target);
224 this.appendHashCode(target);
225 this.appendChar('[');
226 this.append( this.toString((float[]) this.target) );
227 this.appendChar(']');
228 }
229 else if( this.target instanceof double[] )
230 {
231 this.appendClassName(target);
232 this.appendHashCode(target);
233 this.appendChar('[');
234 this.append( this.toString((double[]) this.target) );
235 this.appendChar(']');
236 }
237 else if( this.target instanceof String )
238 {
239 this.appendClassName(target);
240 this.appendHashCode(target);
241 this.appendChar('[');
242 this.append( this.toString((String) this.target) );
243 this.appendChar(']');
244 }
245 else if( this.target instanceof Collection )
246 {
247 this.appendClassName(target);
248 this.appendHashCode(target);
249 this.appendChar('[');
250 this.append( this.toString((Collection) this.target) );
251 this.appendChar(']');
252 }
253 else if( this.target instanceof Dictionary )
254 {
255 this.appendClassName(target);
256 this.appendHashCode(target);
257 this.appendChar('[');
258 this.append( this.toString((Dictionary) this.target) );
259 this.appendChar(']');
260 }
261 else if( this.target instanceof Throwable )
262 {
263 this.append( this.toString((Throwable) this.target) );
264 }
265 else
266 {
267 this.append( this.toString( (Object) this.target ) );
268 }
269 }
270 catch (Throwable t)
271 {
272 t.printStackTrace();
273 return "<" + t + ">";
274 }
275
276 return this.buffer.toString();
277 }
278
279
280 /**
281 * Create a String representation for a Throwable.
282 *
283 * @param throwable the Throwable
284 * @return the string representation
285 */
286 protected String toString(Throwable throwable)
287 {
288 String result = null;
289
290 if( throwable == null )
291 {
292 result = NULL_STRING;
293 }
294 else
295 {
296 result = this.getStackTrace(throwable);
297 }
298
299 return result;
300 }
301
302 /**
303 * Create a string representation of an object array.
304 *
305 * @param array the array to print
306 * @return the result
307 */
308 protected String toString(Object[] array)
309 {
310 StringBuffer temp = new StringBuffer();
311 ArgumentToStringBuilderImpl toStringBuilder = null;
312
313 if( array == null )
314 {
315 return NULL_STRING;
316 }
317 else
318 {
319 temp.append(LENGTH_STRING);
320 temp.append(array.length);
321 temp.append(',');
322
323 for( int i=0; i<array.length; i++ )
324 {
325 temp.append('[');
326 temp.append(i);
327 temp.append(']');
328 temp.append('=');
329 toStringBuilder = new ArgumentToStringBuilderImpl(array[i],this.getMaxArgLength(),this.getMode());
330 temp.append(toStringBuilder.toString());
331
332 if( i<array.length-1)
333 {
334 temp.append(',');
335 }
336
337 if( temp.length() > this.getMaxArgLength() )
338 {
339 break;
340 }
341 }
342 }
343
344 return temp.toString();
345 }
346
347 /**
348 * Create a string representation of a boolean[].
349 *
350 * @param array the array to print
351 * @return the result
352 */
353 protected String toString(boolean[] array)
354 {
355 StringBuffer temp = new StringBuffer();
356
357 if( array == null )
358 {
359 return NULL_STRING;
360 }
361 else
362 {
363 temp.append(LENGTH_STRING);
364 temp.append(array.length);
365 temp.append(',');
366 temp.append(VALUE_STRING);
367
368 for( int i=0; i<array.length; i++ )
369 {
370 temp.append(array[i]);
371 if( i<array.length-1)
372 {
373 temp.append(',');
374 }
375
376 if( temp.length() > this.getMaxArgLength() )
377 {
378 break;
379 }
380 }
381 }
382
383 return temp.toString();
384 }
385
386 /**
387 * Create a string representation of a char[].
388 *
389 * @param array the array to print
390 * @return the result
391 */
392 protected String toString(char[] array)
393 {
394 StringBuffer temp = new StringBuffer();
395
396 if( array == null )
397 {
398 return NULL_STRING;
399 }
400 else
401 {
402 temp.append(LENGTH_STRING);
403 temp.append(array.length);
404 temp.append(',');
405 temp.append(VALUE_STRING);
406
407 for( int i=0; i<array.length; i++ )
408 {
409 temp.append(array[i]);
410 if( i<array.length-1)
411 {
412 temp.append('.');
413 }
414
415 if( temp.length() > this.getMaxArgLength() )
416 {
417 break;
418 }
419 }
420 }
421
422 return temp.toString();
423 }
424
425 /**
426 * Create a string representation of a short[].
427 *
428 * @param array the array to print
429 * @return the result
430 */
431 protected String toString(short[] array)
432 {
433 StringBuffer temp = new StringBuffer();
434
435 if( array == null )
436 {
437 return NULL_STRING;
438 }
439 else
440 {
441 temp.append(LENGTH_STRING);
442 temp.append(array.length);
443 temp.append(',');
444 temp.append(VALUE_STRING);
445
446 for( int i=0; i<array.length; i++ )
447 {
448 temp.append(array[i]);
449 if( i<array.length-1)
450 {
451 temp.append(',');
452 }
453
454 if( temp.length() > this.getMaxArgLength() )
455 {
456 break;
457 }
458 }
459 }
460
461 return temp.toString();
462 }
463
464 /**
465 * Create a string representation of a int[].
466 *
467 * @param array the array to print
468 * @return the result
469 */
470 protected String toString(int[] array)
471 {
472 StringBuffer temp = new StringBuffer();
473
474 if( array == null )
475 {
476 return NULL_STRING;
477 }
478 else
479 {
480 temp.append(LENGTH_STRING);
481 temp.append(array.length);
482 temp.append(',');
483 temp.append(VALUE_STRING);
484
485 for( int i=0; i<array.length; i++ )
486 {
487 temp.append(array[i]);
488 if( i<array.length-1)
489 {
490 temp.append(',');
491 }
492
493 if( temp.length() > this.getMaxArgLength() )
494 {
495 break;
496 }
497 }
498 }
499
500 return temp.toString();
501 }
502
503 /**
504 * Create a string representation of a char[].
505 *
506 * @param array the array to print
507 * @return the result
508 */
509 protected String toString(long[] array)
510 {
511 StringBuffer temp = new StringBuffer();
512
513 if( array == null )
514 {
515 return NULL_STRING;
516 }
517 else
518 {
519 temp.append(LENGTH_STRING);
520 temp.append(array.length);
521 temp.append(',');
522 temp.append(VALUE_STRING);
523
524 for( int i=0; i<array.length; i++ )
525 {
526 temp.append(array[i]);
527 if( i<array.length-1)
528 {
529 temp.append(',');
530 }
531
532 if( temp.length() > this.getMaxArgLength() )
533 {
534 break;
535 }
536 }
537 }
538
539 return temp.toString();
540 }
541
542 /**
543 * Create a string representation of a float[].
544 *
545 * @param array the array to print
546 * @return the result
547 */
548 protected String toString(float[] array)
549 {
550 StringBuffer temp = new StringBuffer();
551
552 if( array == null )
553 {
554 return NULL_STRING;
555 }
556 else
557 {
558 temp.append(LENGTH_STRING);
559 temp.append(array.length);
560 temp.append(',');
561 temp.append(VALUE_STRING);
562
563 for( int i=0; i<array.length; i++ )
564 {
565 temp.append(array[i]);
566 if( i<array.length-1)
567 {
568 temp.append(',');
569 }
570
571 if( temp.length() > this.getMaxArgLength() )
572 {
573 break;
574 }
575 }
576 }
577
578 return temp.toString();
579 }
580
581 /**
582 * Create a string representation of a double[].
583 *
584 * @param array the array to print
585 * @return the result
586 */
587 protected String toString(double[] array)
588 {
589 StringBuffer temp = new StringBuffer();
590
591 if( array == null )
592 {
593 return NULL_STRING;
594 }
595 else
596 {
597 temp.append(LENGTH_STRING);
598 temp.append(array.length);
599 temp.append(',');
600 temp.append(VALUE_STRING);
601
602 for( int i=0; i<array.length; i++ )
603 {
604 temp.append(array[i]);
605 if( i<array.length-1)
606 {
607 temp.append(',');
608 }
609
610 if( temp.length() > this.getMaxArgLength() )
611 {
612 break;
613 }
614 }
615 }
616
617 return temp.toString();
618 }
619
620 /**
621 * Create a string representation of a String.
622 *
623 * @param string the string to print
624 */
625 protected String toString(String string)
626 {
627 StringBuffer temp = new StringBuffer();
628
629 if( string == null )
630 {
631 return NULL_STRING;
632 }
633 else
634 {
635 temp.append(LENGTH_STRING);
636 temp.append(string.length());
637 temp.append(',');
638 temp.append(VALUE_STRING);
639 temp.append(string);
640 }
641
642 return temp.toString();
643 }
644
645 /**
646 * Create a string representation of a char[].
647 *
648 * @param array the array to print
649 * @return the result
650 */
651 protected String toString(byte[] array)
652 {
653 StringBuffer temp = new StringBuffer();
654
655 if( array == null )
656 {
657 temp.append(NULL_STRING);
658 }
659 else
660 {
661 temp.append(LENGTH_STRING);
662 temp.append(array.length);
663 }
664
665 return temp.toString();
666 }
667
668 /**
669 * Create a string representation of a java.util.Collection.
670 *
671 * @param collection the collection to print
672 * @return the result
673 */
674 protected String toString(Collection collection)
675 {
676 int index = 0;
677 StringBuffer temp = new StringBuffer();
678 ArgumentToStringBuilderImpl toStringBuilder = null;
679
680 if( collection == null )
681 {
682 return NULL_STRING;
683 }
684 else
685 {
686 temp.append(LENGTH_STRING);
687 temp.append(collection.size());
688 temp.append(',');
689
690 Iterator iterator = collection.iterator();
691
692 while (iterator.hasNext())
693 {
694 temp.append('[');
695 temp.append(index++);
696 temp.append(']');
697 temp.append('=');
698
699 toStringBuilder = new ArgumentToStringBuilderImpl(
700 iterator.next(),
701 this.getMaxArgLength(),
702 this.getMode()
703 );
704
705 temp.append(toStringBuilder.toString());
706
707 if( index<collection.size()-1)
708 {
709 temp.append(',');
710 }
711
712 if( temp.length() > this.getMaxArgLength() )
713 {
714 break;
715 }
716 }
717 }
718
719 return temp.toString();
720 }
721
722 /**
723 * Create a string representation of a Dictionary.
724 *
725 * @param dictionary the collection to print
726 * @return the result
727 */
728 protected String toString(Dictionary dictionary)
729 {
730 StringBuffer temp = new StringBuffer();
731
732 if( dictionary == null )
733 {
734 return NULL_STRING;
735 }
736 else
737 {
738 temp.append(LENGTH_STRING);
739 temp.append(dictionary.size());
740 temp.append(',');
741 temp.append(VALUE_STRING);
742 temp.append(dictionary.toString());
743 }
744
745 return temp.toString();
746 }
747
748 /**
749 * Create a String representation for an arbitrary object.
750 *
751 * @param object the object
752 * @return string representation
753 */
754 protected String toString(Object object)
755 {
756 String result = null;
757 String temp = null;
758 String className = null;
759
760 if( object == null )
761 {
762 result = NULL_STRING;
763 }
764 else
765 {
766 temp = object.toString();
767
768 className = StringUtils.replace(
769 object.getClass().getName(),
770 "java.lang.", ""
771 );
772
773 if( temp.startsWith(className) == false )
774 {
775 int hashCode = object.hashCode();
776 StringBuffer tempBuffer = new StringBuffer();
777 tempBuffer.append(className);
778 tempBuffer.append('@');
779 tempBuffer.append(hashCode);
780 tempBuffer.append('[');
781 tempBuffer.append(temp);
782 tempBuffer.append(']');
783
784 result = tempBuffer.toString();
785 }
786 else
787 {
788 result = temp;
789 }
790 }
791
792 return result;
793 }
794
795 /**
796 * Append the hash code.
797 * @param target the object to print
798 */
799 protected void appendHashCode(Object target)
800 {
801 if ((this.mode & INCLUDE_HASHCODE) == 0)
802 {
803 return;
804 }
805
806 if( this.target != null )
807 {
808 this.buffer.append('@');
809 this.buffer.append(Integer.toHexString(target.hashCode()));
810 }
811 }
812
813 /**
814 * Append the class name.
815 * @param target the object to print
816 */
817 protected void appendClassName(Object target)
818 {
819 boolean skipClassName = true;
820
821 if ((this.mode & INCLUDE_CLASSNAME) == 0)
822 {
823 return;
824 }
825
826 if( this.target != null )
827 {
828 String className = target.getClass().getName();
829
830 if( target instanceof boolean[] )
831 {
832 this.buffer.append("boolean[]");
833 }
834 else if( target instanceof byte[] )
835 {
836 this.buffer.append("byte[]");
837 }
838 else if( target instanceof char[] )
839 {
840 this.buffer.append("char[]");
841 }
842 else if( target instanceof short[] )
843 {
844 this.buffer.append("short[]");
845 }
846 else if( target instanceof int[] )
847 {
848 this.buffer.append("int[]");
849 }
850 else if( target instanceof long[] )
851 {
852 this.buffer.append("[ong[]");
853 }
854 else if( target instanceof float[] )
855 {
856 this.buffer.append("float[]");
857 }
858 else if( target instanceof double[] )
859 {
860 this.buffer.append("double[]");
861 }
862 else if( target instanceof Boolean )
863 {
864 this.buffer.append("Boolean");
865 }
866 else if( target instanceof Character )
867 {
868 this.buffer.append("Character");
869 }
870 else if( target instanceof Short )
871 {
872 this.buffer.append("Short");
873 }
874 else if( target instanceof Integer )
875 {
876 this.buffer.append("Integer");
877 }
878 else if( target instanceof Long )
879 {
880 this.buffer.append("Long");
881 }
882 else if( target instanceof Float )
883 {
884 this.buffer.append("Float");
885 }
886 else if( target instanceof Double )
887 {
888 this.buffer.append("Double");
889 }
890 else if( target instanceof String )
891 {
892 this.buffer.append("String");
893 }
894 else if( target instanceof Boolean[] )
895 {
896 this.buffer.append("Boolean[]");
897 }
898 else if( target instanceof Character[] )
899 {
900 this.buffer.append("Character[]");
901 }
902 else if( target instanceof Short[] )
903 {
904 this.buffer.append("Short[]");
905 }
906 else if( target instanceof Integer[] )
907 {
908 this.buffer.append("Integer[]");
909 }
910 else if( target instanceof Long[] )
911 {
912 this.buffer.append("Long[]");
913 }
914 else if( target instanceof Float[] )
915 {
916 this.buffer.append("Float[]");
917 }
918 else if( target instanceof Double[] )
919 {
920 this.buffer.append("Double[]");
921 }
922 else if( target instanceof String[] )
923 {
924 this.buffer.append("String[]");
925 }
926 else
927 {
928 skipClassName = false;
929 }
930
931 if( skipClassName == false )
932 {
933 className = StringUtils.replace(className, "java.lang.", "");
934
935 if( className.endsWith(";") )
936 {
937 this.buffer.append(className.substring(0,className.length()-1));
938 }
939 else
940 {
941 this.buffer.append(className);
942 }
943 }
944 }
945 }
946
947 /**
948 * Append the hash code.
949 * @param ch the object to print
950 */
951 protected void appendChar(char ch)
952 {
953 this.buffer.append(ch);
954 }
955
956 /**
957 * @return Returns the maxLineLength.
958 */
959 protected int getMaxArgLength()
960 {
961 return maxArgLength;
962 }
963
964 /**
965 * <p>Gets the stack trace from a Throwable as a String.</p>
966 *
967 * @param throwable the <code>Throwable</code> to be examined
968 * @return the stack trace as generated by the exception's
969 * <code>printStackTrace(PrintWriter)</code> method
970 */
971 protected String getStackTrace(Throwable throwable)
972 {
973 StringWriter sw = new StringWriter();
974 PrintWriter pw = new PrintWriter( sw, true );
975 throwable.printStackTrace( pw );
976 return sw.getBuffer().toString();
977 }
978
979 /**
980 * Append a string to the internal buffer
981 * @param source the string to append
982 */
983 protected void append(String source)
984 {
985 String formattedSource = this.format(source);
986 this.buffer.append(formattedSource);
987 }
988
989 /**
990 * Format the buffer by replacing the whitespaces and cutting
991 * away excessive fluff.
992 *
993 * @param source the source string
994 */
995 protected String format( String source )
996 {
997 boolean isTruncated = false;
998 StringBuffer stringBuffer = new StringBuffer(source);
999
1000
1001
1002 if( stringBuffer.length() > this.getMaxArgLength() )
1003 {
1004 stringBuffer.delete(this.getMaxArgLength()-1, stringBuffer.length());
1005 isTruncated = true;
1006 }
1007
1008
1009
1010 for( int i=0; i<stringBuffer.length(); i++ )
1011 {
1012 if( ( stringBuffer.charAt(i) == '\r' ) ||
1013 ( stringBuffer.charAt(i) == '\n' ) ||
1014 ( stringBuffer.charAt(i) == '\t' ) )
1015 {
1016 stringBuffer.setCharAt(i,' ');
1017 }
1018
1019 if( ( stringBuffer.charAt(i) == SEPERATOR ) )
1020 {
1021 stringBuffer.setCharAt(i,' ');
1022 }
1023 }
1024
1025
1026
1027 if( isTruncated )
1028 {
1029 if (source.endsWith("]"))
1030 {
1031 stringBuffer.append(" ...]");
1032 }
1033 else
1034 {
1035 stringBuffer.append(" ...");
1036 }
1037 }
1038
1039 return stringBuffer.toString();
1040 }
1041 }