Coverage Report - org.apache.maven.jxr.JavaCodeTransform
 
Classes in this File Line Coverage Branch Coverage Complexity
JavaCodeTransform
100%
376/376
N/A
4,029
 
 1  
 package org.apache.maven.jxr;
 2  
 
 3  
 /*
 4  
  * CodeViewer.java
 5  
  * CoolServlets.com
 6  
  * March 2000
 7  
  *
 8  
  * Copyright (C) 2000 CoolServlets.com
 9  
  *
 10  
  * Redistribution and use in source and binary forms, with or without
 11  
  * modification, are permitted provided that the following conditions are met:
 12  
  * 1) Redistributions of source code must retain the above copyright notice,
 13  
  *   this list of conditions and the following disclaimer.
 14  
  * 2) Redistributions in binary form must reproduce the above copyright notice,
 15  
  *   this list of conditions and the following disclaimer in the documentation
 16  
  *   and/or other materials provided with the distribution.
 17  
  * 3) Neither the name CoolServlets.com nor the names of its contributors may be
 18  
  *   used to endorse or promote products derived from this software without
 19  
  *   specific prior written permission.
 20  
  *
 21  
  * THIS SOFTWARE IS PROVIDED BY COOLSERVLETS.COM AND CONTRIBUTORS ``AS IS'' AND
 22  
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 23  
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 24  
  * DISCLAIMED. IN NO EVENT SHALL COOLSERVLETS.COM OR CONTRIBUTORS BE LIABLE FOR
 25  
  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 26  
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 27  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 28  
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 29  
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 30  
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 31  
  */
 32  
 
 33  
 import org.apache.maven.jxr.pacman.ClassType;
 34  
 import org.apache.maven.jxr.pacman.FileManager;
 35  
 import org.apache.maven.jxr.pacman.ImportType;
 36  
 import org.apache.maven.jxr.pacman.JavaFile;
 37  
 import org.apache.maven.jxr.pacman.PackageManager;
 38  
 import org.apache.maven.jxr.pacman.PackageType;
 39  
 import org.apache.maven.jxr.util.SimpleWordTokenizer;
 40  
 import org.apache.maven.jxr.util.StringEntry;
 41  
 import org.codehaus.plexus.util.StringUtils;
 42  
 
 43  
 import java.io.BufferedReader;
 44  
 import java.io.File;
 45  
 import java.io.FileInputStream;
 46  
 import java.io.FileOutputStream;
 47  
 import java.io.FileReader;
 48  
 import java.io.FileWriter;
 49  
 import java.io.IOException;
 50  
 import java.io.InputStreamReader;
 51  
 import java.io.ObjectInputStream;
 52  
 import java.io.ObjectOutputStream;
 53  
 import java.io.OutputStreamWriter;
 54  
 import java.io.PrintWriter;
 55  
 import java.io.Reader;
 56  
 import java.io.Serializable;
 57  
 import java.io.Writer;
 58  
 import java.util.Hashtable;
 59  
 import java.util.Locale;
 60  
 import java.util.Vector;
 61  
 
 62  
 /**
 63  
  * Syntax highlights java by turning it into html. A codeviewer object is
 64  
  * created and then keeps state as lines are passed in. Each line passed in as
 65  
  * java test, is returned as syntax highlighted html text. Users of the class
 66  
  * can set how the java code will be highlighted with setter methods. Only valid
 67  
  * java lines should be passed in since the object maintains state and may not
 68  
  * handle illegal code gracefully. The actual system is implemented as a series
 69  
  * of filters that deal with specific portions of the java code. The filters are
 70  
  * as follows: <pre>
 71  
  *  htmlFilter
 72  
  *     |__
 73  
  *        multiLineCommentFilter -> uriFilter
 74  
  *           |___
 75  
  *              inlineCommentFilter
 76  
  *                 |___
 77  
  *                    stringFilter
 78  
  *                       |___
 79  
  *                          keywordFilter
 80  
  *                             |___
 81  
  *                                uriFilter
 82  
  *                                   |___
 83  
  *                                      jxrFilter
 84  
  *                                         |___
 85  
  *                                            importFilter
 86  
  * </pre>
 87  
  */
 88  
 public class JavaCodeTransform
 89  
     implements Serializable
 90  
 {
 91  
     // ----------------------------------------------------------------------
 92  
     // public fields
 93  
     // ----------------------------------------------------------------------
 94  
 
 95  
     /**
 96  
      * show line numbers
 97  
      */
 98  
     public static final boolean LINE_NUMBERS = true;
 99  
 
 100  
     /**
 101  
      * start comment delimeter
 102  
      */
 103  
     public static final String COMMENT_START = "<em class=\"jxr_comment\">";
 104  
 
 105  
     /**
 106  
      * end comment delimeter
 107  
      */
 108  
     public static final String COMMENT_END = "</em>";
 109  
 
 110  
     /**
 111  
      * start javadoc comment delimeter
 112  
      */
 113  
     public static final String JAVADOC_COMMENT_START = "<em class=\"jxr_javadoccomment\">";
 114  
 
 115  
     /**
 116  
      * end javadoc comment delimeter
 117  
      */
 118  
     public static final String JAVADOC_COMMENT_END = "</em>";
 119  
 
 120  
     /**
 121  
      * start String delimeter
 122  
      */
 123  
     public static final String STRING_START = "<span class=\"jxr_string\">";
 124  
 
 125  
     /**
 126  
      * end String delimeter
 127  
      */
 128  
     public static final String STRING_END = "</span>";
 129  
 
 130  
     /**
 131  
      * start reserved word delimeter
 132  
      */
 133  
     public static final String RESERVED_WORD_START = "<strong class=\"jxr_keyword\">";
 134  
 
 135  
     /**
 136  
      * end reserved word delimeter
 137  
      */
 138  
     public static final String RESERVED_WORD_END = "</strong>";
 139  
 
 140  
     /**
 141  
      * stylesheet file name
 142  
      */
 143  
     public static final String STYLESHEET_FILENAME = "stylesheet.css";
 144  
 
 145  
     /**
 146  
      * Description of the Field
 147  
      */
 148  1
     public static final String[] VALID_URI_SCHEMES = {"http://", "mailto:"};
 149  
 
 150  
     /**
 151  
      * Specify the only characters that are allowed in a URI besides alpha and
 152  
      * numeric characters. Refer RFC2396 - http://www.ietf.org/rfc/rfc2396.txt
 153  
      */
 154  1
     public static final char[] VALID_URI_CHARS = {'?', '+', '%', '&', ':', '/', '.', '@', '_', ';', '=', '$', ',', '-',
 155  
         '!', '~', '*', '\'', '(', ')'};
 156  
 
 157  
     // ----------------------------------------------------------------------
 158  
     // private fields
 159  
     // ----------------------------------------------------------------------
 160  
 
 161  
     /**
 162  
      * HashTable containing java reserved words
 163  
      */
 164  4
     private Hashtable reservedWords = new Hashtable();
 165  
 
 166  
     /**
 167  
      * flag set to true when a multi line comment is started
 168  
      */
 169  4
     private boolean inMultiLineComment = false;
 170  
 
 171  
     /**
 172  
      * flag set to true when a javadoc comment is started
 173  
      */
 174  4
     private boolean inJavadocComment = false;
 175  
 
 176  
     /**
 177  
      * Set the filename that is currently being processed.
 178  
      */
 179  4
     private String currentFilename = null;
 180  
 
 181  
     /**
 182  
      * The current CVS revision of the currently transformed documnt
 183  
      */
 184  4
     private String revision = null;
 185  
 
 186  
     /**
 187  
      * The currently being transformed source file
 188  
      */
 189  4
     private String sourcefile = null;
 190  
 
 191  
     /**
 192  
      * The currently being written destfile
 193  
      */
 194  4
     private String destfile = null;
 195  
 
 196  
     /**
 197  
      * The virtual source directory that is being read from: src/java
 198  
      */
 199  4
     private String sourcedir = null;
 200  
 
 201  
     /**
 202  
      * The input encoding
 203  
      */
 204  4
     private String inputEncoding = null;
 205  
 
 206  
     /**
 207  
      * The output encoding
 208  
      */
 209  4
     private String outputEncoding = null;
 210  
 
 211  
     /**
 212  
      * The wanted locale
 213  
      */
 214  4
     private Locale locale = null;
 215  
 
 216  
     /**
 217  
      * Relative path to javadocs, suitable for hyperlinking
 218  
      */
 219  
     private String javadocLinkDir;
 220  
 
 221  
     /**
 222  
      * Package Manager for this project.
 223  
      */
 224  
     private PackageManager packageManager;
 225  
 
 226  
     /**
 227  
      * current file manager
 228  
      */
 229  
     private FileManager fileManager;
 230  
 
 231  
     // ----------------------------------------------------------------------
 232  
     // constructor
 233  
     // ----------------------------------------------------------------------
 234  
 
 235  
     /**
 236  
      * Constructor for the JavaCodeTransform object
 237  
      *
 238  
      * @param packageManager PackageManager for this project
 239  
      */
 240  
     public JavaCodeTransform( PackageManager packageManager )
 241  4
     {
 242  4
         this.packageManager = packageManager;
 243  4
         loadHash();
 244  4
         this.fileManager = packageManager.getFileManager();
 245  4
     }
 246  
 
 247  
     // ----------------------------------------------------------------------
 248  
     // public methods
 249  
     // ----------------------------------------------------------------------
 250  
 
 251  
     /**
 252  
      * Now different method of seeing if at end of input stream, closes inputs
 253  
      * stream at end.
 254  
      *
 255  
      * @param line String
 256  
      * @return filtered line of code
 257  
      */
 258  
     public final String syntaxHighlight( String line )
 259  
     {
 260  310
         return htmlFilter( line );
 261  
     }
 262  
 
 263  
     /**
 264  
      * Gets the header attribute of the JavaCodeTransform object
 265  
      *
 266  
      * @return String
 267  
      */
 268  
     public String getHeader()
 269  
     {
 270  7
         StringBuffer buffer = new StringBuffer();
 271  
 
 272  7
         String outputEncoding = this.outputEncoding;
 273  7
         if ( outputEncoding == null )
 274  
         {
 275  
             outputEncoding = "ISO-8859-1";
 276  
         }
 277  
 
 278  
         // header
 279  7
         buffer
 280  
             .append(
 281  
                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" )
 282  
             .append( "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"" ).append( locale )
 283  
             .append( "\" lang=\"" ).append( locale ).append( "\">\n" ).append( "<head>\n" )
 284  
             .append( "<meta http-equiv=\"content-type\" content=\"text/html; charset=" ).append( outputEncoding )
 285  
             .append( "\" />\n" );
 286  
 
 287  
         // title ("classname xref")
 288  7
         buffer.append( "<title>" );
 289  
         try
 290  
         {
 291  7
             JavaFile javaFile = fileManager.getFile( this.getCurrentFilename() );
 292  
             // Use the name of the file instead of the class to handle inner classes properly
 293  7
             if ( javaFile.getClassType() != null && javaFile.getClassType().getFilename() != null )
 294  
             {
 295  6
                 buffer.append( javaFile.getClassType().getFilename() );
 296  
             }
 297  
             else
 298  
             {
 299  1
                 buffer.append( this.getCurrentFilename() );
 300  
             }
 301  7
             buffer.append( " " );
 302  
         }
 303  
         catch ( IOException e )
 304  
         {
 305  
             e.printStackTrace();
 306  
         }
 307  
         finally
 308  
         {
 309  7
             buffer.append( "xref</title>\n" );
 310  7
         }
 311  
 
 312  
         // stylesheet link
 313  7
         buffer.append( "<link type=\"text/css\" rel=\"stylesheet\" href=\"" ).append( this.getPackageRoot() )
 314  
             .append( STYLESHEET_FILENAME ).append( "\" />\n" );
 315  
 
 316  7
         buffer.append( "</head>\n" ).append( "<body>\n" ).append( this.getFileOverview() );
 317  
 
 318  
         // start code section
 319  7
         buffer.append( "<pre>\n" );
 320  
 
 321  7
         return buffer.toString();
 322  
     }
 323  
 
 324  
     /**
 325  
      * Gets the footer attribute of the JavaCodeTransform object
 326  
      *
 327  
      * @return String
 328  
      */
 329  
     public final String getFooter()
 330  
     {
 331  7
         return "</pre>\n" + "<hr/>" + "<div id=\"footer\">" + JXR.NOTICE + "</div>" + "</body>\n" + "</html>\n";
 332  
     }
 333  
 
 334  
     /**
 335  
      * This is the public method for doing all transforms of code.
 336  
      *
 337  
      * @param sourceReader Reader
 338  
      * @param destWriter Writer
 339  
      * @param locale String
 340  
      * @param inputEncoding String
 341  
      * @param outputEncoding String
 342  
      * @param javadocLinkDir String
 343  
      * @param revision String
 344  
      * @param showHeader boolean
 345  
      * @param showFooter boolean
 346  
      * @throws IOException
 347  
      */
 348  
     public final void transform( Reader sourceReader, Writer destWriter, Locale locale, String inputEncoding,
 349  
                                  String outputEncoding, String javadocLinkDir, String revision, boolean showHeader,
 350  
                                  boolean showFooter )
 351  
         throws IOException
 352  
     {
 353  7
         this.locale = locale;
 354  7
         this.inputEncoding = inputEncoding;
 355  7
         this.outputEncoding = outputEncoding;
 356  7
         this.javadocLinkDir = javadocLinkDir;
 357  7
         this.revision = revision;
 358  
 
 359  7
         BufferedReader in = new BufferedReader( sourceReader );
 360  
 
 361  7
         PrintWriter out = new PrintWriter( destWriter );
 362  
 
 363  7
         String line = "";
 364  
 
 365  7
         if ( showHeader )
 366  
         {
 367  7
             out.println( getHeader() );
 368  
         }
 369  
 
 370  7
         int linenumber = 1;
 371  317
         while ( ( line = in.readLine() ) != null )
 372  
         {
 373  
             if ( LINE_NUMBERS )
 374  
             {
 375  310
                 out.print( "<a name=\"" + linenumber + "\" " + "href=\"#" + linenumber + "\">" + linenumber
 376  
                     + "</a>" + getLineWidth( linenumber ) );
 377  
             }
 378  
 
 379  310
             out.println( this.syntaxHighlight( line ) );
 380  
 
 381  310
             ++linenumber;
 382  
         }
 383  
 
 384  7
         if ( showFooter )
 385  
         {
 386  7
             out.println( getFooter() );
 387  
         }
 388  
 
 389  7
         out.flush();
 390  7
     }
 391  
 
 392  
     /**
 393  
      * This is the public method for doing all transforms of code.
 394  
      *
 395  
      * @param sourcefile String
 396  
      * @param destfile String
 397  
      * @param locale String
 398  
      * @param inputEncoding String
 399  
      * @param outputEncoding String
 400  
      * @param javadocLinkDir String
 401  
      * @param revision String
 402  
      * @throws IOException
 403  
      */
 404  
     public final void transform( String sourcefile, String destfile, Locale locale, String inputEncoding,
 405  
                                  String outputEncoding, String javadocLinkDir, String revision )
 406  
         throws IOException
 407  
     {
 408  7
         this.setCurrentFilename( sourcefile );
 409  
 
 410  7
         this.sourcefile = sourcefile;
 411  7
         this.destfile = destfile;
 412  
 
 413  
         //make sure that the parent directories exist...
 414  7
         new File( new File( destfile ).getParent() ).mkdirs();
 415  
 
 416  7
         Reader fr = null;
 417  7
         Writer fw = null;
 418  
         try
 419  
         {
 420  7
             if ( inputEncoding != null )
 421  
             {
 422  7
                 fr = new InputStreamReader( new FileInputStream( sourcefile ), inputEncoding );
 423  
             }
 424  
             else
 425  
             {
 426  
                 fr = new FileReader( sourcefile );
 427  
             }
 428  7
             if ( outputEncoding != null )
 429  
             {
 430  7
                 fw = new OutputStreamWriter( new FileOutputStream( destfile ), outputEncoding );
 431  
             }
 432  
             else
 433  
             {
 434  
                 fw = new FileWriter( destfile );
 435  
             }
 436  
 
 437  7
             transform( fr, fw, locale, inputEncoding, outputEncoding, javadocLinkDir, revision, true, true );
 438  7
         }
 439  
         catch ( RuntimeException e )
 440  
         {
 441  
             System.out.println( "Unable to processPath " + sourcefile + " => " + destfile );
 442  
             throw e;
 443  
         }
 444  
         finally
 445  
         {
 446  
             if ( fr != null )
 447  
             {
 448  
                 try
 449  
                 {
 450  7
                     fr.close();
 451  
                 }
 452  
                 catch ( Exception ex )
 453  
                 {
 454  
                     ex.printStackTrace();
 455  7
                 }
 456  
             }
 457  7
             if ( fw != null )
 458  
             {
 459  
                 try
 460  
                 {
 461  7
                     fw.close();
 462  
                 }
 463  
                 catch ( Exception ex )
 464  
                 {
 465  
                     ex.printStackTrace();
 466  14
                 }
 467  
             }
 468  7
         }
 469  7
     }
 470  
 
 471  
     /**
 472  
      * Get the current filename
 473  
      *
 474  
      * @return String
 475  
      */
 476  
     public final String getCurrentFilename()
 477  
     {
 478  509
         return this.currentFilename;
 479  
     }
 480  
 
 481  
     /**
 482  
      * Set the current filename
 483  
      *
 484  
      * @param filename String
 485  
      */
 486  
     public final void setCurrentFilename( String filename )
 487  
     {
 488  7
         this.currentFilename = filename;
 489  7
     }
 490  
 
 491  
     /**
 492  
      * From the current file, determine the package root based on the current
 493  
      * path.
 494  
      *
 495  
      * @return String
 496  
      */
 497  
     public final String getPackageRoot()
 498  
     {
 499  12
         StringBuffer buff = new StringBuffer();
 500  
 
 501  12
         JavaFile jf = null;
 502  
 
 503  
         try
 504  
         {
 505  12
             jf = fileManager.getFile( this.getCurrentFilename() );
 506  
         }
 507  
         catch ( IOException e )
 508  
         {
 509  
             e.printStackTrace();
 510  
             return null;
 511  12
         }
 512  
 
 513  12
         String current = jf.getPackageType().getName();
 514  
 
 515  12
         int count = this.getPackageCount( current );
 516  
 
 517  51
         for ( int i = 0; i < count; ++i )
 518  
         {
 519  39
             buff.append( "../" );
 520  
         }
 521  
 
 522  12
         return buff.toString();
 523  
     }
 524  
 
 525  
     /**
 526  
      * Given a line of text, search for URIs and make href's out of them
 527  
      *
 528  
      * @param line String
 529  
      * @return String
 530  
      */
 531  
     public final String uriFilter( String line )
 532  
     {
 533  1014
         for ( int i = 0; i < VALID_URI_SCHEMES.length; ++i )
 534  
         {
 535  676
             String scheme = VALID_URI_SCHEMES[i];
 536  
 
 537  676
             int index = line.indexOf( scheme );
 538  
 
 539  676
             if ( index != -1 )
 540  
             {
 541  7
                 int start = index;
 542  7
                 int end = -1;
 543  
 
 544  265
                 for ( int j = start; j < line.length(); ++j )
 545  
                 {
 546  265
                     char current = line.charAt( j );
 547  
 
 548  265
                     if ( !Character.isLetterOrDigit( current ) && isInvalidURICharacter( current ) )
 549  
                     {
 550  7
                         end = j;
 551  7
                         break;
 552  
                     }
 553  
 
 554  258
                     end = j;
 555  
                 }
 556  
 
 557  
                 //now you should have the full URI so you can replace this
 558  
                 //in the current buffer
 559  
 
 560  7
                 if ( end != -1 )
 561  
                 {
 562  7
                     String uri = line.substring( start, end );
 563  
 
 564  7
                     line = StringUtils.replace( line, uri,
 565  
                                                 "<a href=\"" + uri + "\" target=\"alexandria_uri\">" + uri + "</a>" );
 566  
                 }
 567  
             }
 568  
         }
 569  
 
 570  
         //if we are in a multiline comment we should not call JXR here.
 571  338
         if ( !inMultiLineComment && !inJavadocComment )
 572  
         {
 573  241
             return jxrFilter( line );
 574  
         }
 575  
 
 576  97
         return line;
 577  
     }
 578  
 
 579  
     /**
 580  
      * The current revision of the CVS module
 581  
      *
 582  
      * @return String
 583  
      */
 584  
     public final String getRevision()
 585  
     {
 586  
         return this.revision;
 587  
     }
 588  
 
 589  
     /**
 590  
      * The current source file being read
 591  
      *
 592  
      * @return source file name
 593  
      */
 594  
     public final String getSourcefile()
 595  
     {
 596  
         return this.sourcefile;
 597  
     }
 598  
 
 599  
     /**
 600  
      * The current dest file being written
 601  
      *
 602  
      * @return destination file name
 603  
      */
 604  
     public final String getDestfile()
 605  
     {
 606  
         return this.destfile;
 607  
     }
 608  
 
 609  
     /**
 610  
      * The current source directory being read from.
 611  
      *
 612  
      * @return source directory
 613  
      */
 614  
     public final String getSourceDirectory()
 615  
     {
 616  
         return this.sourcedir;
 617  
     }
 618  
 
 619  
     /**
 620  
      * Cross Reference the given line with JXR returning the new content.
 621  
      *
 622  
      * @param line String
 623  
      * @param packageName String
 624  
      * @param classType ClassType
 625  
      * @return String
 626  
      */
 627  
     public final String xrLine( String line, String packageName, ClassType classType )
 628  
     {
 629  5
         StringBuffer buff = new StringBuffer( line );
 630  
 
 631  5
         String link = null;
 632  5
         String find = null;
 633  5
         String href = null;
 634  
 
 635  5
         if ( classType != null )
 636  
         {
 637  5
             href = this.getHREF( packageName, classType );
 638  5
             find = classType.getName();
 639  
         }
 640  
         else
 641  
         {
 642  
             href = this.getHREF( packageName );
 643  
             find = packageName;
 644  
         }
 645  
 
 646  
         //build out what the link would be.
 647  5
         link = "<a href=\"" + href + "\">" + find + "</a>";
 648  
 
 649  
         //use the SimpleWordTokenizer to find all entries
 650  
         //that match word.  Then replace these with the link
 651  
 
 652  
         //now replace the word in the buffer with the link
 653  
 
 654  5
         String replace = link;
 655  5
         StringEntry[] tokens = SimpleWordTokenizer.tokenize( buff.toString(), find );
 656  
 
 657  10
         for ( int l = 0; l < tokens.length; ++l )
 658  
         {
 659  
 
 660  5
             int start = tokens[l].getIndex();
 661  5
             int end = tokens[l].getIndex() + find.length();
 662  
 
 663  5
             buff.replace( start, end, replace );
 664  
 
 665  
         }
 666  
 
 667  5
         return buff.toString();
 668  
     }
 669  
 
 670  
     /**
 671  
      * Highlight the package in this line.
 672  
      *
 673  
      * @param line input line
 674  
      * @param packageName package name
 675  
      * @return input line with linked package
 676  
      */
 677  
     public final String xrLine( String line, String packageName )
 678  
     {
 679  
         String href = this.getHREF( packageName );
 680  
 
 681  
         String find = packageName;
 682  
 
 683  
         //build out what the link would be.
 684  
         String link = "<a href=\"" + href + "\">" + find + "</a>";
 685  
 
 686  
         return StringUtils.replace( line, find, link );
 687  
     }
 688  
 
 689  
     // ----------------------------------------------------------------------
 690  
     // private methods
 691  
     // ----------------------------------------------------------------------
 692  
 
 693  
     /**
 694  
      * Filter html tags into more benign text.
 695  
      *
 696  
      * @param line String
 697  
      * @return html encoded line
 698  
      */
 699  
     private final String htmlFilter( String line )
 700  
     {
 701  310
         if ( line == null || line.equals( "" ) )
 702  
         {
 703  43
             return "";
 704  
         }
 705  267
         line = replace( line, "&", "&amp;" );
 706  267
         line = replace( line, "<", "&lt;" );
 707  267
         line = replace( line, ">", "&gt;" );
 708  267
         line = replace( line, "\\\\", "&#92;&#92;" );
 709  267
         line = replace( line, "\\\"", "\\&quot;" );
 710  267
         line = replace( line, "'\"'", "'&quot;'" );
 711  267
         return multiLineCommentFilter( line );
 712  
     }
 713  
 
 714  
     /**
 715  
      * Filter out multiLine comments. State is kept with a private boolean variable.
 716  
      *
 717  
      * @param line String
 718  
      * @return String
 719  
      */
 720  
     private final String multiLineCommentFilter( String line )
 721  
     {
 722  275
         if ( line == null || line.equals( "" ) )
 723  
         {
 724  8
             return "";
 725  
         }
 726  267
         StringBuffer buf = new StringBuffer();
 727  
         int index;
 728  
 
 729  
         //First, check for the end of a java comment.
 730  267
         if ( inJavadocComment && ( index = line.indexOf( "*/" ) ) > -1 && !isInsideString( line, index ) )
 731  
         {
 732  3
             inJavadocComment = false;
 733  3
             buf.append( JAVADOC_COMMENT_START );
 734  3
             buf.append( line.substring( 0, index ) );
 735  3
             buf.append( "*/" ).append( JAVADOC_COMMENT_END );
 736  3
             if ( line.length() > index + 2 )
 737  
             {
 738  
                 buf.append( inlineCommentFilter( line.substring( index + 2 ) ) );
 739  
             }
 740  
 
 741  3
             return uriFilter( buf.toString() );
 742  
         }
 743  
 
 744  
         //Second, check for the end of a multi-line comment.
 745  264
         if ( inMultiLineComment && ( index = line.indexOf( "*/" ) ) > -1 && !isInsideString( line, index ) )
 746  
         {
 747  5
             inMultiLineComment = false;
 748  5
             buf.append( COMMENT_START );
 749  5
             buf.append( line.substring( 0, index ) );
 750  5
             buf.append( "*/" ).append( COMMENT_END );
 751  5
             if ( line.length() > index + 2 )
 752  
             {
 753  
                 buf.append( inlineCommentFilter( line.substring( index + 2 ) ) );
 754  
             }
 755  5
             return uriFilter( buf.toString() );
 756  
         }
 757  
 
 758  
         //If there was no end detected and we're currently in a multi-line
 759  
         //comment, we don't want to do anymore work, so return line.
 760  259
         else if ( inMultiLineComment )
 761  
         {
 762  
 
 763  80
             StringBuffer buffer = new StringBuffer( line );
 764  80
             buffer.insert( 0, COMMENT_START );
 765  80
             buffer.append( COMMENT_END );
 766  80
             return uriFilter( buffer.toString() );
 767  
         }
 768  179
         else if ( inJavadocComment )
 769  
         {
 770  
 
 771  9
             StringBuffer buffer = new StringBuffer( line );
 772  9
             buffer.insert( 0, JAVADOC_COMMENT_START );
 773  9
             buffer.append( JAVADOC_COMMENT_END );
 774  9
             return uriFilter( buffer.toString() );
 775  
         }
 776  
 
 777  
         //We're not currently in a Javadoc comment, so check to see if the start
 778  
         //of a multi-line Javadoc comment is in this line.
 779  170
         else if ( ( index = line.indexOf( "/**" ) ) > -1 && !isInsideString( line, index ) )
 780  
         {
 781  3
             inJavadocComment = true;
 782  
             //Return result of other filters + everything after the start
 783  
             //of the multiline comment. We need to pass the through the
 784  
             //to the multiLineComment filter again in case the comment ends
 785  
             //on the same line.
 786  3
             buf.append( inlineCommentFilter( line.substring( 0, index ) ) );
 787  3
             buf.append( JAVADOC_COMMENT_START ).append( "/**" );
 788  3
             buf.append( JAVADOC_COMMENT_END );
 789  3
             buf.append( multiLineCommentFilter( line.substring( index + 3 ) ) );
 790  3
             return uriFilter( buf.toString() );
 791  
         }
 792  
 
 793  
         //We're not currently in a comment, so check to see if the start
 794  
         //of a multi-line comment is in this line.
 795  167
         else if ( ( index = line.indexOf( "/*" ) ) > -1 && !isInsideString( line, index ) )
 796  
         {
 797  5
             inMultiLineComment = true;
 798  
             //Return result of other filters + everything after the start
 799  
             //of the multiline comment. We need to pass the through the
 800  
             //to the multiLineComment filter again in case the comment ends
 801  
             //on the same line.
 802  5
             buf.append( inlineCommentFilter( line.substring( 0, index ) ) );
 803  5
             buf.append( COMMENT_START ).append( "/*" );
 804  5
             buf.append( multiLineCommentFilter( line.substring( index + 2 ) ) );
 805  5
             buf.append( COMMENT_END );
 806  5
             return uriFilter( buf.toString() );
 807  
         }
 808  
 
 809  
         //Otherwise, no useful multi-line comment information was found so
 810  
         //pass the line down to the next filter for processesing.
 811  
         else
 812  
         {
 813  162
             return inlineCommentFilter( line );
 814  
         }
 815  
     }
 816  
 
 817  
     /**
 818  
      * Filter inline comments from a line and formats them properly. One problem
 819  
      * we'll have to solve here: comments contained in a string should be
 820  
      * ignored... this is also true of the multiline comments. So, we could
 821  
      * either ignore the problem, or implement a function called something like
 822  
      * isInsideString(line, index) where index points to some point in the line
 823  
      * that we need to check... started doing this function below.
 824  
      *
 825  
      * @param line String
 826  
      * @return String
 827  
      */
 828  
     private final String inlineCommentFilter( String line )
 829  
     {
 830  170
         if ( line == null || line.equals( "" ) )
 831  
         {
 832  8
             return "";
 833  
         }
 834  162
         StringBuffer buf = new StringBuffer();
 835  
         int index;
 836  162
         if ( ( index = line.indexOf( "//" ) ) > -1 && !isInsideString( line, index ) )
 837  
         {
 838  
             buf.append( stringFilter( line.substring( 0, index ) ) );
 839  
             buf.append( COMMENT_START );
 840  
             buf.append( line.substring( index ) );
 841  
             buf.append( COMMENT_END );
 842  
         }
 843  
         else
 844  
         {
 845  162
             buf.append( stringFilter( line ) );
 846  
         }
 847  
 
 848  162
         return buf.toString();
 849  
     }
 850  
 
 851  
     /**
 852  
      * Filters strings from a line of text and formats them properly.
 853  
      *
 854  
      * @param line String
 855  
      * @return String
 856  
      */
 857  
     private final String stringFilter( String line )
 858  
     {
 859  233
         if ( line == null || line.equals( "" ) )
 860  
         {
 861  
             return "";
 862  
         }
 863  233
         StringBuffer buf = new StringBuffer();
 864  233
         if ( line.indexOf( "\"" ) <= -1 )
 865  
         {
 866  198
             return keywordFilter( line );
 867  
         }
 868  35
         int start = 0;
 869  35
         int startStringIndex = -1;
 870  35
         int endStringIndex = -1;
 871  
         int tempIndex;
 872  
         //Keep moving through String characters until we want to stop...
 873  177
         while ( ( tempIndex = line.indexOf( "\"" ) ) > -1 )
 874  
         {
 875  
             //We found the beginning of a string
 876  142
             if ( startStringIndex == -1 )
 877  
             {
 878  71
                 startStringIndex = 0;
 879  71
                 buf.append( stringFilter( line.substring( start, tempIndex ) ) );
 880  71
                 buf.append( STRING_START ).append( "\"" );
 881  71
                 line = line.substring( tempIndex + 1 );
 882  
             }
 883  
             //Must be at the end
 884  
             else
 885  
             {
 886  71
                 startStringIndex = -1;
 887  71
                 endStringIndex = tempIndex;
 888  71
                 buf.append( line.substring( 0, endStringIndex + 1 ) );
 889  71
                 buf.append( STRING_END );
 890  71
                 line = line.substring( endStringIndex + 1 );
 891  
             }
 892  
         }
 893  
 
 894  35
         buf.append( keywordFilter( line ) );
 895  
 
 896  35
         return buf.toString();
 897  
     }
 898  
 
 899  
     /**
 900  
      * Filters keywords from a line of text and formats them properly.
 901  
      *
 902  
      * @param line String
 903  
      * @return String
 904  
      */
 905  
     private final String keywordFilter( String line )
 906  
     {
 907  233
         final String CLASS_KEYWORD = "class";
 908  
 
 909  233
         if ( line == null || line.equals( "" ) )
 910  
         {
 911  
             return "";
 912  
         }
 913  233
         StringBuffer buf = new StringBuffer();
 914  233
         Hashtable usedReservedWords = new Hashtable();
 915  233
         int i = 0;
 916  
         char ch;
 917  233
         StringBuffer temp = new StringBuffer();
 918  2090
         while ( i < line.length() )
 919  
         {
 920  1857
             temp.setLength( 0 );
 921  1857
             ch = line.charAt( i );
 922  5047
             while ( i < line.length() && ( ( ch >= 65 && ch <= 90 ) || ( ch >= 97 && ch <= 122 ) ) )
 923  
             {
 924  3190
                 temp.append( ch );
 925  3190
                 i++;
 926  3190
                 if ( i < line.length() )
 927  
                 {
 928  3170
                     ch = line.charAt( i );
 929  
                 }
 930  
             }
 931  1857
             String tempString = temp.toString();
 932  
 
 933  
             // Special handling of css style class definitions
 934  1857
             if ( CLASS_KEYWORD.equals( tempString ) && ch == '=' )
 935  
             {
 936  
                 i++;
 937  
             }
 938  1857
             else if ( reservedWords.containsKey( tempString ) )
 939  
             {
 940  109
                 StringBuffer newLine = new StringBuffer( line.substring( 0, i - tempString.length() ) );
 941  109
                 newLine.append( RESERVED_WORD_START );
 942  109
                 newLine.append( tempString );
 943  109
                 newLine.append( RESERVED_WORD_END );
 944  109
                 newLine.append( line.substring( i ) );
 945  109
                 line = newLine.toString();
 946  109
                 i += ( RESERVED_WORD_START.length() + RESERVED_WORD_END.length() );
 947  
             }
 948  
             else
 949  
             {
 950  1748
                 i++;
 951  
             }
 952  
         }
 953  233
         buf.append( line );
 954  
 
 955  233
         return uriFilter( buf.toString() );
 956  
     }
 957  
 
 958  
     /**
 959  
      * Replace... I made it use a stringBuffer... hope it still works :)
 960  
      *
 961  
      * @param line String
 962  
      * @param oldString String
 963  
      * @param newString String
 964  
      * @return String
 965  
      */
 966  
     private final String replace( String line, String oldString, String newString )
 967  
     {
 968  1602
         int i = 0;
 969  1610
         while ( ( i = line.indexOf( oldString, i ) ) >= 0 )
 970  
         {
 971  8
             line = ( new StringBuffer().append( line.substring( 0, i ) ).append( newString ).append(
 972  
                 line.substring( i + oldString.length() ) ) ).toString();
 973  8
             i += newString.length();
 974  
         }
 975  1602
         return line;
 976  
     }
 977  
 
 978  
     /**
 979  
      * Checks to see if some position in a line is between String start and
 980  
      * ending characters. Not yet used in code or fully working :)
 981  
      *
 982  
      * @param line String
 983  
      * @param position int
 984  
      * @return boolean
 985  
      */
 986  
     private final boolean isInsideString( String line, int position )
 987  
     {
 988  17
         if ( line.indexOf( "\"" ) < 0 )
 989  
         {
 990  16
             return false;
 991  
         }
 992  
         int index;
 993  1
         String left = line.substring( 0, position );
 994  1
         String right = line.substring( position );
 995  1
         int leftCount = 0;
 996  1
         int rightCount = 0;
 997  2
         while ( ( index = left.indexOf( "\"" ) ) > -1 )
 998  
         {
 999  1
             leftCount++;
 1000  1
             left = left.substring( index + 1 );
 1001  
         }
 1002  4
         while ( ( index = right.indexOf( "\"" ) ) > -1 )
 1003  
         {
 1004  3
             rightCount++;
 1005  3
             right = right.substring( index + 1 );
 1006  
         }
 1007  1
         return ( rightCount % 2 != 0 && leftCount % 2 != 0 );
 1008  
     }
 1009  
 
 1010  
     /**
 1011  
      * Description of the Method
 1012  
      */
 1013  
     private final void loadHash()
 1014  
     {
 1015  4
         reservedWords.put( "abstract", "abstract" );
 1016  4
         reservedWords.put( "do", "do" );
 1017  4
         reservedWords.put( "inner", "inner" );
 1018  4
         reservedWords.put( "public", "public" );
 1019  4
         reservedWords.put( "var", "var" );
 1020  4
         reservedWords.put( "boolean", "boolean" );
 1021  4
         reservedWords.put( "continue", "continue" );
 1022  4
         reservedWords.put( "int", "int" );
 1023  4
         reservedWords.put( "return", "return" );
 1024  4
         reservedWords.put( "void", "void" );
 1025  4
         reservedWords.put( "break", "break" );
 1026  4
         reservedWords.put( "else", "else" );
 1027  4
         reservedWords.put( "interface", "interface" );
 1028  4
         reservedWords.put( "short", "short" );
 1029  4
         reservedWords.put( "volatile", "volatile" );
 1030  4
         reservedWords.put( "byvalue", "byvalue" );
 1031  4
         reservedWords.put( "extends", "extends" );
 1032  4
         reservedWords.put( "long", "long" );
 1033  4
         reservedWords.put( "static", "static" );
 1034  4
         reservedWords.put( "while", "while" );
 1035  4
         reservedWords.put( "case", "case" );
 1036  4
         reservedWords.put( "final", "final" );
 1037  4
         reservedWords.put( "native", "native" );
 1038  4
         reservedWords.put( "super", "super" );
 1039  4
         reservedWords.put( "transient", "transient" );
 1040  4
         reservedWords.put( "cast", "cast" );
 1041  4
         reservedWords.put( "float", "float" );
 1042  4
         reservedWords.put( "new", "new" );
 1043  4
         reservedWords.put( "rest", "rest" );
 1044  4
         reservedWords.put( "catch", "catch" );
 1045  4
         reservedWords.put( "for", "for" );
 1046  4
         reservedWords.put( "null", "null" );
 1047  4
         reservedWords.put( "synchronized", "synchronized" );
 1048  4
         reservedWords.put( "char", "char" );
 1049  4
         reservedWords.put( "finally", "finally" );
 1050  4
         reservedWords.put( "operator", "operator" );
 1051  4
         reservedWords.put( "this", "this" );
 1052  4
         reservedWords.put( "class", "class" );
 1053  4
         reservedWords.put( "generic", "generic" );
 1054  4
         reservedWords.put( "outer", "outer" );
 1055  4
         reservedWords.put( "switch", "switch" );
 1056  4
         reservedWords.put( "const", "const" );
 1057  4
         reservedWords.put( "goto", "goto" );
 1058  4
         reservedWords.put( "package", "package" );
 1059  4
         reservedWords.put( "throw", "throw" );
 1060  4
         reservedWords.put( "double", "double" );
 1061  4
         reservedWords.put( "if", "if" );
 1062  4
         reservedWords.put( "private", "private" );
 1063  4
         reservedWords.put( "true", "true" );
 1064  4
         reservedWords.put( "default", "default" );
 1065  4
         reservedWords.put( "import", "import" );
 1066  4
         reservedWords.put( "protected", "protected" );
 1067  4
         reservedWords.put( "try", "try" );
 1068  4
         reservedWords.put( "throws", "throws" );
 1069  4
     }
 1070  
 
 1071  
     /**
 1072  
      * Description of the Method
 1073  
      *
 1074  
      * @param oos ObjectOutputStream
 1075  
      * @throws IOException
 1076  
      */
 1077  
     final void writeObject( ObjectOutputStream oos )
 1078  
         throws IOException
 1079  
     {
 1080  
         oos.defaultWriteObject();
 1081  
     }
 1082  
 
 1083  
     /**
 1084  
      * Description of the Method
 1085  
      *
 1086  
      * @param ois ObjectInputStream
 1087  
      * @throws ClassNotFoundException
 1088  
      * @throws IOException
 1089  
      */
 1090  
     final void readObject( ObjectInputStream ois )
 1091  
         throws ClassNotFoundException, IOException
 1092  
     {
 1093  
         ois.defaultReadObject();
 1094  
     }
 1095  
 
 1096  
     /**
 1097  
      * Get an overview header for this file.
 1098  
      *
 1099  
      * @return String
 1100  
      */
 1101  
     private final String getFileOverview()
 1102  
     {
 1103  7
         StringBuffer overview = new StringBuffer();
 1104  
 
 1105  
         // only add the header if javadocs are present
 1106  7
         if ( javadocLinkDir != null )
 1107  
         {
 1108  7
             overview.append( "<div id=\"overview\">" );
 1109  
             //get the URI to get Javadoc info.
 1110  7
             StringBuffer javadocURI = new StringBuffer().append( javadocLinkDir );
 1111  
 
 1112  
             try
 1113  
             {
 1114  7
                 JavaFile jf = fileManager.getFile( this.getCurrentFilename() );
 1115  
 
 1116  7
                 javadocURI.append( StringUtils.replace( jf.getPackageType().getName(), ".", "/" ) );
 1117  7
                 javadocURI.append( "/" );
 1118  
                 // Use the name of the file instead of the class to handle inner classes properly
 1119  7
                 if ( jf.getClassType() != null && jf.getClassType().getFilename() != null )
 1120  
                 {
 1121  6
                     javadocURI.append( jf.getClassType().getFilename() );
 1122  
                 }
 1123  
                 else
 1124  
                 {
 1125  1
                     return "";
 1126  
                 }
 1127  6
                 javadocURI.append( ".html" );
 1128  
 
 1129  
             }
 1130  
             catch ( IOException e )
 1131  
             {
 1132  
                 e.printStackTrace();
 1133  6
             }
 1134  
 
 1135  6
             String javadocHREF = "<a href=\"" + javadocURI + "\">View Javadoc</a>";
 1136  
 
 1137  
             //get the generation time...
 1138  6
             overview.append( javadocHREF );
 1139  
 
 1140  6
             overview.append( "</div>" );
 1141  
         }
 1142  
 
 1143  6
         return overview.toString();
 1144  
     }
 1145  
 
 1146  
     /**
 1147  
      * Handles line width which may need to change depending on which line
 1148  
      * number you are on.
 1149  
      *
 1150  
      * @param linenumber int
 1151  
      * @return String
 1152  
      */
 1153  
     private final String getLineWidth( int linenumber )
 1154  
     {
 1155  310
         if ( linenumber < 10 )
 1156  
         {
 1157  53
             return "   ";
 1158  
         }
 1159  257
         else if ( linenumber < 100 )
 1160  
         {
 1161  257
             return "  ";
 1162  
         }
 1163  
         else
 1164  
         {
 1165  
             return " ";
 1166  
         }
 1167  
     }
 1168  
 
 1169  
     /**
 1170  
      * Handles finding classes based on the current filename and then makes
 1171  
      * HREFs for you to link to them with.
 1172  
      *
 1173  
      * @param line String
 1174  
      * @return String
 1175  
      */
 1176  
     private final String jxrFilter( String line )
 1177  
     {
 1178  241
         JavaFile jf = null;
 1179  
 
 1180  
         try
 1181  
         {
 1182  
             //if the current file isn't set then just return
 1183  241
             if ( this.getCurrentFilename() == null )
 1184  
             {
 1185  
                 return line;
 1186  
             }
 1187  
 
 1188  241
             jf = fileManager.getFile( this.getCurrentFilename() );
 1189  
         }
 1190  
         catch ( IOException e )
 1191  
         {
 1192  
             e.printStackTrace();
 1193  
             return line;
 1194  241
         }
 1195  
 
 1196  241
         Vector v = new Vector();
 1197  
 
 1198  
         //get the imported packages
 1199  241
         ImportType[] imports = jf.getImportTypes();
 1200  1341
         for ( int j = 0; j < imports.length; ++j )
 1201  
         {
 1202  1100
             v.addElement( imports[j].getPackage() );
 1203  
         }
 1204  
 
 1205  
         //add the current package.
 1206  241
         v.addElement( jf.getPackageType().getName() );
 1207  
 
 1208  241
         String[] packages = new String[v.size()];
 1209  241
         v.copyInto( packages );
 1210  
 
 1211  241
         StringEntry[] words = SimpleWordTokenizer.tokenize( line );
 1212  
 
 1213  
         //go through each word and then match them to the correct class if necessary.
 1214  357
         for ( int i = 0; i < words.length; ++i )
 1215  
         {
 1216  
             //each word
 1217  116
             StringEntry word = words[i];
 1218  
 
 1219  768
             for ( int j = 0; j < packages.length; ++j )
 1220  
             {
 1221  
                 //get the package from teh PackageManager because this will hold
 1222  
                 //the version with the classes also.
 1223  
 
 1224  652
                 PackageType currentImport = packageManager.getPackageType( packages[j] );
 1225  
 
 1226  
                 //the package here might in fact be null because it wasn't parsed out
 1227  
                 //this might be something that is either not included or os part
 1228  
                 //of another package and wasn't parsed out.
 1229  
 
 1230  652
                 if ( currentImport == null )
 1231  
                 {
 1232  564
                     continue;
 1233  
                 }
 1234  
 
 1235  
                 //see if the current word is within the package
 1236  
 
 1237  
                 //at this point the word could be a fully qualified package name
 1238  
                 //(FQPN) or an imported package name.
 1239  
 
 1240  88
                 String wordName = word.toString();
 1241  
 
 1242  88
                 if ( wordName.indexOf( "." ) != -1 )
 1243  
                 {
 1244  
                     //if there is a "." in the string then we have to assume
 1245  
                     //it is a package.
 1246  
 
 1247  22
                     String fqpn_package = null;
 1248  22
                     String fqpn_class = null;
 1249  
 
 1250  22
                     fqpn_package = wordName.substring( 0, wordName.lastIndexOf( "." ) );
 1251  22
                     fqpn_class = wordName.substring( wordName.lastIndexOf( "." ) + 1, wordName.length() );
 1252  
 
 1253  
                     //note. since this is a reference to a full package then
 1254  
                     //it doesn't have to be explicitly imported so this information
 1255  
                     //is useless.  Instead just see if it was parsed out.
 1256  
 
 1257  22
                     PackageType pt = packageManager.getPackageType( fqpn_package );
 1258  
 
 1259  22
                     if ( pt != null )
 1260  
                     {
 1261  
                         ClassType ct = pt.getClassType( fqpn_class );
 1262  
 
 1263  
                         if ( ct != null )
 1264  
                         {
 1265  
                             //OK.  the user specified a full package to be imported
 1266  
                             //that is in the package manager so it is time to
 1267  
                             //link to it.
 1268  
 
 1269  
                             line = xrLine( line, pt.getName(), ct );
 1270  
                         }
 1271  
                     }
 1272  
 
 1273  22
                     if ( fqpn_package.equals( currentImport.getName() )
 1274  
                         && currentImport.getClassType( fqpn_class ) != null )
 1275  
                     {
 1276  
                         //then the package we are currently in is the one specified in the string
 1277  
                         //and the import class is correct.
 1278  
                         line = xrLine( line, packages[j], currentImport.getClassType( fqpn_class ) );
 1279  
                     }
 1280  
                 }
 1281  66
                 else if ( currentImport.getClassType( wordName ) != null )
 1282  
                 {
 1283  5
                     line = xrLine( line, packages[j], currentImport.getClassType( wordName ) );
 1284  
                 }
 1285  
             }
 1286  
         }
 1287  
 
 1288  241
         return importFilter( line );
 1289  
     }
 1290  
 
 1291  
     /**
 1292  
      * Given the current package, get an HREF to the package and class given
 1293  
      *
 1294  
      * @param dest String
 1295  
      * @param jc ClassType
 1296  
      * @return String
 1297  
      */
 1298  
     private final String getHREF( String dest, ClassType jc )
 1299  
     {
 1300  5
         StringBuffer href = new StringBuffer();
 1301  
 
 1302  
         //find out how to go back to the root
 1303  5
         href.append( this.getPackageRoot() );
 1304  
 
 1305  
         //now find out how to get to the dest package
 1306  5
         dest = StringUtils.replace( dest, ".*", "" );
 1307  5
         dest = StringUtils.replace( dest, ".", "/" );
 1308  
 
 1309  5
         href.append( dest );
 1310  
 
 1311  
         // Now append filename.html
 1312  5
         if ( jc != null )
 1313  
         {
 1314  5
             href.append( "/" );
 1315  5
             href.append( jc.getFilename() );
 1316  5
             href.append( ".html" );
 1317  
         }
 1318  
 
 1319  5
         return href.toString();
 1320  
     }
 1321  
 
 1322  
     /**
 1323  
      * Based on the destination package, get the HREF.
 1324  
      *
 1325  
      * @param dest String
 1326  
      * @return String
 1327  
      */
 1328  
     private final String getHREF( String dest )
 1329  
     {
 1330  
         return getHREF( dest, null );
 1331  
     }
 1332  
 
 1333  
     /**
 1334  
      * <p>Given the name of a package... get the number of
 1335  
      * subdirectories/subpackages there would be. </p>
 1336  
      * <p>EX: org.apache.maven == 3 </p>
 1337  
      *
 1338  
      * @param packageName String
 1339  
      * @return int
 1340  
      */
 1341  
     private final int getPackageCount( String packageName )
 1342  
     {
 1343  12
         if ( packageName == null )
 1344  
         {
 1345  
             return 0;
 1346  
         }
 1347  
 
 1348  12
         int count = 0;
 1349  12
         int index = 0;
 1350  
 
 1351  
         while ( true )
 1352  
         {
 1353  39
             index = packageName.indexOf( ".", index );
 1354  
 
 1355  39
             if ( index == -1 )
 1356  
             {
 1357  12
                 break;
 1358  
             }
 1359  27
             ++index;
 1360  27
             ++count;
 1361  
         }
 1362  
 
 1363  
         //need to increment this by one
 1364  12
         count = ++count;
 1365  
 
 1366  12
         return count;
 1367  
     }
 1368  
 
 1369  
     /**
 1370  
      * Parse out the current link and look for package/import statements and
 1371  
      * then create HREFs for them
 1372  
      *
 1373  
      * @param line String
 1374  
      * @return String
 1375  
      */
 1376  
     private final String importFilter( String line )
 1377  
     {
 1378  241
         int start = -1;
 1379  
 
 1380  
         /*
 1381  
          Used for determining if this is a package declaration.  If it is
 1382  
          then we can make some additional assumptions:
 1383  
          - that this isn't a Class import so the full String is valid
 1384  
          - that it WILL be on the disk since this is based on the current
 1385  
          - file.
 1386  
          */
 1387  241
         boolean isPackage = line.trim().startsWith( "package " );
 1388  241
         boolean isImport = line.trim().startsWith( "import " );
 1389  
 
 1390  241
         if ( isImport || isPackage )
 1391  
         {
 1392  
             start = line.trim().indexOf( " " );
 1393  
         }
 1394  
 
 1395  241
         if ( start != -1 )
 1396  
         {
 1397  
             //filter out this packagename...
 1398  
             String pkg = line.substring( start, line.length() ).trim();
 1399  
 
 1400  
             //specify the classname of this import if any.
 1401  
             String classname = null;
 1402  
 
 1403  
             if ( pkg.indexOf( ".*" ) != -1 )
 1404  
             {
 1405  
                 pkg = StringUtils.replace( pkg, ".*", "" );
 1406  
             }
 1407  
             else if ( !isPackage )
 1408  
             {
 1409  
                 //this is an explicit Class import
 1410  
 
 1411  
                 String packageLine = pkg.toString();
 1412  
 
 1413  
                 // This catches a boundary problem where you have something like:
 1414  
                 //
 1415  
                 // Foo foo = FooMaster.getFooInstance().
 1416  
                 //     danceLittleFoo();
 1417  
                 //
 1418  
                 // This breaks Jxr and won't be a problem when we hook
 1419  
                 // in the real parser.
 1420  
 
 1421  
                 int a = packageLine.lastIndexOf( "." ) + 1;
 1422  
                 int b = packageLine.length() - 1;
 1423  
 
 1424  
                 if ( a > b + 1 )
 1425  
                 {
 1426  
                     classname = packageLine.substring( packageLine.lastIndexOf( "." ) + 1, packageLine.length() - 1 );
 1427  
 
 1428  
                     int end = pkg.lastIndexOf( "." );
 1429  
                     if ( end == -1 )
 1430  
                     {
 1431  
                         end = pkg.length() - 1;
 1432  
                     }
 1433  
 
 1434  
                     pkg = pkg.substring( 0, end );
 1435  
                 }
 1436  
             }
 1437  
 
 1438  
             pkg = StringUtils.replace( pkg, ";", "" );
 1439  
             String pkgHREF = getHREF( pkg );
 1440  
             //if this package is within the PackageManager then you can create an HREF for it.
 1441  
 
 1442  
             if ( packageManager.getPackageType( pkg ) != null || isPackage )
 1443  
             {
 1444  
                 //Create an HREF for explicit classname imports
 1445  
                 if ( classname != null )
 1446  
                 {
 1447  
                     line = StringUtils.replace( line, classname, "<a href=\"" + pkgHREF + "/" + classname + ".html"
 1448  
                         + "\">" + classname + "</a>" );
 1449  
                 }
 1450  
 
 1451  
                 //now replace the given package with a href
 1452  
                 line = StringUtils.replace( line, pkg, "<a href=\"" + pkgHREF + "/" + DirectoryIndexer.INDEX + "\">"
 1453  
                     + pkg + "</a>" );
 1454  
             }
 1455  
 
 1456  
         }
 1457  
 
 1458  241
         return line;
 1459  
     }
 1460  
 
 1461  
 
 1462  
     /**
 1463  
      * if the given char is not one of the following in VALID_URI_CHARS then
 1464  
      * return true
 1465  
      *
 1466  
      * @param c char to check against VALID_URI_CHARS list
 1467  
      * @return <code>true</code> if c is a valid URI char
 1468  
      */
 1469  
     private final boolean isInvalidURICharacter( char c )
 1470  
     {
 1471  507
         for ( int i = 0; i < VALID_URI_CHARS.length; ++i )
 1472  
         {
 1473  500
             if ( VALID_URI_CHARS[i] == c )
 1474  
             {
 1475  51
                 return false;
 1476  
             }
 1477  
         }
 1478  
 
 1479  7
         return true;
 1480  
     }
 1481  
 }