KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > infozone > tools > janalyzer > JavaCodeOutput


1 // You can redistribute this software and/or modify it under the terms of
2
// the Infozone Software License version 2 published by the Infozone Group
3
// (http://www.infozone-group.org).
4
//
5
// Copyright (C) @year@ by The Infozone Group. All rights reserved.
6
//
7
// $Id: JavaCodeOutput.java,v 1.1 2002/05/10 08:59:12 per_nyfelt Exp $
8

9 package org.infozone.tools.janalyzer;
10
11 import koala.dynamicjava.tree.*;
12
13 import java.io.File JavaDoc;
14 import java.io.FileReader JavaDoc;
15 import java.io.BufferedReader JavaDoc;
16 import java.io.FileNotFoundException JavaDoc;
17 import java.io.IOException JavaDoc;
18 import java.io.PrintStream JavaDoc;
19 import java.io.FileOutputStream JavaDoc;
20
21 import java.util.Vector JavaDoc;
22 import java.util.Collections JavaDoc;
23
24 import org.apache.regexp.RE;
25 import org.apache.regexp.RESyntaxException;
26
27
28 /**
29  * This class prints the lines of code and the affiliated comments of the output from
30  * the JavaCodeAnalyzer class.
31  * It makes line wrapping with splitting levels, correct indentation and comment creation. .
32  * This all is done after the
33  * <a HREF=http://xml.apache.org/source.html>Apache Source Conventions</a>
34  * from SUN and therefore the ASF..
35  *
36  * <pre>
37  *
38  * TODO:
39  * - trailling comments
40  * - more documentation
41  * - doc comment cration for classes, constructors, fields, methods
42  * BUGS
43  * - comment items in "" are extracted to real comments
44  * </pre>
45  *
46  * @version $Revision: 1.1 $ $Date: 2002/05/10 08:59:12 $
47  * @author <a HREF="http://www.softwarebuero.de">SMB</a>
48  * @see org.infozone.tools.janalyzer.JavaCodeAnalyzer
49  */

50 public final class JavaCodeOutput extends java.lang.Object JavaDoc {
51     
52     //
53
// constants
54
//
55

56     /** The maximum line length JCC 4.1 */
57     private int LINE_LENGTH;
58     /** Constants for line wrapping nice level */
59     private final static int LOW_SPLIT_LEVEL = 10;
60     private final static int MIDDLE_SPLIT_LEVEL = 25;
61     private final static int HIGH_SPLIT_LEVEL = 50;
62     private final static int OBLIGATION_SPLIT_LEVEL = 99;
63     /** One indentation */
64     private final static String JavaDoc ONE_INDENT = " ";
65     /** Indentation for automatically line wrapping */
66     private final static String JavaDoc WRAP_INDENT = " ";
67     /** documentation comment start */
68     // for correct highlighting :-)=)
69
private final static String JavaDoc DOC_COMMENT_START = "/" + "**";
70     /** block comment start */
71     // for correct highlighting :-)=)
72
private final static String JavaDoc BLOCK_COMMENT_START = "/" + "*";
73     /** line comment start */
74     // for correct highlighting :-)=)
75
private final static String JavaDoc LINE_COMMENT_START = "/" + "/";
76     /** block and documentation comment line start */
77     private final static String JavaDoc BLOCK_COMMENT_LINE = "*";
78     /** block and documentation comment end */
79     private final static String JavaDoc BLOCK_COMMENT_END = "*" + "/";
80     /** lines to start a created doc comment */
81     private final static String JavaDoc[] DOC_COMMENT_START_LINES = {DOC_COMMENT_START};
82     /** lines to end a created doc comment */
83     private final static String JavaDoc[] DOC_COMMENT_END_LINES = {BLOCK_COMMENT_END};
84     
85     /**
86      * A split character for priority expression splitting in line wrapping.
87      * All existing split characters must be masked by double split character.
88      * After this character follows the splitting nice level as integer.
89      * - 1 means better no splitting
90      * - 9 or greater means lets split
91      * Example: §1§ or §25§
92      *
93      * @see #println(String aLine)
94      */

95     private final static String JavaDoc SPLIT_CHARACTER = "§";
96     /** Should lineNumbers be printed? */
97     private final static boolean PRINT_LINE_NUMBERS = true;
98     
99     //
100
// data
101
//
102

103     /**
104      * The nice level for splitting on wrapping lines.
105      * @see #SPLIT_CHARACTER
106      * @see #println(String aLine)
107      */

108     private int splitLevel = LOW_SPLIT_LEVEL + 1;
109     /**
110      * @see #println(String aLine)
111      */

112     private boolean wrapIndentAdded = false;
113     /** The complete indentationString. */
114     private String JavaDoc indent = "";
115     
116     /** The start for printing a comment.It should be the end of the previous node. */
117     private int commentStart = 0;
118     /** The endline for printing a comment.It should be the line of the actual node. */
119     private int commentEnd = 0;
120     
121     /** to output the resulting lines */
122     private PrintStream JavaDoc outStream = new PrintStream JavaDoc( System.out );
123     
124     /**
125      * The container for textlines of the original file.
126      */

127     Vector JavaDoc origLines = new Vector JavaDoc();
128     
129     
130     public JavaCodeOutput( File JavaDoc fileIn, String JavaDoc filenameOut, String JavaDoc lineLength ) {
131         try {
132             BufferedReader JavaDoc br = new BufferedReader JavaDoc( new FileReader JavaDoc( fileIn ) );
133             while (br.ready()) {
134                 origLines.add( br.readLine() );
135             }
136             br.close();
137         } catch (FileNotFoundException JavaDoc e) {
138             printEx( "File " + fileIn.getName() + " not found!", e );
139         } catch (IOException JavaDoc e) {
140             printEx( " ", e );
141         }
142         try {
143             if (filenameOut != null) {
144                 File JavaDoc file = new File JavaDoc( filenameOut );
145                 FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc( file );
146                 outStream = new PrintStream JavaDoc( fos );
147             }
148         } catch (FileNotFoundException JavaDoc e) {
149             printEx( "File " + filenameOut + " not found!", e );
150         } catch (IOException JavaDoc e) {
151             printEx( " ", e );
152         }
153         try {
154             if (lineLength != null) {
155                 LINE_LENGTH = Integer.parseInt( lineLength );
156             } else {
157                 LINE_LENGTH = 80;
158             }
159         } catch (NumberFormatException JavaDoc e) {
160             printEx( "Line length " + lineLength + " is not a valid number!", e );
161         }
162     }
163     
164     
165     //
166
// indentation section
167
//
168

169     
170     /**
171      * Increase the indentation String by oneIndent.
172      */

173     public void increaseIndent() {
174         indent += ONE_INDENT;
175     }
176     
177     
178     /**
179      * Decrease the indentation String by the length of the OE_INDENT String.
180      */

181     protected void decreaseIndent() {
182         if (indent.length() > 2) {
183             indent = indent.substring( 0, indent.length() - ONE_INDENT.length() );
184         }
185     }
186     
187     
188     /**
189      * Add to the indentation String the WRAP_INDENT,
190      * because on automatic line wrapping a other indentation string must used.
191      * Only the method println use it.
192      */

193     private void addWrapIndent() {
194         if (!wrapIndentAdded) {
195             wrapIndentAdded = true;
196             indent += WRAP_INDENT;
197         }
198     }
199     
200     
201     /**
202      * Delete the indentation String by the length of the WRAP_INDENT String
203      * if it added before.
204      */

205     private void deleteWrapIndent() {
206         if (wrapIndentAdded) {
207             wrapIndentAdded = false;
208             indent = indent.substring( 0, indent.length() - WRAP_INDENT.length() );
209         }
210     }
211     
212     
213     //
214
// line numbering for debugging only
215
//
216

217     
218     /**
219      * Formatting of the line number on the begin of each outline if it desired.
220      *
221      * The format should be replaced java.text.MessageFormat or someone else.
222      * @return The number of the line formatted of three characters at the moment.
223      */

224     private String JavaDoc getLineNumber() {
225         return "";
226     }
227     
228     
229     //
230
// line wrapping section
231
//
232

233     
234     /**
235      * If the split level String exits in the original source it must be masked
236      */

237     public String JavaDoc mask( String JavaDoc aText ) {
238         try {
239             RE regexp = new RE( SPLIT_CHARACTER );
240             aText = regexp.subst( aText, SPLIT_CHARACTER + SPLIT_CHARACTER );
241         } catch (RESyntaxException e) {
242             printEx( "false regexp in mask", e );
243         }
244         return aText;
245     }
246     
247     
248     /**
249      * Splitting levels were used by the JavaCodeAnalyzer to set marker into the lines of
250      * code, were line wrapping is recommended.
251      * Miscellaneous split level should give a priority were line wrapping is good or bad.
252      * A high level means a good place to wrap the line.
253      *
254      * @return The splitting level with splitting characters.
255      */

256     public String JavaDoc getSplitLevel() {
257         return SPLIT_CHARACTER + splitLevel;
258     }
259     
260     
261     /**
262      * @return The low splitting level with splitting characters.
263      */

264     public String JavaDoc getLowSplitLevel() {
265         return SPLIT_CHARACTER + LOW_SPLIT_LEVEL;
266     }
267     
268     
269     /**
270      * @return The middle splitting level with splitting characters.
271      */

272     public String JavaDoc getMiddleSplitLevel() {
273         return SPLIT_CHARACTER + MIDDLE_SPLIT_LEVEL;
274     }
275     
276     
277     /**
278      * @return The high splitting level with splitting characters.
279      */

280     public String JavaDoc getHighSplitLevel() {
281         return SPLIT_CHARACTER + HIGH_SPLIT_LEVEL;
282     }
283     
284     
285     /**
286      * If it present in a line and the line is longer then LINE_LENGTH
287      * then line must wrapped on this place.
288      * Useful for correct indentation of e.g. ternary expressions.
289      *
290      * @return The obligation splitting level with splitting characters.
291      */

292     public String JavaDoc getObligateSplitLevel() {
293         return SPLIT_CHARACTER + OBLIGATION_SPLIT_LEVEL;
294     }
295     
296     
297     /**
298      * Increase the split level and returns it.
299      */

300     public String JavaDoc getNextSplitLevel() {
301         return SPLIT_CHARACTER + splitLevel++;
302     }
303     
304     
305     public void resetSplitLevel() {
306         splitLevel = LOW_SPLIT_LEVEL + 1;
307     }
308     
309     
310     //
311
// line wrapping
312
//
313

314     
315     /**
316      * This method print out the line. It wrapping lines and so on.
317      * Code Convention Chapter 4.
318      *
319      * @param aLine
320      */

321     public void println( String JavaDoc aLine ) {
322         String JavaDoc output = cleanOutputLine( aLine );
323         output = getLineNumber() + indent + output;
324         //
325
if (output.length() <= LINE_LENGTH) {
326             // line ok print it out
327
outStream.println( output );
328         } else {
329             // line to long
330
// found split characters in the original line and break it there
331
// printLog("println: Line too long.");
332
// find last presence of HIGH_SPLIT_LEVEL
333
// then split_level greater then LOW_SPLIT_LEVEL
334
// then LOW_SPLIT_LEVEL
335
// obligation split level at first
336
// split on getObligateSplitLevel not on SPLIT_CHARACTER+getObligateSplitLevel!
337
int index = 0;
338             // find first presence
339
if ((index = aLine.indexOf( getObligateSplitLevel() )) != -1 && (index == 0 || index > 0 && !(aLine.charAt(
340                     index - 1 ) == SPLIT_CHARACTER.charAt( 0 )))) {
341                 // aSplitter found
342
println( aLine.substring( 0, index ) );
343                 aLine = aLine.substring( index + getObligateSplitLevel().length() );
344                 printDB( "ObligateSplitLevel found on line in if " + getLineNumber() + " index is " + index
345                         + " aLine is " + aLine );
346                 addWrapIndent();
347                 // find next presences
348
while ((index = aLine.indexOf( getObligateSplitLevel() )) != -1 && (index == 0 || index > 0
349                         && !(aLine.charAt( index - 1 ) == SPLIT_CHARACTER.charAt( 0 )))) {
350                     // aSplitter found
351
println( aLine.substring( 0, index ) );
352                     aLine = aLine.substring( index + getObligateSplitLevel().length() );
353                     printDB( "ObligateSplitLevel found on line in while " + getLineNumber() + " index is " + index
354                             + " aLine is " + aLine );
355                 }
356                 // the last part ever
357
println( aLine );
358                 deleteWrapIndent();
359                 // after this for all parts a expliziet println is invoked therefore return
360
return;
361             }
362             //
363
if ((output = breakThisLine( aLine, getHighSplitLevel() )) != null) {
364                 if ((output = breakThisLine( output, getMiddleSplitLevel() )) != null) {
365                     if ((output = breakThisLine( output, getLowSplitLevel() )) != null) {
366                         outStream.println( getLineNumber() + indent + cleanOutputLine( output ) );
367                         deleteWrapIndent();
368                     }
369                 }
370             }
371         }
372     }
373     
374     
375     private String JavaDoc breakThisLine( String JavaDoc aLine, String JavaDoc aSplitter ) {
376         int index = LINE_LENGTH + 8 * aSplitter.length();
377         String JavaDoc output = null;
378         // string splitter found and no split_character before
379
while ((index = aLine.lastIndexOf( aSplitter,
380                 index )) != -1 && (index == 0 || index > 0 && !(aLine.charAt( index - 1 ) == SPLIT_CHARACTER.charAt(
381                 0 )))) {
382             // aSplitter found
383
output = getLineNumber() + indent + cleanOutputLine( aLine.substring( 0, index ) );
384             if (output.length() <= LINE_LENGTH) {
385                 // string fit's the size
386
outStream.println( output );
387                 // line contains only a splitter at end of line
388
if (index + aSplitter.length() < aLine.length()) {
389                     // print the rest
390
addWrapIndent();
391                     println( aLine.substring( index + aSplitter.length() ).trim() );
392                     deleteWrapIndent();
393                 }
394                 return null;
395             } else {
396                 // line too long
397
// search next Splitter
398
--index;
399             }
400         }
401         // no suitable Splitter found
402
// now test the other
403
printLog( "Line not splitable by Splitter " + aSplitter );
404         //
405
return aLine;
406     }
407     
408     
409     /**
410      * This method removes all splitting chracters and other stuff from
411      * the output line.
412      */

413     private String JavaDoc cleanOutputLine( String JavaDoc aLine ) {
414         if (aLine.indexOf( SPLIT_CHARACTER ) != -1) {
415             try {
416                 // first delete all unmasked combinations
417

418                 RE regexp = new RE( "[^" + SPLIT_CHARACTER + "](" + SPLIT_CHARACTER + "\\d\\d)" );
419                 RE regexptwo;
420                 while (regexp.match( aLine )) {
421                     regexptwo = new RE( regexp.getParen( 1 ) );
422                     aLine = regexptwo.subst( aLine, "" );
423                 }
424                 
425                 // subsstitute at begin of line
426
regexp = new RE( "^(" + SPLIT_CHARACTER + "\\d\\d)" );
427                 aLine = regexp.subst( aLine, "" );
428                 
429                 // substitute masked to original
430
regexp = new RE( SPLIT_CHARACTER + SPLIT_CHARACTER );
431                 aLine = regexp.subst( aLine, SPLIT_CHARACTER );
432             } catch (Exception JavaDoc e) {
433                 e.printStackTrace();
434             }
435         }
436         return aLine;
437     }
438     
439     
440     //
441
// comment section
442
//
443

444     
445     public void setCommentStart( int start ) {
446         commentStart = start;
447     }
448     
449     
450     public void setCommentEnd( int end ) {
451         commentEnd = end;
452     }
453     
454     
455     /**
456      * Invokes the method printOrigComment with the parameters
457      * commentStart, commentEnd.
458      */

459     public void printComment() {
460         printOrigComment( commentStart, commentEnd, 0 );
461     }
462     
463     
464     /**
465      * Insert existing comments between Node.getBeginLine To lastline..
466      * This methods could be used to create empty comments.
467      */

468     public void printImportComment( Node aNode ) {
469         printComment();
470     }
471     
472     
473     public void printPackageComment( Node aNode ) {
474         printComment();
475     }
476     
477     
478     public void printClassComment( Node aNode ) {
479         printOrigComment( commentStart, commentEnd, 2 );
480     }
481     
482     
483     public void printInterfaceComment( Node aNode ) {
484         printOrigComment( commentStart, commentEnd, 2 );
485     }
486     
487     
488     public void printConstructorComment( Node aNode ) {
489         printOrigComment( commentStart, commentEnd, 2 );
490     }
491     
492     
493     public void printMethodComment( MethodDeclaration method ) {
494         printOrigComment( commentStart, commentEnd, 2 );
495     }
496     
497     
498     public void printFieldComment( Node aNode ) {
499         printComment();
500     }
501     
502     
503     public void printVariableComment( Node aNode ) {
504         printComment();
505     }
506     
507     
508     /**
509      * Prints the comment line out.
510      * There are a println for source code and a printComment for comment.
511      */

512     private void printComment( String JavaDoc aCommentLine ) {
513         outStream.println( getLineNumber() + indent + aCommentLine );
514     }
515     
516     
517     //
518
// comment output section
519
//
520

521     
522     /**
523      * Performes a arraycopy of the existing Comments between start and end in vector origLines.
524      * @see #printComment(String[] lines)
525      *
526      */

527     private boolean printOrigComment( int startLine, int endLine, int insertLineCount ) {
528         
529         // trailling comments not handled actually
530
if (startLine >= endLine) {
531             // no comment and no empty line found
532
return false;
533         }
534         Vector JavaDoc lines = new Vector JavaDoc();
535         
536         boolean removeEmptyLines = false;
537         // boolean linesInserted = (insertLineCount == 0);
538

539         for (int i = 1; i < (commentEnd - commentStart); i++) {
540             String JavaDoc line = (String JavaDoc)origLines.elementAt( commentEnd - i - 1 );
541             
542             if (line.trim().length() != 0) {
543                 removeEmptyLines = false;
544                 lines.add( line );
545             } else {
546                 // first empty line before following statement found
547
// insert empty lines
548
if (insertLineCount > 0) {
549                     while (insertLineCount > 0) {
550                         lines.add( "" );
551                         insertLineCount--;
552                     }
553                     removeEmptyLines = true;
554                 }
555                 if (!removeEmptyLines) {
556                     lines.add( "" );
557                 }
558             }
559         }
560         
561         while (insertLineCount > 0) {
562             lines.add( "" );
563             insertLineCount--;
564         }
565         
566         Collections.reverse( lines );
567         
568         String JavaDoc[] strings = new String JavaDoc[lines.size()];
569         try {
570             // copy only relevant lines from the origLines vector
571
System.arraycopy( lines.toArray(), 0, strings, 0, lines.size() );
572         } catch (Exception JavaDoc e) {
573             e.printStackTrace();
574         }
575         return printComment( strings );
576     }
577     
578     
579     /**
580      * Perform a arraycopy of all elements in the Vector to a String[].
581      * @see #printComment(String[] lines)
582      */

583     private boolean printComment( Vector JavaDoc someLines ) {
584         String JavaDoc[] lines = new String JavaDoc[someLines.size()];
585         try {
586             // copy only relevant lines from the origLines vector
587
System.arraycopy( someLines.toArray(), 0, lines, 0, someLines.size() );
588         } catch (Exception JavaDoc e) {
589             e.printStackTrace();
590         }
591         return printComment( lines );
592     }
593     
594     
595     private boolean printComment( String JavaDoc[] lines ) {
596         // actual line in Vector
597
String JavaDoc actLine;
598         // loop in documentation block comment
599
boolean isDocComment = false;
600         // loop in block comment
601
boolean isBlockComment = false;
602         //
603
boolean commentExist = false;
604         
605         // get lines from vector
606
for (int i = 0; i < lines.length; i++) {
607             // single line documentation comment
608
/** ... */
609             actLine = lines[i].trim();
610             if (actLine == null) {
611                 actLine = "";
612             }
613             // //
614
if (actLine.startsWith( LINE_COMMENT_START )) {
615                 // single line comment with // found
616
if (!isBlockComment) {
617                     // is not inside a block comment
618
printComment( actLine );
619                     continue;
620                 }
621             }
622             // /** ... */
623
if ((actLine.startsWith( DOC_COMMENT_START ) || actLine.startsWith( BLOCK_COMMENT_START ))
624                     && actLine.endsWith( BLOCK_COMMENT_END )) {
625                 // single line comment found
626
printComment( actLine );
627                 commentExist = true;
628                 continue;
629             }
630             // ... /* .... */ ....
631
// more detailed handling of this comment
632
if (actLine.indexOf( BLOCK_COMMENT_START ) != -1 && actLine.indexOf( BLOCK_COMMENT_END ) != -1) {
633                 printComment( actLine.substring( actLine.indexOf( BLOCK_COMMENT_START ),
634                         actLine.indexOf( BLOCK_COMMENT_END ) + BLOCK_COMMENT_END.length() ) );
635                 
636                 continue;
637             }
638             
639             // */
640
if (actLine.startsWith( BLOCK_COMMENT_END )) {
641                 // block comment ended with */
642
isDocComment = isBlockComment = false;
643                 printComment( " " + BLOCK_COMMENT_END );
644                 continue;
645             }
646             // block comment ended with ..... */
647
if (actLine.indexOf( BLOCK_COMMENT_END ) != -1) {
648                 isDocComment = isBlockComment = false;
649                 
650                 int index = actLine.indexOf( BLOCK_COMMENT_END );
651                 printComment( printBlockCommentLine( actLine.substring( 0, index ) ) );
652                 // actline contains more than the doc comment start
653
printComment( " " + BLOCK_COMMENT_END );
654                 // }
655
continue;
656             }
657             // block doc comment started /** ... */
658
if (actLine.startsWith( DOC_COMMENT_START )) {
659                 isDocComment = true;
660                 commentExist = true;
661                 
662                 printComment( DOC_COMMENT_START );
663                 // actline contains more than the doc comment start
664
if (actLine.length() > DOC_COMMENT_START.length()) {
665                     printComment( printBlockCommentLine( actLine.substring( DOC_COMMENT_START.length() - 1 ) ) );
666                 }
667                 continue;
668             }
669             if (actLine.startsWith( BLOCK_COMMENT_START )) {
670                 // block doc comment started
671
//System.out.printComment("printComment block doc comment found");
672
isBlockComment = true;
673                 
674                 printComment( BLOCK_COMMENT_START );
675                 // actline contains more than the doc comment start
676
if (actLine.length() > BLOCK_COMMENT_START.length()) {
677                     printComment( printBlockCommentLine( actLine.substring( BLOCK_COMMENT_START.length() - 1 ) ) );
678                 }
679                 continue;
680             }
681             // no start or end string found
682
if (isDocComment) {
683                 // in a blockComment, must start with asterisk
684
printComment( printBlockCommentLine( actLine ) );
685                 continue;
686             }
687             if (isBlockComment) {
688                 // in a blockComment
689
// print as is
690
outStream.println( lines[i] );
691                 continue;
692             }
693             
694             // trailing comment ..... // ......
695
if (actLine.indexOf( LINE_COMMENT_START ) != -1) {
696                 // && !isInQuotes(actLine, LINE_COMMENT_START) ) {
697
if (!isBlockComment) {
698                     int index = actLine.indexOf( LINE_COMMENT_START );
699                     printComment( actLine.substring( index ) );
700                 }
701                 continue;
702             }
703             // empty actline is only a newline
704
if (actLine.length() < 1) {
705                 printComment( "" );
706             }
707         }
708         // is isBlock or DocComment true, block isn't determined
709

710         // no start or end string in the loop found
711
if (isDocComment || isBlockComment) {
712             printComment( " " + BLOCK_COMMENT_END );
713             printLog( "Blockcomment not determinated!" );
714         }
715         return commentExist;
716     }
717     
718     
719     /**
720      * Useful for printComment to encapsulate some functionality.
721      * If the line doesn't start with * it would be precede
722      *
723      * @see #printComment(String).
724      */

725     private String JavaDoc printBlockCommentLine( String JavaDoc aLine ) {
726         if (aLine.startsWith( BLOCK_COMMENT_LINE )) {
727             return " " + aLine;
728         } else {
729             return " " + BLOCK_COMMENT_LINE + " " + aLine;
730         }
731     }
732     
733     
734     /**
735      * This method logs warnings on code violations.
736      * @param aLine
737      */

738     private void printLog( String JavaDoc aLine ) {
739     }
740     
741     
742     /**
743      * This method print debug messages.
744      * @param aLine
745      */

746     private void printDB( String JavaDoc aLine ) {
747     }
748     
749     
750     /**
751      * This method print debug messages.
752      * @param aLine
753      */

754     private void printEx( String JavaDoc aLine, Exception JavaDoc e ) {
755         System.err.println( getClass() + ": " + e );
756     }
757 }
758
Popular Tags