001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020 package org.apache.fulcrum.yaafi.interceptor.util; 021 022 import java.io.PrintWriter; 023 import java.io.StringWriter; 024 import java.util.Collection; 025 import java.util.Dictionary; 026 import java.util.Iterator; 027 028 import org.apache.fulcrum.yaafi.framework.util.StringUtils; 029 030 /** 031 * Creates a string representation of method argument. 032 * 033 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a> 034 */ 035 public class ArgumentToStringBuilderImpl implements InterceptorToStringBuilder 036 { 037 /** include the class name in the result */ 038 public static final int INCLUDE_CLASSNAME = 0x1; 039 040 /** include the hashcode in the result */ 041 public static final int INCLUDE_HASHCODE = 0x02; 042 043 /** the default mode using class names and hashcode */ 044 private static int defaultMode = INCLUDE_CLASSNAME & INCLUDE_HASHCODE; 045 046 /** our current formatting mode */ 047 private int mode; 048 049 /** the maximum length of a dumped argument */ 050 private static final int MAX_LINE_LENGTH = 2000; 051 052 /** seperator for the arguments in the logfile */ 053 private static final char SEPERATOR = ';'; 054 055 /** the output for a NULL value **/ 056 private static final String NULL_STRING = "<null>"; 057 058 /** the output for a length string **/ 059 private static final String LENGTH_STRING = "length="; 060 061 /** the output for a value string **/ 062 private static final String VALUE_STRING = "value="; 063 064 /** maximum line length for dumping arguments */ 065 private int maxArgLength; 066 067 /** the result of the invocation */ 068 private StringBuffer buffer; 069 070 /** the target object */ 071 private Object target; 072 073 /** 074 * Constructor 075 */ 076 public ArgumentToStringBuilderImpl() 077 { 078 this.mode = ArgumentToStringBuilderImpl.defaultMode; 079 this.maxArgLength = MAX_LINE_LENGTH; 080 this.buffer = new StringBuffer(); 081 } 082 083 /** 084 * Constructor 085 * 086 * @param target the object to print 087 */ 088 public ArgumentToStringBuilderImpl(Object target) 089 { 090 this(target,MAX_LINE_LENGTH); 091 } 092 093 /** 094 * Constructor 095 * 096 * @param target the object to print 097 * @param maxArgLength the maximum length 098 */ 099 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 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 }