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  
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         // trim the string to avoid dumping tons of data
1001 
1002         if( stringBuffer.length() > this.getMaxArgLength() )
1003         {
1004             stringBuffer.delete(this.getMaxArgLength()-1, stringBuffer.length());
1005             isTruncated = true;
1006         }
1007 
1008         // remove the line breaks and tabs for logging output and replace
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         // show the user that we truncated the ouptut
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 }