1   package org.apache.maven.jxr;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  import org.apache.commons.lang.StringUtils;
34  import org.apache.maven.jxr.pacman.ClassType;
35  import org.apache.maven.jxr.pacman.FileManager;
36  import org.apache.maven.jxr.pacman.ImportType;
37  import org.apache.maven.jxr.pacman.JavaFile;
38  import org.apache.maven.jxr.pacman.PackageManager;
39  import org.apache.maven.jxr.pacman.PackageType;
40  import org.apache.maven.jxr.util.SimpleWordTokenizer;
41  import org.apache.maven.jxr.util.StringEntry;
42  
43  import java.io.BufferedReader;
44  import java.io.FileInputStream;
45  import java.io.FileOutputStream;
46  import java.io.FileReader;
47  import java.io.FileWriter;
48  import java.io.IOException;
49  import java.io.InputStreamReader;
50  import java.io.ObjectInputStream;
51  import java.io.ObjectOutputStream;
52  import java.io.OutputStreamWriter;
53  import java.io.PrintWriter;
54  import java.io.Reader;
55  import java.io.Serializable;
56  import java.io.Writer;
57  import java.nio.file.Files;
58  import java.nio.file.Path;
59  import java.util.HashSet;
60  import java.util.Hashtable;
61  import java.util.List;
62  import java.util.Locale;
63  import java.util.Set;
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  public class JavaCodeTransform
93      implements Serializable
94  {
95      
96      
97      
98  
99      
100 
101 
102     private static final boolean LINE_NUMBERS = true;
103 
104     
105 
106 
107     private static final String COMMENT_START = "<em class=\"jxr_comment\">";
108 
109     
110 
111 
112     private static final String COMMENT_END = "</em>";
113 
114     
115 
116 
117     private static final String JAVADOC_COMMENT_START = "<em class=\"jxr_javadoccomment\">";
118 
119     
120 
121 
122     private static final String JAVADOC_COMMENT_END = "</em>";
123 
124     
125 
126 
127     private static final String STRING_START = "<span class=\"jxr_string\">";
128 
129     
130 
131 
132     private static final String STRING_END = "</span>";
133 
134     
135 
136 
137     private static final String RESERVED_WORD_START = "<strong class=\"jxr_keyword\">";
138 
139     
140 
141 
142     private static final String RESERVED_WORD_END = "</strong>";
143 
144     
145 
146 
147     private static final String STYLESHEET_FILENAME = "stylesheet.css";
148 
149     
150 
151 
152     private static final String[] VALID_URI_SCHEMES = { "http://", "https://", "mailto:" };
153 
154     
155 
156 
157 
158     private static final char[] VALID_URI_CHARS = { '?', '+', '%', '&', ':', '/', '.', '@', '_', ';', '=', '$', ',',
159         '-', '!', '~', '*', '\'', '(', ')' };
160 
161     
162     
163     
164 
165     
166 
167 
168     private Hashtable<String, String> reservedWords = new Hashtable<>();
169 
170     
171 
172 
173     private boolean inMultiLineComment = false;
174 
175     
176 
177 
178     private boolean inJavadocComment = false;
179 
180     
181 
182 
183     private Path currentFilename = null;
184 
185     
186 
187 
188     private String revision = null;
189 
190     
191 
192 
193     private String inputEncoding = null;
194 
195     
196 
197 
198     private String outputEncoding = null;
199 
200     
201 
202 
203     private Locale locale = null;
204 
205     
206 
207 
208     private Path javadocLinkDir;
209 
210     
211 
212 
213     private PackageManager packageManager;
214 
215     
216 
217 
218     private FileManager fileManager;
219 
220     
221     
222     
223 
224     
225 
226 
227 
228 
229     public JavaCodeTransform( PackageManager packageManager )
230     {
231         this.packageManager = packageManager;
232         loadHash();
233         this.fileManager = packageManager.getFileManager();
234     }
235 
236     
237     
238     
239 
240     
241 
242 
243 
244 
245 
246     private String syntaxHighlight( String line )
247     {
248         return htmlFilter( line );
249     }
250 
251     
252 
253 
254 
255 
256 
257     private void appendHeader( PrintWriter out )
258     {
259         String outputEncoding = this.outputEncoding;
260         if ( outputEncoding == null )
261         {
262             outputEncoding = "ISO-8859-1";
263         }
264 
265         
266         out.println( "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
267             + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" );
268         out.print( "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"" );
269         out.print( locale );
270         out.print( "\" lang=\"" );
271         out.print( locale );
272         out.println( "\">" );
273         out.print( "<head>" );
274         out.print( "<meta http-equiv=\"content-type\" content=\"text/html; charset=" );
275         out.print( outputEncoding );
276         out.println( "\" />" );
277 
278         
279         out.print( "<title>" );
280         try
281         {
282             JavaFile javaFile = fileManager.getFile( this.getCurrentFilename() );
283             
284             if ( javaFile.getClassType() != null && javaFile.getClassType().getFilename() != null )
285             {
286                 out.print( javaFile.getClassType().getFilename() );
287             }
288             else
289             {
290                 out.print( this.getCurrentFilename() );
291             }
292             out.print( ' ' );
293         }
294         catch ( IOException e )
295         {
296             e.printStackTrace();
297         }
298         finally
299         {
300             out.println( "xref</title>" );
301         }
302 
303         
304         out.print( "<link type=\"text/css\" rel=\"stylesheet\" href=\"" );
305         out.print( this.getPackageRoot() );
306         out.print( STYLESHEET_FILENAME );
307         out.println( "\" />" );
308 
309         out.println( "</head>" );
310         out.println( "<body>" );
311         out.print( this.getFileOverview() );
312 
313         
314         out.println( "<pre>" );
315     }
316 
317     
318 
319 
320 
321 
322 
323 
324     private void appendFooter( PrintWriter out, String bottom )
325     {
326         out.println( "</pre>" );
327         out.println( "<hr/>" );
328         out.print( "<div id=\"footer\">" );
329         out.print( bottom );
330         out.println( "</div>" );
331         out.println( "</body>" );
332         out.println( "</html>" );
333     }
334 
335     
336 
337 
338 
339 
340 
341 
342 
343 
344 
345 
346 
347 
348     private void transform( Reader sourceReader, Writer destWriter, Locale locale, String inputEncoding,
349                                  String outputEncoding, Path javadocLinkDir, String revision, String bottom )
350         throws IOException
351     {
352         this.locale = locale;
353         this.inputEncoding = inputEncoding;
354         this.outputEncoding = outputEncoding;
355         this.javadocLinkDir = javadocLinkDir;
356         this.revision = revision;
357 
358         BufferedReader in = new BufferedReader( sourceReader );
359 
360         PrintWriter out = new PrintWriter( destWriter );
361 
362         String line = "";
363 
364         appendHeader( out );
365 
366         int linenumber = 1;
367         while ( ( line = in.readLine() ) != null )
368         {
369             if ( LINE_NUMBERS )
370             {
371                 out.print( "<a class=\"jxr_linenumber\" name=\"L" + linenumber + "\" " + "href=\"#L" + linenumber
372                     + "\">" + linenumber + "</a>" + getLineWidth( linenumber ) );
373             }
374 
375             out.println( this.syntaxHighlight( line ) );
376 
377             ++linenumber;
378         }
379 
380         appendFooter( out, bottom );
381 
382         out.flush();
383     }
384 
385     
386 
387 
388 
389 
390 
391 
392 
393 
394 
395 
396 
397 
398     public final void transform( Path sourcefile, Path destfile, Locale locale, String inputEncoding,
399                                  String outputEncoding, Path javadocLinkDir, String revision, String bottom )
400         throws IOException
401     {
402         this.setCurrentFilename( sourcefile );
403 
404         
405         Files.createDirectories( destfile.getParent() );
406 
407         try ( Reader fr = getReader( sourcefile, inputEncoding ); Writer fw = getWriter( destfile, outputEncoding ) )
408         {
409             transform( fr, fw, locale, inputEncoding, outputEncoding, javadocLinkDir, revision, bottom );
410         }
411         catch ( RuntimeException e )
412         {
413             System.out.println( "Unable to processPath " + sourcefile + " => " + destfile );
414             throw e;
415         }
416     }
417 
418     private Writer getWriter( Path destfile, String outputEncoding )
419         throws IOException
420     {
421         Writer fw;
422         if ( outputEncoding != null )
423         {
424             fw = new OutputStreamWriter( new FileOutputStream( destfile.toFile() ), outputEncoding );
425         }
426         else
427         {
428             fw = new FileWriter( destfile.toFile() );
429         }
430         return fw;
431     }
432 
433     private Reader getReader( Path sourcefile, String inputEncoding )
434         throws IOException
435     {
436         Reader fr;
437         if ( inputEncoding != null )
438         {
439             fr = new InputStreamReader( new FileInputStream( sourcefile.toFile() ), inputEncoding );
440         }
441         else
442         {
443             fr = new FileReader( sourcefile.toFile() );
444         }
445         return fr;
446     }
447 
448     
449 
450 
451 
452 
453     private Path getCurrentFilename()
454     {
455         return this.currentFilename;
456     }
457 
458     
459 
460 
461 
462 
463     private void setCurrentFilename( Path filename )
464     {
465         this.currentFilename = filename;
466     }
467 
468     
469 
470 
471 
472 
473     private String getPackageRoot()
474     {
475         StringBuilder buff = new StringBuilder();
476 
477         JavaFile jf = null;
478 
479         try
480         {
481             jf = fileManager.getFile( this.getCurrentFilename() );
482         }
483         catch ( IOException e )
484         {
485             e.printStackTrace();
486             return null;
487         }
488 
489         String current = jf.getPackageType().getName();
490 
491         int count = this.getPackageCount( current );
492 
493         for ( int i = 0; i < count; ++i )
494         {
495             buff.append( "../" );
496         }
497 
498         return buff.toString();
499     }
500 
501     
502 
503 
504 
505 
506 
507     private final String uriFilter( String line )
508     {
509         for ( int i = 0; i < VALID_URI_SCHEMES.length; ++i )
510         {
511             String scheme = VALID_URI_SCHEMES[i];
512 
513             int index = line.indexOf( scheme );
514 
515             if ( index != -1 )
516             {
517                 int start = index;
518                 int end = -1;
519 
520                 for ( int j = start; j < line.length(); ++j )
521                 {
522                     char current = line.charAt( j );
523 
524                     if ( !Character.isLetterOrDigit( current ) && isInvalidURICharacter( current ) )
525                     {
526                         end = j;
527                         break;
528                     }
529 
530                     end = j;
531                 }
532 
533                 
534                 
535 
536                 if ( end != -1 )
537                 {
538                     String uri = ( end + 1 == line.length() ) ? line.substring( start ) : line.substring( start, end );
539 
540                     line =
541                         StringUtils.replace( line, uri, "<a href=\"" + uri + "\" target=\"alexandria_uri\">" + uri
542                             + "</a>" );
543                 }
544             }
545         }
546 
547         
548         if ( !inMultiLineComment && !inJavadocComment )
549         {
550             return jxrFilter( line );
551         }
552 
553         return line;
554     }
555 
556     
557 
558 
559 
560 
561     public final String getRevision()
562     {
563         return this.revision;
564     }
565 
566     
567 
568 
569 
570 
571 
572 
573 
574     private String xrLine( String line, String packageName, ClassType classType )
575     {
576         StringBuilder buff = new StringBuilder( line );
577 
578         String link = null;
579         String find = null;
580         String href = null;
581 
582         if ( classType != null )
583         {
584             href = this.getHREF( packageName, classType );
585             find = classType.getName();
586 
587             
588             link = "<a name=\"" + find + "\" href=\"" + href + "\">" + find + "</a>";
589         }
590         else
591         {
592             href = this.getHREF( packageName );
593             find = packageName;
594 
595             
596             link = "<a href=\"" + href + "\">" + find + "</a>";
597         }
598 
599         
600         
601 
602         
603 
604         String replace = link;
605         List<StringEntry> tokens = SimpleWordTokenizer.tokenize( buff.toString(), find );
606 
607         for ( StringEntry token : tokens )
608         {
609             int start = token.getIndex();
610             int end = token.getIndex() + find.length();
611 
612             buff.replace( start, end, replace );
613 
614         }
615 
616         return buff.toString();
617     }
618 
619     
620     
621     
622 
623     
624 
625 
626 
627 
628 
629     private String htmlFilter( String line )
630     {
631         if ( line == null || line.equals( "" ) )
632         {
633             return "";
634         }
635         line = line.replace( "&", "&" )
636                     .replace( "<", "<" )
637                     .replace( ">", ">" )
638                     .replace( "\\\\", "\\" )
639                     .replace( "\\\"", "\\"" )
640                     .replace( "'\"'", "'"'" );
641         return ongoingMultiLineCommentFilter( line );
642     }
643 
644     
645 
646 
647 
648 
649 
650 
651     private String ongoingMultiLineCommentFilter( String line )
652     {
653         if ( line == null || line.equals( "" ) )
654         {
655             return "";
656         }
657         final String[] tags =
658             inJavadocComment ? new String[] { JAVADOC_COMMENT_START, JAVADOC_COMMENT_END }
659                             : inMultiLineComment ? new String[] { COMMENT_START, COMMENT_END } : null;
660 
661         if ( tags == null )
662         {
663             
664             return inlineCommentFilter( line );
665         }
666 
667         int index = line.indexOf( "*/" );
668         
669         
670         String comment = uriFilter( index < 0 ? line : line.substring( 0, index ) );
671         if ( index >= 0 )
672         {
673             inJavadocComment = false;
674             inMultiLineComment = false;
675         }
676         StringBuilder buf = new StringBuilder( tags[0] ).append( comment );
677 
678         if ( index >= 0 )
679         {
680             buf.append( "*/" );
681         }
682         buf.append( tags[1] );
683 
684         if ( index >= 0 && line.length() > index + 2 )
685         {
686             buf.append( inlineCommentFilter( line.substring( index + 2 ) ) );
687         }
688         return buf.toString();
689     }
690 
691     
692 
693 
694 
695 
696 
697 
698 
699 
700     private String inlineCommentFilter( String line )
701     {
702         
703         
704 
705         if ( line == null || line.equals( "" ) )
706         {
707             return "";
708         }
709         int index = line.indexOf( "//" );
710         if ( ( index >= 0 ) && !isInsideString( line, index ) )
711         {
712             return new StringBuilder( beginMultiLineCommentFilter( line.substring( 0, index ) ) ).append( COMMENT_START ).append( line.substring( index ) ).append( COMMENT_END ).toString();
713         }
714 
715         return beginMultiLineCommentFilter( line );
716     }
717 
718     
719 
720 
721 
722 
723 
724 
725     private String beginMultiLineCommentFilter( String line )
726     {
727         
728         
729 
730         if ( line == null || line.equals( "" ) )
731         {
732             return "";
733         }
734 
735         int index = line.indexOf( "/*" );
736         
737         if ( ( index > -1 ) && !isInsideString( line, index ) )
738         {
739             String fromIndex = line.substring( index );
740             if ( fromIndex.startsWith( "/**" ) && !( fromIndex.startsWith( "/**/" ) ) )
741             {
742                 inJavadocComment = true;
743             }
744             else
745             {
746                 inMultiLineComment = true;
747             }
748             
749             
750             
751             
752             return new StringBuilder( stringFilter( line.substring( 0, index ) ) ).append( ongoingMultiLineCommentFilter( fromIndex ) ).toString();
753         }
754 
755         
756         
757         else
758         {
759             return stringFilter( line );
760         }
761     }
762 
763     
764 
765 
766 
767 
768 
769     private String stringFilter( String line )
770     {
771         if ( line == null || line.equals( "" ) )
772         {
773             return "";
774         }
775         StringBuilder buf = new StringBuilder();
776         if ( line.indexOf( '"' ) <= -1 )
777         {
778             return keywordFilter( line );
779         }
780         int start = 0;
781         int startStringIndex = -1;
782         int endStringIndex = -1;
783         int tempIndex;
784         
785         while ( ( tempIndex = line.indexOf( '"' ) ) > -1 )
786         {
787             
788             if ( startStringIndex == -1 )
789             {
790                 startStringIndex = 0;
791                 buf.append( stringFilter( line.substring( start, tempIndex ) ) );
792                 buf.append( STRING_START ).append( '"' );
793                 line = line.substring( tempIndex + 1 );
794             }
795             
796             else
797             {
798                 startStringIndex = -1;
799                 endStringIndex = tempIndex;
800                 buf.append( line.substring( 0, endStringIndex + 1 ) );
801                 buf.append( STRING_END );
802                 line = line.substring( endStringIndex + 1 );
803             }
804         }
805 
806         buf.append( keywordFilter( line ) );
807 
808         return buf.toString();
809     }
810 
811     
812 
813 
814 
815 
816 
817     private String keywordFilter( String line )
818     {
819         final String classKeyword = "class";
820 
821         if ( line == null || line.equals( "" ) )
822         {
823             return "";
824         }
825         StringBuilder buf = new StringBuilder();
826         int i = 0;
827         char ch;
828         StringBuilder temp = new StringBuilder();
829         while ( i < line.length() )
830         {
831             temp.setLength( 0 );
832             ch = line.charAt( i );
833             while ( i < line.length() && ( ( ch >= 'a' && ch <= 'z' ) || ( ch >= 'A' && ch <= 'Z' ) ) )
834             {
835                 temp.append( ch );
836                 i++;
837                 if ( i < line.length() )
838                 {
839                     ch = line.charAt( i );
840                 }
841             }
842             String tempString = temp.toString();
843 
844             
845             if ( classKeyword.equals( tempString ) && ch == '=' )
846             {
847                 i++;
848             }
849             else if ( reservedWords.containsKey( tempString ) )
850             {
851                 StringBuilder newLine = new StringBuilder( line.substring( 0, i - tempString.length() ) );
852                 newLine.append( RESERVED_WORD_START );
853                 newLine.append( tempString );
854                 newLine.append( RESERVED_WORD_END );
855                 newLine.append( line.substring( i ) );
856                 line = newLine.toString();
857                 i += ( RESERVED_WORD_START.length() + RESERVED_WORD_END.length() );
858             }
859             else
860             {
861                 i++;
862             }
863         }
864         buf.append( line );
865 
866         return uriFilter( buf.toString() );
867     }
868 
869     
870 
871 
872 
873 
874 
875 
876 
877     private boolean isInsideString( String line, int position )
878     {
879         if ( line.indexOf( '"' ) < 0 )
880         {
881             return false;
882         }
883         int index;
884         String left = line.substring( 0, position );
885         String right = line.substring( position );
886         int leftCount = 0;
887         int rightCount = 0;
888         while ( ( index = left.indexOf( '"' ) ) > -1 )
889         {
890             leftCount++;
891             left = left.substring( index + 1 );
892         }
893         while ( ( index = right.indexOf( '"' ) ) > -1 )
894         {
895             rightCount++;
896             right = right.substring( index + 1 );
897         }
898         return ( rightCount % 2 != 0 && leftCount % 2 != 0 );
899     }
900 
901     
902 
903 
904     private void loadHash()
905     {
906         reservedWords.put( "abstract", "abstract" );
907         reservedWords.put( "do", "do" );
908         reservedWords.put( "inner", "inner" );
909         reservedWords.put( "public", "public" );
910         reservedWords.put( "var", "var" );
911         reservedWords.put( "boolean", "boolean" );
912         reservedWords.put( "continue", "continue" );
913         reservedWords.put( "int", "int" );
914         reservedWords.put( "return", "return" );
915         reservedWords.put( "void", "void" );
916         reservedWords.put( "break", "break" );
917         reservedWords.put( "else", "else" );
918         reservedWords.put( "interface", "interface" );
919         reservedWords.put( "short", "short" );
920         reservedWords.put( "volatile", "volatile" );
921         reservedWords.put( "byvalue", "byvalue" );
922         reservedWords.put( "extends", "extends" );
923         reservedWords.put( "long", "long" );
924         reservedWords.put( "static", "static" );
925         reservedWords.put( "while", "while" );
926         reservedWords.put( "case", "case" );
927         reservedWords.put( "final", "final" );
928         reservedWords.put( "native", "native" );
929         reservedWords.put( "super", "super" );
930         reservedWords.put( "transient", "transient" );
931         reservedWords.put( "cast", "cast" );
932         reservedWords.put( "float", "float" );
933         reservedWords.put( "new", "new" );
934         reservedWords.put( "rest", "rest" );
935         reservedWords.put( "catch", "catch" );
936         reservedWords.put( "for", "for" );
937         reservedWords.put( "null", "null" );
938         reservedWords.put( "synchronized", "synchronized" );
939         reservedWords.put( "char", "char" );
940         reservedWords.put( "finally", "finally" );
941         reservedWords.put( "operator", "operator" );
942         reservedWords.put( "this", "this" );
943         reservedWords.put( "class", "class" );
944         reservedWords.put( "generic", "generic" );
945         reservedWords.put( "outer", "outer" );
946         reservedWords.put( "switch", "switch" );
947         reservedWords.put( "const", "const" );
948         reservedWords.put( "goto", "goto" );
949         reservedWords.put( "package", "package" );
950         reservedWords.put( "throw", "throw" );
951         reservedWords.put( "double", "double" );
952         reservedWords.put( "if", "if" );
953         reservedWords.put( "private", "private" );
954         reservedWords.put( "true", "true" );
955         reservedWords.put( "default", "default" );
956         reservedWords.put( "import", "import" );
957         reservedWords.put( "protected", "protected" );
958         reservedWords.put( "try", "try" );
959         reservedWords.put( "throws", "throws" );
960         reservedWords.put( "implements", "implements" );
961     }
962 
963     
964 
965 
966 
967 
968 
969     final void writeObject( ObjectOutputStream oos )
970         throws IOException
971     {
972         oos.defaultWriteObject();
973     }
974 
975     
976 
977 
978 
979 
980 
981 
982     final void readObject( ObjectInputStream ois )
983         throws ClassNotFoundException, IOException
984     {
985         ois.defaultReadObject();
986     }
987 
988     
989 
990 
991 
992 
993     private String getFileOverview()
994     {
995         StringBuilder overview = new StringBuilder();
996 
997         
998         if ( javadocLinkDir != null )
999         {
1000             overview.append( "<div id=\"overview\">" );
1001             
1002             Path javadocURI = javadocLinkDir;
1003 
1004             try
1005             {
1006                 JavaFile jf = fileManager.getFile( this.getCurrentFilename() );
1007 
1008                 javadocURI = javadocLinkDir.resolve( jf.getPackageType().getName().replace( '.', '/' ) )
1009                                 ;
1010                 
1011                 if ( jf.getClassType() != null && jf.getClassType().getFilename() != null )
1012                 {
1013                     javadocURI = javadocURI.resolve( jf.getClassType().getFilename() + ".html" );
1014                 }
1015 
1016                 String javadocHREF = "<a href=\"" + javadocURI.toString().replace( '\\', '/' ) + "\">View Javadoc</a>";
1017 
1018                 
1019                 overview.append( javadocHREF );
1020             }
1021             catch ( IOException e )
1022             {
1023                 e.printStackTrace();
1024             }
1025 
1026             overview.append( "</div>" );
1027         }
1028 
1029         return overview.toString();
1030     }
1031 
1032     
1033 
1034 
1035 
1036 
1037 
1038     private String getLineWidth( int linenumber )
1039     {
1040         if ( linenumber < 10 )
1041         {
1042             return "   ";
1043         }
1044         else if ( linenumber < 100 )
1045         {
1046             return "  ";
1047         }
1048         else
1049         {
1050             return " ";
1051         }
1052     }
1053 
1054     
1055 
1056 
1057 
1058 
1059 
1060     private String jxrFilter( String line )
1061     {
1062         JavaFile jf = null;
1063 
1064         try
1065         {
1066             
1067             if ( this.getCurrentFilename() == null )
1068             {
1069                 return line;
1070             }
1071 
1072             jf = fileManager.getFile( this.getCurrentFilename() );
1073         }
1074         catch ( IOException e )
1075         {
1076             e.printStackTrace();
1077             return line;
1078         }
1079 
1080         Set<String> packages = new HashSet<String>();
1081 
1082         
1083         for ( ImportType importType : jf.getImportTypes() )
1084         {
1085             packages.add( importType.getPackage() );
1086         }
1087 
1088         
1089         packages.add( jf.getPackageType().getName() );
1090 
1091         List<StringEntry> words = SimpleWordTokenizer.tokenize( line );
1092 
1093         
1094         for ( StringEntry word : words )
1095         {
1096             for ( String pkg : packages )
1097             {
1098                 
1099                 
1100 
1101                 PackageType currentImport = packageManager.getPackageType( pkg );
1102 
1103                 
1104                 
1105                 
1106 
1107                 if ( currentImport == null )
1108                 {
1109                     continue;
1110                 }
1111 
1112                 
1113 
1114                 
1115                 
1116 
1117                 String wordName = word.toString();
1118 
1119                 if ( wordName.indexOf( '.' ) != -1 )
1120                 {
1121                     
1122                     
1123 
1124                     String fqpnPackage = null;
1125                     String fqpnClass = null;
1126 
1127                     fqpnPackage = wordName.substring( 0, wordName.lastIndexOf( '.' ) );
1128                     fqpnClass = wordName.substring( wordName.lastIndexOf( '.' ) + 1, wordName.length() );
1129 
1130                     
1131                     
1132                     
1133 
1134                     PackageType pt = packageManager.getPackageType( fqpnPackage );
1135 
1136                     if ( pt != null )
1137                     {
1138                         ClassType ct = pt.getClassType( fqpnClass );
1139 
1140                         if ( ct != null )
1141                         {
1142                             
1143                             
1144                             
1145 
1146                             line = xrLine( line, pt.getName(), ct );
1147                         }
1148                     }
1149 
1150                     if ( fqpnPackage.equals( currentImport.getName() )
1151                         && currentImport.getClassType( fqpnClass ) != null )
1152                     {
1153                         
1154                         
1155                         line = xrLine( line, pkg, currentImport.getClassType( fqpnClass ) );
1156                     }
1157                 }
1158                 else if ( currentImport.getClassType( wordName ) != null )
1159                 {
1160                     line = xrLine( line, pkg, currentImport.getClassType( wordName ) );
1161                 }
1162             }
1163         }
1164 
1165         return importFilter( line );
1166     }
1167 
1168     
1169 
1170 
1171 
1172 
1173 
1174 
1175     private String getHREF( String dest, ClassType jc )
1176     {
1177         StringBuilder href = new StringBuilder();
1178 
1179         
1180         href.append( this.getPackageRoot() );
1181 
1182         
1183         dest = StringUtils.replace( dest, ".*", "" ).replace( '.', '/' );
1184 
1185         href.append( dest );
1186 
1187         
1188         if ( jc != null )
1189         {
1190             href.append( '/' );
1191             href.append( jc.getFilename() );
1192             href.append( ".html" );
1193             href.append( '#' );
1194             href.append( jc.getName() );
1195         }
1196 
1197         return href.toString();
1198     }
1199 
1200     
1201 
1202 
1203 
1204 
1205 
1206     private String getHREF( String dest )
1207     {
1208         return getHREF( dest, null );
1209     }
1210 
1211     
1212 
1213 
1214 
1215 
1216 
1217 
1218 
1219 
1220 
1221 
1222     private int getPackageCount( String packageName )
1223     {
1224         if ( packageName == null )
1225         {
1226             return 0;
1227         }
1228 
1229         int count = 0;
1230         int index = 0;
1231 
1232         while ( true )
1233         {
1234             index = packageName.indexOf( '.', index );
1235 
1236             if ( index == -1 )
1237             {
1238                 break;
1239             }
1240             ++index;
1241             ++count;
1242         }
1243 
1244         
1245         ++count;
1246 
1247         return count;
1248     }
1249 
1250     
1251 
1252 
1253 
1254 
1255 
1256     private String importFilter( String line )
1257     {
1258         int start = -1;
1259 
1260         
1261 
1262 
1263 
1264 
1265         boolean isPackage = line.trim().startsWith( "package " );
1266         boolean isImport = line.trim().startsWith( "import " );
1267 
1268         if ( isImport || isPackage )
1269         {
1270             start = line.trim().indexOf( ' ' );
1271         }
1272 
1273         if ( start != -1 )
1274         {
1275             
1276             String pkg = line.substring( start, line.length() ).trim();
1277 
1278             
1279             String classname = null;
1280 
1281             if (pkg.contains(".*"))
1282             {
1283                 pkg = StringUtils.replace( pkg, ".*", "" );
1284             }
1285             else if ( !isPackage )
1286             {
1287                 
1288 
1289                 String packageLine = pkg.toString();
1290 
1291                 
1292                 
1293                 
1294                 
1295                 
1296                 
1297                 
1298 
1299                 int a = packageLine.lastIndexOf( '.' ) + 1;
1300                 int b = packageLine.length() - 1;
1301 
1302                 if ( a > b + 1 )
1303                 {
1304                     classname = packageLine.substring( packageLine.lastIndexOf( '.' ) + 1, packageLine.length() - 1 );
1305 
1306                     int end = pkg.lastIndexOf( '.' );
1307                     if ( end == -1 )
1308                     {
1309                         end = pkg.length() - 1;
1310                     }
1311 
1312                     pkg = pkg.substring( 0, end );
1313                 }
1314             }
1315 
1316             pkg = StringUtils.replace( pkg, ";", "" );
1317             String pkgHREF = getHREF( pkg );
1318             
1319 
1320             if ( packageManager.getPackageType( pkg ) != null || isPackage )
1321             {
1322                 
1323                 if ( classname != null )
1324                 {
1325                     line =
1326                         StringUtils.replace( line, classname, "<a href=\"" + pkgHREF + '/' + classname + ".html"
1327                             + "\">" + classname + "</a>" );
1328                 }
1329 
1330                 
1331                 line =
1332                     StringUtils.replace( line, pkg, "<a href=\"" + pkgHREF + '/' + DirectoryIndexer.INDEX + "\">" + pkg
1333                         + "</a>" );
1334             }
1335 
1336         }
1337 
1338         return line;
1339     }
1340 
1341     
1342 
1343 
1344 
1345 
1346 
1347     private boolean isInvalidURICharacter( char c )
1348     {
1349         for ( int i = 0; i < VALID_URI_CHARS.length; ++i )
1350         {
1351             if ( VALID_URI_CHARS[i] == c )
1352             {
1353                 return false;
1354             }
1355         }
1356 
1357         return true;
1358     }
1359 }