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.commons.lang3.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 String 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 StringBuilder 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 StringBuilder();
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             maxArgLength,
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 StringBuilder();
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         StringBuilder temp = new StringBuilder();
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         StringBuilder temp = new StringBuilder();
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         StringBuilder temp = new StringBuilder();
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         StringBuilder temp = new StringBuilder();
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         StringBuilder temp = new StringBuilder();
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         StringBuilder temp = new StringBuilder();
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         StringBuilder temp = new StringBuilder();
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         StringBuilder temp = new StringBuilder();
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      * @return the result
625      */
626     protected String toString(String string)
627     {
628         StringBuilder temp = new StringBuilder();
629 
630         if( string == null )
631         {
632             return NULL_STRING;
633         }
634         else
635         {
636             temp.append(LENGTH_STRING);
637             temp.append(string.length());
638             temp.append(',');
639             temp.append(VALUE_STRING);
640             temp.append(string);
641         }
642 
643         return temp.toString();
644     }
645 
646     /**
647      * Create a string representation of a char[].
648      *
649      * @param array the array to print
650      * @return the result
651      */
652     protected String toString(byte[] array)
653     {
654         StringBuilder temp = new StringBuilder();
655 
656         if( array == null )
657         {
658             temp.append(NULL_STRING);
659         }
660         else
661         {
662             temp.append(LENGTH_STRING);
663             temp.append(array.length);
664         }
665 
666         return temp.toString();
667     }
668 
669     /**
670      * Create a string representation of a java.util.Collection.
671      *
672      * @param collection the collection to print
673      * @return the result
674      */
675     protected String toString(Collection<?> collection)
676     {
677         int index = 0;
678         StringBuilder temp = new StringBuilder();
679         ArgumentToStringBuilderImpl toStringBuilder = null;
680 
681         if( collection == null )
682         {
683           return NULL_STRING;
684         }
685         else
686         {
687             temp.append(LENGTH_STRING);
688             temp.append(collection.size());
689             temp.append(',');
690 
691             Iterator<?> iterator = collection.iterator();
692 
693             while (iterator.hasNext())
694             {
695                 temp.append('[');
696                 temp.append(index++);
697                 temp.append(']');
698                 temp.append('=');
699 
700                 toStringBuilder = new ArgumentToStringBuilderImpl(
701                     iterator.next(),
702                     this.getMaxArgLength(),
703                     this.getMode()
704                     );
705 
706                 temp.append(toStringBuilder.toString());
707 
708                 if( index<collection.size()-1)
709                 {
710                     temp.append(',');
711                 }
712 
713                 if( temp.length() > this.getMaxArgLength() )
714                 {
715                     break;
716                 }
717             }
718         }
719 
720         return temp.toString();
721     }
722 
723     /**
724      * Create a string representation of a Dictionary.
725      *
726      * @param dictionary the collection to print
727      * @return the result
728      */
729     protected String toString(Dictionary<?, ?> dictionary)
730     {
731         StringBuilder temp = new StringBuilder();
732 
733         if( dictionary == null )
734         {
735             return NULL_STRING;
736         }
737         else
738         {
739             temp.append(LENGTH_STRING);
740             temp.append(dictionary.size());
741             temp.append(',');
742             temp.append(VALUE_STRING);
743             temp.append(dictionary.toString());
744         }
745 
746         return temp.toString();
747     }
748 
749     /**
750      * Create a String representation for an arbitrary object.
751      *
752      * @param object the object
753      * @return string representation
754      */
755     protected String toString(Object object)
756     {
757         String result = null;
758         String temp = null;
759         String className = null;
760 
761         if( object == null )
762         {
763             result = NULL_STRING;
764         }
765         else
766         {
767             temp = object.toString();
768 
769             className = StringUtils.replace(
770                 object.getClass().getName(),
771                 "java.lang.", ""
772                 );
773 
774             if( temp.startsWith(className) == false )
775             {
776                 int hashCode = object.hashCode();
777                 StringBuilder tempBuffer = new StringBuilder();
778                 tempBuffer.append(className);
779                 tempBuffer.append('@');
780                 tempBuffer.append(hashCode);
781                 tempBuffer.append('[');
782                 tempBuffer.append(temp);
783                 tempBuffer.append(']');
784 
785                 result = tempBuffer.toString();
786             }
787             else
788             {
789                 result = temp;
790             }
791         }
792 
793         return result;
794     }
795 
796     /**
797      * Append the hash code.
798      * @param target the object to print
799      */
800     protected void appendHashCode(Object target)
801     {
802             if ((this.mode & INCLUDE_HASHCODE) == 0)
803             {
804                     return;
805             }
806 
807         if( this.target != null )
808         {
809             this.buffer.append('@');
810             this.buffer.append(Integer.toHexString(target.hashCode()));
811         }
812     }
813 
814     /**
815      * Append the class name.
816      * @param target the object to print
817      */
818     protected void appendClassName(Object target)
819     {
820         boolean skipClassName = true;
821 
822         if ((this.mode & INCLUDE_CLASSNAME) == 0)
823         {
824             return;
825         }
826 
827         if( this.target != null )
828         {
829             String className = target.getClass().getName();
830 
831             if( target instanceof boolean[] )
832             {
833                 this.buffer.append("boolean[]");
834             }
835             else if( target instanceof byte[] )
836             {
837                 this.buffer.append("byte[]");
838             }
839             else if( target instanceof char[] )
840             {
841                 this.buffer.append("char[]");
842             }
843             else if( target instanceof short[] )
844             {
845                 this.buffer.append("short[]");
846             }
847             else if( target instanceof int[] )
848             {
849                 this.buffer.append("int[]");
850             }
851             else if( target instanceof long[] )
852             {
853                 this.buffer.append("[ong[]");
854             }
855             else if( target instanceof float[] )
856             {
857                 this.buffer.append("float[]");
858             }
859             else if( target instanceof double[] )
860             {
861                 this.buffer.append("double[]");
862             }
863             else if( target instanceof Boolean )
864             {
865                 this.buffer.append("Boolean");
866             }
867             else if( target instanceof Character )
868             {
869                 this.buffer.append("Character");
870             }
871             else if( target instanceof Short )
872             {
873                 this.buffer.append("Short");
874             }
875             else if( target instanceof Integer )
876             {
877                 this.buffer.append("Integer");
878             }
879             else if( target instanceof Long )
880             {
881                 this.buffer.append("Long");
882             }
883             else if( target instanceof Float )
884             {
885                 this.buffer.append("Float");
886             }
887             else if( target instanceof Double )
888             {
889                 this.buffer.append("Double");
890             }
891             else if( target instanceof String )
892             {
893                 this.buffer.append("String");
894             }
895             else if( target instanceof Boolean[] )
896             {
897                 this.buffer.append("Boolean[]");
898             }
899             else if( target instanceof Character[] )
900             {
901                 this.buffer.append("Character[]");
902             }
903             else if( target instanceof Short[] )
904             {
905                 this.buffer.append("Short[]");
906             }
907             else if( target instanceof Integer[] )
908             {
909                 this.buffer.append("Integer[]");
910             }
911             else if( target instanceof Long[] )
912             {
913                 this.buffer.append("Long[]");
914             }
915             else if( target instanceof Float[] )
916             {
917                 this.buffer.append("Float[]");
918             }
919             else if( target instanceof Double[] )
920             {
921                 this.buffer.append("Double[]");
922             }
923             else if( target instanceof String[] )
924             {
925                 this.buffer.append("String[]");
926             }
927             else
928             {
929                 skipClassName = false;
930             }
931 
932             if( skipClassName == false )
933             {
934                 className = StringUtils.replace(className, "java.lang.", "");
935 
936                 if( className.endsWith(";") )
937                 {
938                     this.buffer.append(className.substring(0,className.length()-1));
939                 }
940                 else
941                 {
942                     this.buffer.append(className);
943                 }
944             }
945         }
946     }
947 
948     /**
949      * Append the hash code.
950      * @param ch the object to print
951      */
952     protected void appendChar(char ch)
953     {
954         this.buffer.append(ch);
955     }
956 
957     /**
958      * @return Returns the maxLineLength.
959      */
960     protected int getMaxArgLength()
961     {
962         return maxArgLength;
963     }
964 
965     /**
966      * <p>Gets the stack trace from a Throwable as a String.</p>
967      *
968      * @param throwable  the <code>Throwable</code> to be examined
969      * @return the stack trace as generated by the exception's
970      *  <code>printStackTrace(PrintWriter)</code> method
971      */
972     protected String getStackTrace(Throwable throwable)
973     {
974         StringWriter sw = new StringWriter();
975         PrintWriter pw = new PrintWriter( sw, true );
976         throwable.printStackTrace( pw );
977         return sw.getBuffer().toString();
978     }
979 
980     /**
981      * Append a string to the internal buffer
982      * @param source the string to append
983      */
984     protected void append(String source)
985     {
986         String formattedSource = this.format(source);
987         this.buffer.append(formattedSource);
988     }
989 
990     /**
991      * Format the buffer by replacing the whitespaces and cutting
992      * away excessive fluff.
993      *
994      * @param source the source string
995      * @return formatted string
996      */
997     protected String format( String source )
998     {
999         boolean isTruncated = false;
1000 
1001         // test for null or empty string
1002         if ( StringUtils.isEmpty(source) )
1003         	return "";
1004 
1005         // remove the line breaks and tabs for logging output and replace
1006         StringUtils.replace(source,  "\r",  " ");
1007         StringUtils.replace(source,  "\n",  " ");
1008         StringUtils.replace(source,  "\t",  " ");
1009         StringUtils.replace(source,  SEPERATOR,  " ");
1010 
1011         // Build the output
1012         StringBuilder stringBuilder = new StringBuilder(source);
1013 
1014         // trim the string to avoid dumping tons of data
1015         if( stringBuilder.length() > this.getMaxArgLength() )
1016         {
1017             stringBuilder.delete(this.getMaxArgLength()-1, stringBuilder.length());
1018             isTruncated = true;
1019         }
1020         
1021         // show the user that we truncated the ouptut
1022         if( isTruncated )
1023         {
1024             if (source.endsWith("]"))
1025             {
1026                 stringBuilder.append(" ...]");
1027             }
1028             else
1029             {
1030                 stringBuilder.append(" ...");
1031             }
1032         }
1033         return stringBuilder.toString();
1034     }
1035 }