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