Coverage Report - org.apache.maven.plugin.javadoc.AbstractFixJavadocMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractFixJavadocMojo
78 %
808/1039
61 %
426/702
5,364
AbstractFixJavadocMojo$JavaEntityTags
55 %
24/44
43 %
6/14
5,364
 
 1  
 package org.apache.maven.plugin.javadoc;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.BufferedReader;
 23  
 import java.io.File;
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.io.Reader;
 27  
 import java.io.StringReader;
 28  
 import java.io.StringWriter;
 29  
 import java.io.Writer;
 30  
 import java.lang.reflect.Method;
 31  
 import java.net.MalformedURLException;
 32  
 import java.net.URL;
 33  
 import java.net.URLClassLoader;
 34  
 import java.util.ArrayList;
 35  
 import java.util.Arrays;
 36  
 import java.util.Collections;
 37  
 import java.util.Iterator;
 38  
 import java.util.LinkedHashMap;
 39  
 import java.util.LinkedList;
 40  
 import java.util.List;
 41  
 import java.util.Locale;
 42  
 import java.util.Map;
 43  
 import java.util.Properties;
 44  
 import java.util.StringTokenizer;
 45  
 import java.util.regex.Pattern;
 46  
 
 47  
 import org.apache.commons.lang.ClassUtils;
 48  
 import org.apache.maven.artifact.Artifact;
 49  
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 50  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 51  
 import org.apache.maven.plugin.AbstractMojo;
 52  
 import org.apache.maven.plugin.MojoExecutionException;
 53  
 import org.apache.maven.plugin.MojoFailureException;
 54  
 import org.apache.maven.project.MavenProject;
 55  
 import org.apache.maven.settings.Settings;
 56  
 import org.codehaus.plexus.components.interactivity.InputHandler;
 57  
 import org.codehaus.plexus.util.FileUtils;
 58  
 import org.codehaus.plexus.util.IOUtil;
 59  
 import org.codehaus.plexus.util.ReaderFactory;
 60  
 import org.codehaus.plexus.util.StringUtils;
 61  
 import org.codehaus.plexus.util.WriterFactory;
 62  
 
 63  
 import com.thoughtworks.qdox.JavaDocBuilder;
 64  
 import com.thoughtworks.qdox.model.AbstractInheritableJavaEntity;
 65  
 import com.thoughtworks.qdox.model.AbstractJavaEntity;
 66  
 import com.thoughtworks.qdox.model.Annotation;
 67  
 import com.thoughtworks.qdox.model.DocletTag;
 68  
 import com.thoughtworks.qdox.model.JavaClass;
 69  
 import com.thoughtworks.qdox.model.JavaField;
 70  
 import com.thoughtworks.qdox.model.JavaMethod;
 71  
 import com.thoughtworks.qdox.model.JavaParameter;
 72  
 import com.thoughtworks.qdox.model.Type;
 73  
 import com.thoughtworks.qdox.model.TypeVariable;
 74  
 import com.thoughtworks.qdox.parser.ParseException;
 75  
 
 76  
 /**
 77  
  * Abstract class to fix Javadoc documentation and tags in source files.
 78  
  * <br/>
 79  
  * See <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javadoc.html#wheretags">Where Tags Can Be Used</a>.
 80  
  *
 81  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 82  
  * @version $Id$
 83  
  * @since 2.6
 84  
  */
 85  2
 public abstract class AbstractFixJavadocMojo
 86  
     extends AbstractMojo
 87  
 {
 88  
     /** The vm line separator */
 89  1
     private static final String EOL = System.getProperty( "line.separator" );
 90  
 
 91  
     /** Tag name for &#64;author **/
 92  
     private static final String AUTHOR_TAG = "author";
 93  
 
 94  
     /** Tag name for &#64;version **/
 95  
     private static final String VERSION_TAG = "version";
 96  
 
 97  
     /** Tag name for &#64;since **/
 98  
     private static final String SINCE_TAG = "since";
 99  
 
 100  
     /** Tag name for &#64;param **/
 101  
     private static final String PARAM_TAG = "param";
 102  
 
 103  
     /** Tag name for &#64;return **/
 104  
     private static final String RETURN_TAG = "return";
 105  
 
 106  
     /** Tag name for &#64;throws **/
 107  
     private static final String THROWS_TAG = "throws";
 108  
 
 109  
     /** Tag name for {&#64;inheritDoc} **/
 110  
     private static final String INHERITED_TAG = "{@inheritDoc}";
 111  
 
 112  
     /** Start Javadoc String i.e. <code>&#47;&#42;&#42;</code> **/
 113  
     private static final String START_JAVADOC = "/**";
 114  
 
 115  
     /** End Javadoc String i.e. <code>&#42;&#47;</code> **/
 116  
     private static final String END_JAVADOC = "*/";
 117  
 
 118  
     /** Javadoc Separator i.e. <code> &#42; </code> **/
 119  
     private static final String SEPARATOR_JAVADOC = " * ";
 120  
 
 121  
     /** Inherited Javadoc i.e. <code>&#47;&#42;&#42; {&#64;inheritDoc} &#42;&#47;</code> **/
 122  
     private static final String INHERITED_JAVADOC = START_JAVADOC + " " + INHERITED_TAG + " " + END_JAVADOC;
 123  
 
 124  
     /** <code>all</code> parameter used by {@link #fixTags} **/
 125  
     private static final String FIX_TAGS_ALL = "all";
 126  
 
 127  
     /** <code>public</code> parameter used by {@link #level} **/
 128  
     private static final String LEVEL_PUBLIC = "public";
 129  
 
 130  
     /** <code>protected</code> parameter used by {@link #level} **/
 131  
     private static final String LEVEL_PROTECTED = "protected";
 132  
 
 133  
     /** <code>package</code> parameter used by {@link #level} **/
 134  
     private static final String LEVEL_PACKAGE = "package";
 135  
 
 136  
     /** <code>private</code> parameter used by {@link #level} **/
 137  
     private static final String LEVEL_PRIVATE = "private";
 138  
 
 139  
     /** The Clirr Maven plugin groupId <code>org.codehaus.mojo</code> **/
 140  
     private static final String CLIRR_MAVEN_PLUGIN_GROUPID = "org.codehaus.mojo";
 141  
 
 142  
     /** The Clirr Maven plugin artifactId <code>clirr-maven-plugin</code> **/
 143  
     private static final String CLIRR_MAVEN_PLUGIN_ARTIFACTID = "clirr-maven-plugin";
 144  
 
 145  
     /** The latest Clirr Maven plugin version <code>2.2.2</code> **/
 146  
     private static final String CLIRR_MAVEN_PLUGIN_VERSION = "2.2.2";
 147  
 
 148  
     /** The Clirr Maven plugin goal <code>check</code> **/
 149  
     private static final String CLIRR_MAVEN_PLUGIN_GOAL = "check";
 150  
 
 151  
     // ----------------------------------------------------------------------
 152  
     // Mojo components
 153  
     // ----------------------------------------------------------------------
 154  
 
 155  
     /**
 156  
      * Input handler, needed for command line handling.
 157  
      *
 158  
      * @component
 159  
      */
 160  
     private InputHandler inputHandler;
 161  
 
 162  
     // ----------------------------------------------------------------------
 163  
     // Mojo parameters
 164  
     // ----------------------------------------------------------------------
 165  
 
 166  
     /**
 167  
      * Version to compare the current code against using the
 168  
      * <a href="http://mojo.codehaus.org/clirr-maven-plugin/">Clirr Maven Plugin</a>.
 169  
      * <br/>
 170  
      * See <a href="#defaultSince">defaultSince</a>.
 171  
      *
 172  
      * @parameter expression="${comparisonVersion}" default-value="(,${project.version})"
 173  
      */
 174  
     private String comparisonVersion;
 175  
 
 176  
     /**
 177  
      * Default value for the Javadoc tag <code>&#64;author</code>.
 178  
      * <br/>
 179  
      * If not specified, the <code>user.name</code> defined in the System properties will be used.
 180  
      *
 181  
      * @parameter expression="${defaultAuthor}"
 182  
      */
 183  
     private String defaultAuthor;
 184  
 
 185  
     /**
 186  
      * Default value for the Javadoc tag <code>&#64;since</code>.
 187  
      * <br/>
 188  
      *
 189  
      * @parameter expression="${defaultSince}" default-value="${project.version}"
 190  
      */
 191  
     private String defaultSince;
 192  
 
 193  
     /**
 194  
      * Default value for the Javadoc tag <code>&#64;version</code>.
 195  
      * <br/>
 196  
      * By default, it is <code>&#36;Id:&#36;</code>, corresponding to a
 197  
      * <a href="http://svnbook.red-bean.com/en/1.1/ch07s02.html#svn-ch-7-sect-2.3.4">SVN keyword</a>.
 198  
      * Refer to your SCM to use an other SCM keyword.
 199  
      *
 200  
      * @parameter expression="${defaultVersion}"
 201  
      */
 202  2
     private String defaultVersion = "\u0024Id: \u0024"; // can't use default-value="\u0024Id: \u0024"
 203  
 
 204  
     /**
 205  
      * The file encoding to use when reading the source files. If the property
 206  
      * <code>project.build.sourceEncoding</code> is not set, the platform default encoding is used.
 207  
      *
 208  
      * @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
 209  
      */
 210  
     private String encoding;
 211  
 
 212  
     /**
 213  
      * Comma separated excludes Java files, i.e. <code>&#42;&#42;/&#42;Test.java</code>.
 214  
      *
 215  
      * @parameter expression="${excludes}"
 216  
      */
 217  
     private String excludes;
 218  
 
 219  
     /**
 220  
      * Comma separated tags to fix in classes, interfaces or methods Javadoc comments.
 221  
      * Possible values are:
 222  
      * <ul>
 223  
      * <li>all (fix all Javadoc tags)</li>
 224  
      * <li>author (fix only &#64;author tag)</li>
 225  
      * <li>version (fix only &#64;version tag)</li>
 226  
      * <li>since (fix only &#64;since tag)</li>
 227  
      * <li>param (fix only &#64;param tag)</li>
 228  
      * <li>return (fix only &#64;return tag)</li>
 229  
      * <li>throws (fix only &#64;throws tag)</li>
 230  
      * </ul>
 231  
      *
 232  
      * @parameter expression="${fixTags}" default-value="all"
 233  
      */
 234  
     private String fixTags;
 235  
 
 236  
     /**
 237  
      * Flag to fix the classes or interfaces Javadoc comments according the <code>level</code>.
 238  
      *
 239  
      * @parameter expression="${fixClassComment}" default-value="true"
 240  
      */
 241  
     private boolean fixClassComment;
 242  
 
 243  
     /**
 244  
      * Flag to fix the fields Javadoc comments according the <code>level</code>.
 245  
      *
 246  
      * @parameter expression="${fixFieldComment}" default-value="true"
 247  
      */
 248  
     private boolean fixFieldComment;
 249  
 
 250  
     /**
 251  
      * Flag to fix the methods Javadoc comments according the <code>level</code>.
 252  
      *
 253  
      * @parameter expression="${fixMethodComment}" default-value="true"
 254  
      */
 255  
     private boolean fixMethodComment;
 256  
 
 257  
     /**
 258  
      * Forcing the goal execution i.e. skip warranty messages (not recommended).
 259  
      *
 260  
      * @parameter expression="${force}"
 261  
      */
 262  
     private boolean force;
 263  
 
 264  
     /**
 265  
      * Flag to ignore or not Clirr.
 266  
      *
 267  
      * @parameter expression="${ignoreClirr}" default-value="false"
 268  
      */
 269  
     protected boolean ignoreClirr;
 270  
 
 271  
     /**
 272  
      * Comma separated includes Java files, i.e. <code>&#42;&#42;/&#42;Test.java</code>.
 273  
      *
 274  
      * @parameter expression="${includes}" default-value="**\/*.java"
 275  
      */
 276  
     private String includes;
 277  
 
 278  
     /**
 279  
      * Specifies the access level for classes and members to show in the Javadocs.
 280  
      * Possible values are:
 281  
      * <ul>
 282  
      * <li><a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#public">public</a>
 283  
      * (shows only public classes and members)</li>
 284  
      * <li><a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#protected">protected</a>
 285  
      * (shows only public and protected classes and members)</li>
 286  
      * <li><a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#package">package</a>
 287  
      * (shows all classes and members not marked private)</li>
 288  
      * <li><a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#private">private</a>
 289  
      * (shows all classes and members)</li>
 290  
      * </ul>
 291  
      * <br/>
 292  
      *
 293  
      * @parameter expression="${level}" default-value="protected"
 294  
      */
 295  
     private String level;
 296  
 
 297  
     /**
 298  
      * The local repository where the artifacts are located, used by the tests.
 299  
      *
 300  
      * @parameter expression="${localRepository}"
 301  
      */
 302  
     private ArtifactRepository localRepository;
 303  
 
 304  
     /**
 305  
      * Output directory where Java classes will be rewrited.
 306  
      *
 307  
      * @parameter expression="${outputDirectory}" default-value="${project.build.sourceDirectory}"
 308  
      */
 309  
     private File outputDirectory;
 310  
 
 311  
     /**
 312  
      * The Maven Project Object.
 313  
      *
 314  
      * @parameter expression="${project}"
 315  
      * @required
 316  
      * @readonly
 317  
      */
 318  
     private MavenProject project;
 319  
 
 320  
     /**
 321  
      * The current user system settings for use in Maven.
 322  
      *
 323  
      * @parameter expression="${settings}"
 324  
      * @required
 325  
      * @readonly
 326  
      */
 327  
     private Settings settings;
 328  
 
 329  
     // ----------------------------------------------------------------------
 330  
     // Internal fields
 331  
     // ----------------------------------------------------------------------
 332  
 
 333  
     /** The current project class loader. */
 334  
     private ClassLoader projectClassLoader;
 335  
 
 336  
     /**
 337  
      * Split {@link #fixTags} by comma.
 338  
      * @see {@link #init()}
 339  
      */
 340  
     private String[] fixTagsSplitted;
 341  
 
 342  
     /** New classes found by Clirr. */
 343  
     private List clirrNewClasses;
 344  
 
 345  
     /** New Methods in a Class (the key) found by Clirr. */
 346  
     private Map clirrNewMethods;
 347  
 
 348  
     /** List of classes where <code>&#42;since</code> is added. Will be used to add or not this tag in the methods. */
 349  
     private List sinceClasses;
 350  
 
 351  
     /** {@inheritDoc} */
 352  
     public void execute()
 353  
         throws MojoExecutionException, MojoFailureException
 354  
     {
 355  2
         if ( !fixClassComment && !fixFieldComment && !fixMethodComment )
 356  
         {
 357  0
             getLog().info( "Specified to NOT fix classes, fields and methods. Nothing to do." );
 358  0
             return;
 359  
         }
 360  
 
 361  
         // verify goal params
 362  2
         init();
 363  
 
 364  2
         if ( fixTagsSplitted.length == 0 )
 365  
         {
 366  0
             getLog().info( "No fix tag specified. Nothing to do." );
 367  0
             return;
 368  
         }
 369  
 
 370  
         // add warranty msg
 371  2
         if ( !preCheck() )
 372  
         {
 373  0
             return;
 374  
         }
 375  
 
 376  
         // run clirr
 377  2
         executeClirr();
 378  
 
 379  
         // run qdox and process
 380  
         try
 381  
         {
 382  2
             JavaClass[] javaClasses = getQdoxClasses();
 383  
 
 384  2
             if ( javaClasses != null )
 385  
             {
 386  14
                 for ( int i = 0; i < javaClasses.length; i++ )
 387  
                 {
 388  12
                     JavaClass javaClass = javaClasses[i];
 389  
 
 390  12
                     processFix( javaClass );
 391  
                 }
 392  
             }
 393  
         }
 394  0
         catch ( IOException e )
 395  
         {
 396  0
             throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
 397  2
         }
 398  2
     }
 399  
 
 400  
     // ----------------------------------------------------------------------
 401  
     // protected methods
 402  
     // ----------------------------------------------------------------------
 403  
 
 404  
     /**
 405  
      * @param p not null maven project.
 406  
      * @return the artifact type.
 407  
      */
 408  
     protected String getArtifactType( MavenProject p )
 409  
     {
 410  0
         return p.getArtifact().getType();
 411  
     }
 412  
 
 413  
     /**
 414  
      * @param p not null maven project.
 415  
      * @return the list of source paths for the given project.
 416  
      */
 417  
     protected List getProjectSourceRoots( MavenProject p )
 418  
     {
 419  2
         return p.getCompileSourceRoots();
 420  
     }
 421  
 
 422  
     /**
 423  
      * @param p not null
 424  
      * @return the compile classpath elements
 425  
      * @throws DependencyResolutionRequiredException if any
 426  
      */
 427  
     protected List getCompileClasspathElements( MavenProject p )
 428  
         throws DependencyResolutionRequiredException
 429  
     {
 430  2
         return p.getCompileClasspathElements();
 431  
     }
 432  
 
 433  
     /**
 434  
      * @param javaMethod not null
 435  
      * @return the fully qualify name of javaMethod with signature
 436  
      */
 437  
     protected static String getJavaMethodAsString( JavaMethod javaMethod )
 438  
     {
 439  5
         StringBuffer sb = new StringBuffer();
 440  
 
 441  5
         sb.append( javaMethod.getParentClass().getFullyQualifiedName() );
 442  5
         sb.append( "#" ).append( javaMethod.getCallSignature() );
 443  
 
 444  5
         return sb.toString();
 445  
     }
 446  
 
 447  
     // ----------------------------------------------------------------------
 448  
     // private methods
 449  
     // ----------------------------------------------------------------------
 450  
 
 451  
     /**
 452  
      * Init goal parameters.
 453  
      */
 454  
     private void init()
 455  
     {
 456  
         // defaultAuthor
 457  2
         if ( StringUtils.isEmpty( defaultAuthor ) )
 458  
         {
 459  0
             defaultAuthor = System.getProperty( "user.name" );
 460  
         }
 461  
 
 462  
         // defaultSince
 463  2
         int i = defaultSince.indexOf( "-" + Artifact.SNAPSHOT_VERSION );
 464  2
         if ( i != -1 )
 465  
         {
 466  2
             defaultSince = defaultSince.substring( 0, i );
 467  
         }
 468  
 
 469  
         // fixTags
 470  2
         if ( !FIX_TAGS_ALL.equalsIgnoreCase( fixTags.trim() ) )
 471  
         {
 472  0
             String[] split = StringUtils.split( fixTags, "," );
 473  0
             List filtered = new LinkedList();
 474  0
             for ( int j = 0; j < split.length; j++ )
 475  
             {
 476  0
                 String s = split[j].trim();
 477  0
                 if ( FIX_TAGS_ALL.equalsIgnoreCase( s.trim() ) || AUTHOR_TAG.equalsIgnoreCase( s.trim() )
 478  
                     || VERSION_TAG.equalsIgnoreCase( s.trim() ) || SINCE_TAG.equalsIgnoreCase( s.trim() )
 479  
                     || PARAM_TAG.equalsIgnoreCase( s.trim() ) || RETURN_TAG.equalsIgnoreCase( s.trim() )
 480  
                     || THROWS_TAG.equalsIgnoreCase( s.trim() ) )
 481  
                 {
 482  0
                     filtered.add( s );
 483  
                 }
 484  
                 else
 485  
                 {
 486  0
                     getLog().warn( "Unrecognized '" + s + "' for fixTags parameter. Ignored it!" );
 487  
                 }
 488  
             }
 489  0
             fixTags = StringUtils.join( filtered.iterator(), "," );
 490  
         }
 491  2
         fixTagsSplitted = StringUtils.split( fixTags, "," );
 492  
 
 493  
         // encoding
 494  2
         if ( StringUtils.isEmpty( encoding ) )
 495  
         {
 496  0
             getLog().warn(
 497  
                            "File encoding has not been set, using platform encoding "
 498  
                                + ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
 499  0
             encoding = ReaderFactory.FILE_ENCODING;
 500  
         }
 501  
 
 502  
         // level
 503  2
         if ( !( LEVEL_PUBLIC.equalsIgnoreCase( level.trim() ) || LEVEL_PROTECTED.equalsIgnoreCase( level.trim() )
 504  
             || LEVEL_PACKAGE.equalsIgnoreCase( level.trim() ) || LEVEL_PRIVATE.equalsIgnoreCase( level.trim() ) ) )
 505  
         {
 506  0
             getLog().warn( "Unrecognized '" + level + "' for level parameter, using 'protected' level." );
 507  0
             level = "protected";
 508  
         }
 509  2
     }
 510  
 
 511  
     /**
 512  
      * @return <code>true</code> if the user wants to proceed, <code>false</code> otherwise.
 513  
      * @throws MojoExecutionException if any
 514  
      */
 515  
     private boolean preCheck()
 516  
         throws MojoExecutionException
 517  
     {
 518  2
         if ( force )
 519  
         {
 520  2
             return true;
 521  
         }
 522  
 
 523  0
         if ( outputDirectory != null
 524  
             && !outputDirectory.getAbsolutePath().equals( getProjectSourceDirectory().getAbsolutePath() ) )
 525  
         {
 526  0
             return true;
 527  
         }
 528  
 
 529  0
         if ( !settings.isInteractiveMode() )
 530  
         {
 531  0
             getLog().error(
 532  
                             "Maven is not attempt to interact with the user for input. "
 533  
                                 + "Verify the <interactiveMode/> configuration in your settings." );
 534  0
             return false;
 535  
         }
 536  
 
 537  0
         getLog().warn( "" );
 538  0
         getLog().warn( "    WARRANTY DISCLAIMER" );
 539  0
         getLog().warn( "" );
 540  0
         getLog().warn( "All warranties with regard to this Maven goal are disclaimed!" );
 541  0
         getLog().warn( "The changes will be done directly in the source code." );
 542  0
         getLog().warn(
 543  
                        "The Maven Team strongly recommends the use of a SCM software BEFORE executing this "
 544  
                            + "goal." );
 545  0
         getLog().warn( "" );
 546  
 
 547  
         while ( true )
 548  
         {
 549  0
             getLog().info( "Are you sure to proceed? [Y]es [N]o" );
 550  
 
 551  
             try
 552  
             {
 553  0
                 String userExpression = inputHandler.readLine();
 554  0
                 if ( userExpression == null || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "Y" )
 555  
                     || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "Yes" ) )
 556  
                 {
 557  0
                     getLog().info( "OK, let's proceed..." );
 558  0
                     break;
 559  
                 }
 560  0
                 if ( userExpression == null || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "N" )
 561  
                     || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "No" ) )
 562  
                 {
 563  0
                     getLog().info( "No changes in your sources occur." );
 564  0
                     return false;
 565  
                 }
 566  
             }
 567  0
             catch ( IOException e )
 568  
             {
 569  0
                 throw new MojoExecutionException( "Unable to read from standard input.", e );
 570  0
             }
 571  
         }
 572  
 
 573  0
         return true;
 574  
     }
 575  
 
 576  
     /**
 577  
      * @return the source dir as File for the given project
 578  
      */
 579  
     private File getProjectSourceDirectory()
 580  
     {
 581  9
         return new File( project.getBuild().getSourceDirectory() );
 582  
     }
 583  
 
 584  
     /**
 585  
      * Invoke Maven to run clirr-maven-plugin to find API differences.
 586  
      */
 587  
     private void executeClirr()
 588  
     {
 589  2
         if ( ignoreClirr )
 590  
         {
 591  0
             getLog().info( "Clirr is ignored." );
 592  0
             return;
 593  
         }
 594  
 
 595  2
         String clirrGoal = getFullClirrGoal();
 596  
 
 597  
         // http://mojo.codehaus.org/clirr-maven-plugin/check-mojo.html
 598  2
         File clirrTextOutputFile = new File( project.getBuild().getDirectory(), "clirr.txt" );
 599  2
         Properties properties = new Properties();
 600  2
         properties.put( "textOutputFile", clirrTextOutputFile.getAbsolutePath() );
 601  2
         properties.put( "comparisonVersion", comparisonVersion );
 602  2
         properties.put( "failOnError", "false" );
 603  
 
 604  2
         File invokerLogFile = new File( project.getBuild().getDirectory(), "invoker-clirr-maven-plugin.txt" );
 605  2
         JavadocUtil.invokeMaven( getLog(), new File( localRepository.getBasedir() ), project.getFile(),
 606  
                                  Collections.singletonList( clirrGoal ), properties, invokerLogFile );
 607  
 
 608  
         try
 609  
         {
 610  2
             if ( invokerLogFile.exists() )
 611  
             {
 612  2
                 String invokerLogContent = readFile( invokerLogFile, "UTF-8" );
 613  
                 // see org.codehaus.mojo.clirr.AbstractClirrMojo#getComparisonArtifact()
 614  2
                 final String artifactNotFoundMsg =
 615  
                     "Unable to find a previous version of the project in the repository";
 616  2
                 if ( invokerLogContent.indexOf( artifactNotFoundMsg ) != -1 )
 617  
                 {
 618  0
                     getLog().warn( "No previous artifact has been deployed, Clirr is ignored." );
 619  0
                     return;
 620  
                 }
 621  
             }
 622  
         }
 623  0
         catch ( IOException e )
 624  
         {
 625  0
             getLog().debug( "IOException: " + e.getMessage() );
 626  2
         }
 627  
 
 628  
         try
 629  
         {
 630  2
             parseClirrTextOutputFile( clirrTextOutputFile );
 631  
         }
 632  0
         catch ( IOException e )
 633  
         {
 634  0
             if ( getLog().isDebugEnabled() )
 635  
             {
 636  0
                 getLog().debug( "IOException: " + e.getMessage(), e );
 637  
             }
 638  0
             getLog().info(
 639  
                            "IOException when parsing Clirr output '" + clirrTextOutputFile.getAbsolutePath()
 640  
                                + "', Clirr is ignored." );
 641  2
         }
 642  2
     }
 643  
 
 644  
     /**
 645  
      * @param clirrTextOutputFile not null
 646  
      * @throws IOException if any
 647  
      */
 648  
     private void parseClirrTextOutputFile( File clirrTextOutputFile )
 649  
         throws IOException
 650  
     {
 651  2
         if ( !clirrTextOutputFile.exists() )
 652  
         {
 653  0
             getLog().info(
 654  
                            "No Clirr output file '" + clirrTextOutputFile.getAbsolutePath()
 655  
                                + "' exists, Clirr is ignored." );
 656  0
             return;
 657  
         }
 658  
 
 659  2
         getLog().info( "Clirr output file was created: " + clirrTextOutputFile.getAbsolutePath() );
 660  
 
 661  2
         clirrNewClasses = new LinkedList();
 662  2
         clirrNewMethods = new LinkedHashMap();
 663  
 
 664  2
         BufferedReader input = new BufferedReader( ReaderFactory.newReader( clirrTextOutputFile, "UTF-8" ) );
 665  2
         String line = null;
 666  18
         while ( ( line = input.readLine() ) != null )
 667  
         {
 668  16
             String[] split = StringUtils.split( line, ":" );
 669  16
             if ( split.length != 4 )
 670  
             {
 671  0
                 getLog().debug( "Unable to parse the clirr line: " + line );
 672  0
                 continue;
 673  
             }
 674  
 
 675  
             int code;
 676  
             try
 677  
             {
 678  16
                 code = Integer.parseInt( split[1].trim() );
 679  
             }
 680  0
             catch ( NumberFormatException e )
 681  
             {
 682  0
                 getLog().debug( "Unable to parse the clirr line: " + line );
 683  0
                 continue;
 684  16
             }
 685  
 
 686  
             // http://clirr.sourceforge.net/clirr-core/exegesis.html
 687  
             // 7011 - Method Added
 688  
             // 7012 - Method Added to Interface
 689  
             // 8000 - Class Added
 690  
             List list;
 691  
             String[] splits2;
 692  16
             switch ( code )
 693  
             {
 694  
                 case 7011:
 695  11
                     list = (List) clirrNewMethods.get( split[2].trim() );
 696  11
                     if ( list == null )
 697  
                     {
 698  4
                         list = new ArrayList();
 699  
                     }
 700  11
                     splits2 = StringUtils.split( split[3].trim(), "'" );
 701  11
                     if ( splits2.length != 3 )
 702  
                     {
 703  0
                         continue;
 704  
                     }
 705  11
                     list.add( splits2[1].trim() );
 706  11
                     clirrNewMethods.put( split[2].trim(), list );
 707  11
                     break;
 708  
 
 709  
                 case 7012:
 710  4
                     list = (List) clirrNewMethods.get( split[2].trim() );
 711  4
                     if ( list == null )
 712  
                     {
 713  4
                         list = new ArrayList();
 714  
                     }
 715  4
                     splits2 = StringUtils.split( split[3].trim(), "'" );
 716  4
                     if ( splits2.length != 3 )
 717  
                     {
 718  0
                         continue;
 719  
                     }
 720  4
                     list.add( splits2[1].trim() );
 721  4
                     clirrNewMethods.put( split[2].trim(), list );
 722  4
                     break;
 723  
 
 724  
                 case 8000:
 725  0
                     clirrNewClasses.add( split[2].trim() );
 726  0
                     break;
 727  
                 default:
 728  
                     break;
 729  
             }
 730  16
         }
 731  
 
 732  2
         if ( clirrNewClasses.isEmpty() && clirrNewMethods.isEmpty() )
 733  
         {
 734  0
             getLog().info( "Clirr NOT found API differences." );
 735  
         }
 736  
         else
 737  
         {
 738  2
             getLog().info( "Clirr found API differences, i.e. new classes/interfaces or methods." );
 739  
         }
 740  2
     }
 741  
 
 742  
     /**
 743  
      * @param tag not null
 744  
      * @return <code>true</code> if <code>tag</code> is defined in {@link #fixTags}.
 745  
      */
 746  
     private boolean fixTag( String tag )
 747  
     {
 748  406
         if ( fixTagsSplitted.length == 1 && fixTagsSplitted[0].equals( FIX_TAGS_ALL ) )
 749  
         {
 750  406
             return true;
 751  
         }
 752  
 
 753  0
         for ( int i = 0; i < fixTagsSplitted.length; i++ )
 754  
         {
 755  0
             if ( fixTagsSplitted[i].trim().equals( tag ) )
 756  
             {
 757  0
                 return true;
 758  
             }
 759  
         }
 760  
 
 761  0
         return false;
 762  
     }
 763  
 
 764  
     /**
 765  
      * Calling Qdox to find {@link JavaClass} objects from the Maven project sources.
 766  
      * Ignore java class if Qdox has parsing errors.
 767  
      *
 768  
      * @return an array of {@link JavaClass} found by QDox
 769  
      * @throws IOException if any
 770  
      * @throws MojoExecutionException if any
 771  
      */
 772  
     private JavaClass[] getQdoxClasses()
 773  
         throws IOException, MojoExecutionException
 774  
     {
 775  2
         if ( "pom".equals( project.getPackaging().toLowerCase() ) )
 776  
         {
 777  0
             getLog().warn( "This project has 'pom' packaging, no Java sources is available." );
 778  0
             return null;
 779  
         }
 780  
 
 781  2
         List javaFiles = new LinkedList();
 782  2
         for ( Iterator i = getProjectSourceRoots( project ).iterator(); i.hasNext(); )
 783  
         {
 784  4
             File f = new File( (String) i.next() );
 785  4
             if ( f.isDirectory() )
 786  
             {
 787  4
                 javaFiles.addAll( FileUtils.getFiles( f, includes, excludes, true ) );
 788  
             }
 789  
             else
 790  
             {
 791  0
                 getLog().warn( f + " doesn't exist. Ignored it." );
 792  
             }
 793  4
         }
 794  
 
 795  2
         JavaDocBuilder builder = new JavaDocBuilder();
 796  2
         builder.getClassLibrary().addClassLoader( getProjectClassLoader() );
 797  2
         builder.setEncoding( encoding );
 798  2
         for ( Iterator i = javaFiles.iterator(); i.hasNext(); )
 799  
         {
 800  9
             File f = (File) i.next();
 801  9
             if ( !f.getAbsolutePath().toLowerCase( Locale.ENGLISH ).endsWith( ".java" )
 802  
                 && getLog().isWarnEnabled() )
 803  
             {
 804  0
                 getLog().warn( "'" + f + "' is not a Java file. Ignored it." );
 805  0
                 continue;
 806  
             }
 807  
 
 808  
             try
 809  
             {
 810  9
                 builder.addSource( f );
 811  
             }
 812  0
             catch ( ParseException e )
 813  
             {
 814  0
                 getLog().warn( "QDOX ParseException: " + e.getMessage() + ". Can't fix it." );
 815  9
             }
 816  9
         }
 817  
 
 818  2
         return builder.getClasses();
 819  
     }
 820  
 
 821  
     /**
 822  
      * @return the classLoader for the given project using lazy instantiation.
 823  
      * @throws MojoExecutionException if any
 824  
      */
 825  
     private ClassLoader getProjectClassLoader()
 826  
         throws MojoExecutionException
 827  
     {
 828  133
         if ( projectClassLoader == null )
 829  
         {
 830  
             List classPath;
 831  
             try
 832  
             {
 833  2
                 classPath = getCompileClasspathElements( project );
 834  
             }
 835  0
             catch ( DependencyResolutionRequiredException e )
 836  
             {
 837  0
                 throw new MojoExecutionException( "DependencyResolutionRequiredException: " + e.getMessage(), e );
 838  2
             }
 839  
 
 840  2
             List urls = new ArrayList( classPath.size() );
 841  2
             Iterator iter = classPath.iterator();
 842  6
             while ( iter.hasNext() )
 843  
             {
 844  
                 try
 845  
                 {
 846  4
                     urls.add( new File( ( (String) iter.next() ) ).toURL() );
 847  
                 }
 848  0
                 catch ( MalformedURLException e )
 849  
                 {
 850  0
                     throw new MojoExecutionException( "MalformedURLException: " + e.getMessage(), e );
 851  4
                 }
 852  
             }
 853  
 
 854  2
             projectClassLoader = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), null );
 855  
         }
 856  
 
 857  133
         return projectClassLoader;
 858  
     }
 859  
 
 860  
     /**
 861  
      * Process the given {@link JavaClass}, ie add missing javadoc tags depending user parameters.
 862  
      *
 863  
      * @param javaClass not null
 864  
      * @throws IOException if any
 865  
      * @throws MojoExecutionException if any
 866  
      */
 867  
     private void processFix( JavaClass javaClass )
 868  
         throws IOException, MojoExecutionException
 869  
     {
 870  
         // Skipping inner classes
 871  12
         if ( javaClass.isInner() )
 872  
         {
 873  3
             return;
 874  
         }
 875  
 
 876  9
         File javaFile = new File( javaClass.getSource().getURL().getFile() );
 877  
         // the original java content in memory
 878  9
         final String originalContent = readFile( javaFile, encoding );
 879  
 
 880  9
         getLog().debug( "Fixing " + javaClass.getFullyQualifiedName() );
 881  
 
 882  9
         final StringWriter stringWriter = new StringWriter();
 883  9
         BufferedReader reader = null;
 884  
         try
 885  
         {
 886  9
             reader = new BufferedReader( new StringReader( originalContent ) );
 887  
 
 888  
             String line;
 889  9
             int lineNumber = 0;
 890  807
             while ( ( line = reader.readLine() ) != null )
 891  
             {
 892  798
                 lineNumber++;
 893  798
                 final String indent = autodetectIndentation( line );
 894  
 
 895  
                 // fixing classes
 896  798
                 if ( javaClass.getComment() == null && javaClass.getAnnotations() != null
 897  
                     && javaClass.getAnnotations().length != 0 )
 898  
                 {
 899  0
                     if ( lineNumber == javaClass.getAnnotations()[0].getLineNumber() )
 900  
                     {
 901  0
                         fixClassComment( stringWriter, originalContent, javaClass, indent );
 902  
 
 903  0
                         takeCareSingleComment( stringWriter, originalContent, javaClass );
 904  
                     }
 905  
                 }
 906  
                 else
 907  
                 {
 908  798
                     if ( lineNumber == javaClass.getLineNumber() )
 909  
                     {
 910  9
                         fixClassComment( stringWriter, originalContent, javaClass, indent );
 911  
 
 912  9
                         takeCareSingleComment( stringWriter, originalContent, javaClass );
 913  
                     }
 914  
                 }
 915  
 
 916  
                 // fixing fields
 917  798
                 if ( javaClass.getFields() != null )
 918  
                 {
 919  1790
                     for ( int i = 0; i < javaClass.getFields().length; i++ )
 920  
                     {
 921  992
                         JavaField field = javaClass.getFields()[i];
 922  
 
 923  992
                         if ( lineNumber == field.getLineNumber() )
 924  
                         {
 925  12
                             fixFieldComment( stringWriter, javaClass, field, indent );
 926  
                         }
 927  
                     }
 928  
                 }
 929  
 
 930  
                 // fixing methods
 931  798
                 if ( javaClass.getMethods() != null )
 932  
                 {
 933  10392
                     for ( int i = 0; i < javaClass.getMethods().length; i++ )
 934  
                     {
 935  9594
                         JavaMethod method = javaClass.getMethods()[i];
 936  
 
 937  9594
                         if ( lineNumber == method.getLineNumber() )
 938  
                         {
 939  61
                             fixMethodComment( stringWriter, originalContent, method, indent );
 940  
 
 941  61
                             takeCareSingleComment( stringWriter, originalContent, method );
 942  
                         }
 943  
                     }
 944  
                 }
 945  
 
 946  798
                 stringWriter.write( line );
 947  798
                 stringWriter.write( EOL );
 948  798
             }
 949  
         }
 950  
         finally
 951  
         {
 952  9
             IOUtil.close( reader );
 953  9
         }
 954  
 
 955  9
         getLog().debug( "Saving " + javaClass.getFullyQualifiedName() );
 956  
 
 957  9
         if ( outputDirectory != null
 958  
             && !outputDirectory.getAbsolutePath().equals( getProjectSourceDirectory().getAbsolutePath() ) )
 959  
         {
 960  9
             String path =
 961  
                 StringUtils.replace( javaFile.getAbsolutePath().replaceAll( "\\\\", "/" ),
 962  
                                      project.getBuild().getSourceDirectory().replaceAll( "\\\\", "/" ), "" );
 963  9
             javaFile = new File( outputDirectory, path );
 964  9
             javaFile.getParentFile().mkdirs();
 965  
         }
 966  9
         writeFile( javaFile, encoding, stringWriter.toString() );
 967  9
     }
 968  
 
 969  
     /**
 970  
      * Take care of block or single comments between Javadoc comment and entity declaration ie:
 971  
      * <br/>
 972  
      * <code>
 973  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;</font>
 974  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 975  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 976  
      * <font color="#3f5fbf">&#42;&nbsp;{Javadoc&nbsp;Comment}</font><br />
 977  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 978  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 979  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;</font>
 980  
      * <font color="#3f7f5f">&#47;&#42;</font><br />
 981  
      * <font color="#808080">5</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 982  
      * <font color="#3f7f5f">&#42;&nbsp;{Block&nbsp;Comment}</font><br />
 983  
      * <font color="#808080">6</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 984  
      * <font color="#3f7f5f">&#42;&#47;</font><br />
 985  
      * <font color="#808080">7</font>&nbsp;<font color="#ffffff">&nbsp;</font>
 986  
      * <font color="#3f7f5f">&#47;&#47;&nbsp;{Single&nbsp;comment}</font><br />
 987  
      * <font color="#808080">8</font>&nbsp;<font color="#ffffff">&nbsp;</font>
 988  
      * <font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font>
 989  
      * <font color="#000000">dummyMethod</font><font color="#000000">(&nbsp;</font>
 990  
      * <font color="#000000">String&nbsp;s&nbsp;</font><font color="#000000">){}</font>
 991  
      * </code>
 992  
      *
 993  
      * @param stringWriter not null
 994  
      * @param originalContent not null
 995  
      * @param entity not null
 996  
      * @throws IOException if any
 997  
      * @see #extractOriginalJavadoc(String, AbstractJavaEntity)
 998  
      */
 999  
     private void takeCareSingleComment( final StringWriter stringWriter, final String originalContent,
 1000  
                                         final AbstractInheritableJavaEntity entity )
 1001  
         throws IOException
 1002  
     {
 1003  70
         if ( entity.getComment() == null )
 1004  
         {
 1005  26
             return;
 1006  
         }
 1007  
 
 1008  44
         String javadocComment = trimRight( extractOriginalJavadoc( originalContent, entity ) );
 1009  44
         String extraComment =
 1010  
             javadocComment.substring( javadocComment.indexOf( END_JAVADOC ) + END_JAVADOC.length() );
 1011  44
         if ( StringUtils.isNotEmpty( extraComment ) )
 1012  
         {
 1013  2
             if ( extraComment.indexOf( EOL ) != -1 )
 1014  
             {
 1015  2
                 stringWriter.write( extraComment.substring( extraComment.indexOf( EOL ) + EOL.length() ) );
 1016  
             }
 1017  
             else
 1018  
             {
 1019  0
                 stringWriter.write( extraComment );
 1020  
             }
 1021  2
             stringWriter.write( EOL );
 1022  
         }
 1023  44
     }
 1024  
 
 1025  
     /**
 1026  
      * Add/update Javadoc class comment.
 1027  
      *
 1028  
      * @param stringWriter
 1029  
      * @param originalContent
 1030  
      * @param javaClass
 1031  
      * @param indent
 1032  
      * @throws MojoExecutionException
 1033  
      * @throws IOException
 1034  
      */
 1035  
     private void fixClassComment( final StringWriter stringWriter, final String originalContent,
 1036  
                                   final JavaClass javaClass, final String indent )
 1037  
         throws MojoExecutionException, IOException
 1038  
     {
 1039  9
         if ( !fixClassComment )
 1040  
         {
 1041  0
             return;
 1042  
         }
 1043  
 
 1044  9
         if ( !isInLevel( javaClass.getModifiers() ) )
 1045  
         {
 1046  0
             return;
 1047  
         }
 1048  
 
 1049  
         // add
 1050  9
         if ( javaClass.getComment() == null )
 1051  
         {
 1052  4
             addDefaultClassComment( stringWriter, javaClass, indent );
 1053  4
             return;
 1054  
         }
 1055  
 
 1056  
         // update
 1057  5
         updateEntityComment( stringWriter, originalContent, javaClass, indent );
 1058  5
     }
 1059  
 
 1060  
     /**
 1061  
      * @param modifiers list of modifiers (public, private, protected, package)
 1062  
      * @return <code>true</code> if modifier is align with <code>level</code>.
 1063  
      */
 1064  
     private boolean isInLevel( String[] modifiers )
 1065  
     {
 1066  64
         List modifiersAsList = Arrays.asList( modifiers );
 1067  
 
 1068  64
         if ( LEVEL_PUBLIC.equalsIgnoreCase( level.trim() ) )
 1069  
         {
 1070  0
             if ( modifiersAsList.contains( LEVEL_PUBLIC ) )
 1071  
             {
 1072  0
                 return true;
 1073  
             }
 1074  
 
 1075  0
             return false;
 1076  
         }
 1077  
 
 1078  64
         if ( LEVEL_PROTECTED.equalsIgnoreCase( level.trim() ) )
 1079  
         {
 1080  64
             if ( modifiersAsList.contains( LEVEL_PUBLIC ) || modifiersAsList.contains( LEVEL_PROTECTED ) )
 1081  
             {
 1082  62
                 return true;
 1083  
             }
 1084  
 
 1085  2
             return false;
 1086  
         }
 1087  
 
 1088  0
         if ( LEVEL_PACKAGE.equalsIgnoreCase( level.trim() ) )
 1089  
         {
 1090  0
             if ( !modifiersAsList.contains( LEVEL_PRIVATE ) )
 1091  
             {
 1092  0
                 return true;
 1093  
             }
 1094  
 
 1095  0
             return false;
 1096  
         }
 1097  
 
 1098  
         // should be private (shows all classes and members)
 1099  0
         return true;
 1100  
     }
 1101  
 
 1102  
     /**
 1103  
      * Add a default Javadoc for the given class, i.e.:
 1104  
      * <br/>
 1105  
      * <code>
 1106  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;</font>
 1107  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 1108  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1109  
      * <font color="#3f5fbf">&#42;&nbsp;{Comment&nbsp;based&nbsp;on&nbsp;the&nbsp;class&nbsp;name}</font><br />
 1110  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1111  
      * <font color="#3f5fbf">&#42;</font><br />
 1112  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1113  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@author&nbsp;</font>
 1114  
      * <font color="#3f5fbf">X&nbsp;{added&nbsp;if&nbsp;addMissingAuthor}</font><br />
 1115  
      * <font color="#808080">5</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1116  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@version&nbsp;</font>
 1117  
      * <font color="#3f5fbf">X&nbsp;{added&nbsp;if&nbsp;addMissingVersion}</font><br />
 1118  
      * <font color="#808080">6</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1119  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@since&nbsp;</font>
 1120  
      * <font color="#3f5fbf">X&nbsp;{added&nbsp;if&nbsp;addMissingSince&nbsp;and&nbsp;new&nbsp;classes
 1121  
      * from&nbsp;previous&nbsp;version}</font><br />
 1122  
      * <font color="#808080">7</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1123  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 1124  
      * <font color="#808080">8</font>&nbsp;<font color="#7f0055"><b>public&nbsp;class&nbsp;</b></font>
 1125  
      * <font color="#000000">DummyClass&nbsp;</font><font color="#000000">{}</font></code>
 1126  
      * </code>
 1127  
      *
 1128  
      * @param buffer not null
 1129  
      * @param javaClass not null
 1130  
      * @param indent not null
 1131  
      * @see #getDefaultClassJavadocComment(JavaClass)
 1132  
      * @see #appendDefaultAuthorTag(StringBuffer, String)
 1133  
      * @see #appendDefaultSinceTag(StringBuffer, String)
 1134  
      * @see #appendDefaultVersionTag(StringBuffer, String)
 1135  
      */
 1136  
     private void addDefaultClassComment( final StringWriter stringWriter, final JavaClass javaClass,
 1137  
                                          final String indent )
 1138  
     {
 1139  4
         StringBuffer sb = new StringBuffer();
 1140  
 
 1141  4
         sb.append( indent ).append( START_JAVADOC );
 1142  4
         sb.append( EOL );
 1143  4
         sb.append( indent ).append( SEPARATOR_JAVADOC );
 1144  4
         sb.append( getDefaultClassJavadocComment( javaClass ) );
 1145  4
         sb.append( EOL );
 1146  
 
 1147  4
         appendSeparator( sb, indent );
 1148  
 
 1149  4
         appendDefaultAuthorTag( sb, indent );
 1150  
 
 1151  4
         appendDefaultVersionTag( sb, indent );
 1152  
 
 1153  4
         if ( fixTag( SINCE_TAG ) )
 1154  
         {
 1155  4
             if ( !ignoreClirr )
 1156  
             {
 1157  4
                 if ( isNewClassFromLastVersion( javaClass ) )
 1158  
                 {
 1159  0
                     appendDefaultSinceTag( sb, indent );
 1160  
                 }
 1161  
             }
 1162  
             else
 1163  
             {
 1164  0
                 appendDefaultSinceTag( sb, indent );
 1165  0
                 addSinceClasses( javaClass );
 1166  
             }
 1167  
         }
 1168  
 
 1169  4
         sb.append( indent ).append( " " ).append( END_JAVADOC );
 1170  4
         sb.append( EOL );
 1171  
 
 1172  4
         stringWriter.write( sb.toString() );
 1173  4
     }
 1174  
 
 1175  
     /**
 1176  
      * Add Javadoc field comment, only for static fields or interface fields.
 1177  
      *
 1178  
      * @param stringWriter not null
 1179  
      * @param javaClass not null
 1180  
      * @param field not null
 1181  
      * @param indent not null
 1182  
      * @throws IOException if any
 1183  
      */
 1184  
     private void fixFieldComment( final StringWriter stringWriter, final JavaClass javaClass,
 1185  
                                   final JavaField field, final String indent )
 1186  
         throws IOException
 1187  
     {
 1188  12
         if ( !fixFieldComment )
 1189  
         {
 1190  0
             return;
 1191  
         }
 1192  
 
 1193  12
         if ( !javaClass.isInterface() )
 1194  
         {
 1195  7
             if ( !isInLevel( field.getModifiers() ) )
 1196  
             {
 1197  1
                 return;
 1198  
             }
 1199  
 
 1200  6
             if ( !field.isStatic() )
 1201  
             {
 1202  0
                 return;
 1203  
             }
 1204  
         }
 1205  
 
 1206  
         // add
 1207  11
         if ( field.getComment() == null )
 1208  
         {
 1209  9
             addDefaultFieldComment( stringWriter, field, indent );
 1210  9
             return;
 1211  
         }
 1212  
 
 1213  
         // no update
 1214  2
     }
 1215  
 
 1216  
     /**
 1217  
      * Add a default Javadoc for the given field, i.e.:
 1218  
      * <br/>
 1219  
      * <code>
 1220  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 1221  
      * <font color="#3f5fbf">&#47;&#42;&#42;&nbsp;Constant&nbsp;</font><font color="#7f7f9f">&lt;code&gt;</font>
 1222  
      * <font color="#3f5fbf">MY_STRING_CONSTANT=&#34;value&#34;</font>
 1223  
      * <font color="#7f7f9f">&lt;/code&gt;&nbsp;</font><font color="#3f5fbf">&#42;&#47;</font><br />
 1224  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 1225  
      * <font color="#7f0055"><b>public&nbsp;static&nbsp;final&nbsp;</b></font>
 1226  
      * <font color="#000000">String&nbsp;MY_STRING_CONSTANT&nbsp;=&nbsp;</font>
 1227  
      * <font color="#2a00ff">&#34;value&#34;</font><font color="#000000">;</font>
 1228  
      * </code>
 1229  
      *
 1230  
      * @param stringWriter not null
 1231  
      * @param field not null
 1232  
      * @param indent not null
 1233  
      * @throws IOException if any
 1234  
      */
 1235  
     private void addDefaultFieldComment( final StringWriter stringWriter, final JavaField field,
 1236  
                                          final String indent )
 1237  
         throws IOException
 1238  
     {
 1239  9
         StringBuffer sb = new StringBuffer();
 1240  
 
 1241  9
         sb.append( indent ).append( START_JAVADOC ).append( " " );
 1242  9
         sb.append( "Constant <code>" ).append( field.getName() );
 1243  
 
 1244  9
         if ( StringUtils.isNotEmpty( field.getInitializationExpression() ) )
 1245  
         {
 1246  9
             String qualifiedName = field.getType().getJavaClass().getFullyQualifiedName();
 1247  
 
 1248  9
             if ( qualifiedName.equals( Byte.TYPE.toString() ) || qualifiedName.equals( Short.TYPE.toString() )
 1249  
                 || qualifiedName.equals( Integer.TYPE.toString() ) || qualifiedName.equals( Long.TYPE.toString() )
 1250  
                 || qualifiedName.equals( Float.TYPE.toString() ) || qualifiedName.equals( Double.TYPE.toString() )
 1251  
                 || qualifiedName.equals( Boolean.TYPE.toString() )
 1252  
                 || qualifiedName.equals( Character.TYPE.toString() ) )
 1253  
             {
 1254  2
                 sb.append( "=" );
 1255  2
                 sb.append( field.getInitializationExpression().trim() );
 1256  
             }
 1257  
 
 1258  13
             if ( qualifiedName.equals( String.class.getName() ) )
 1259  
             {
 1260  5
                 StringBuffer value = new StringBuffer();
 1261  5
                 String[] lines = getLines( field.getInitializationExpression() );
 1262  10
                 for ( int i = 0; i < lines.length; i++ )
 1263  
                 {
 1264  5
                     String line = lines[i];
 1265  
 
 1266  5
                     StringTokenizer token = new StringTokenizer( line.trim(), "\"\n\r" );
 1267  14
                     while ( token.hasMoreTokens() )
 1268  
                     {
 1269  9
                         String s = token.nextToken();
 1270  
 
 1271  9
                         if ( s.trim().equals( "+" ) )
 1272  
                         {
 1273  1
                             continue;
 1274  
                         }
 1275  8
                         if ( s.trim().endsWith( "\\" ) )
 1276  
                         {
 1277  0
                             s += "\"";
 1278  
                         }
 1279  8
                         value.append( s );
 1280  8
                     }
 1281  
                 }
 1282  
 
 1283  5
                 sb.append( "=\"" );
 1284  
                 // reduce the size
 1285  5
                 if ( value.length() < 40 )
 1286  
                 {
 1287  5
                     sb.append( value.toString() ).append( "\"" );
 1288  
                 }
 1289  
                 else
 1290  
                 {
 1291  0
                     sb.append( value.toString().substring( 0, 39 ) ).append( "\"{trunked}" );
 1292  
                 }
 1293  
             }
 1294  
         }
 1295  
 
 1296  9
         sb.append( "</code> " ).append( END_JAVADOC );
 1297  9
         sb.append( EOL );
 1298  
 
 1299  9
         stringWriter.write( sb.toString() );
 1300  9
     }
 1301  
 
 1302  
     /**
 1303  
      * Add/update Javadoc method comment.
 1304  
      *
 1305  
      * @param stringWriter not null
 1306  
      * @param originalContent not null
 1307  
      * @param javaMethod not null
 1308  
      * @param indent not null
 1309  
      * @throws MojoExecutionException if any
 1310  
      * @throws IOException if any
 1311  
      */
 1312  
     private void fixMethodComment( final StringWriter stringWriter, final String originalContent,
 1313  
                                    final JavaMethod javaMethod, final String indent )
 1314  
         throws MojoExecutionException, IOException
 1315  
     {
 1316  61
         if ( !fixMethodComment )
 1317  
         {
 1318  0
             return;
 1319  
         }
 1320  
 
 1321  61
         if ( !javaMethod.getParentClass().isInterface() && !isInLevel( javaMethod.getModifiers() ) )
 1322  
         {
 1323  1
             return;
 1324  
         }
 1325  
 
 1326  
         // add
 1327  60
         if ( javaMethod.getComment() == null )
 1328  
         {
 1329  21
             addDefaultMethodComment( stringWriter, javaMethod, indent );
 1330  21
             return;
 1331  
         }
 1332  
 
 1333  
         // update
 1334  39
         updateEntityComment( stringWriter, originalContent, javaMethod, indent );
 1335  39
     }
 1336  
 
 1337  
     /**
 1338  
      * Add in the buffer a default Javadoc for the given class:
 1339  
      * <br/>
 1340  
      * <code>
 1341  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;</font>
 1342  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 1343  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1344  
      * <font color="#3f5fbf">&#42;&nbsp;{Comment&nbsp;based&nbsp;on&nbsp;the&nbsp;method&nbsp;name}</font><br />
 1345  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1346  
      * <font color="#3f5fbf">&#42;</font><br />
 1347  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1348  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 1349  
      * <font color="#3f5fbf">X&nbsp;{added&nbsp;if&nbsp;addMissingParam}</font><br />
 1350  
      * <font color="#808080">5</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1351  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@return&nbsp;</font>
 1352  
      * <font color="#3f5fbf">X&nbsp;{added&nbsp;if&nbsp;addMissingReturn}</font><br />
 1353  
      * <font color="#808080">6</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1354  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@throws&nbsp;</font>
 1355  
      * <font color="#3f5fbf">X&nbsp;{added&nbsp;if&nbsp;addMissingThrows}</font><br />
 1356  
      * <font color="#808080">7</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1357  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@since&nbsp;</font>
 1358  
      * <font color="#3f5fbf">X&nbsp;{added&nbsp;if&nbsp;addMissingSince&nbsp;and&nbsp;new&nbsp;classes
 1359  
      * from&nbsp;previous&nbsp;version}</font><br />
 1360  
      * <font color="#808080">8</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;</font>
 1361  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 1362  
      * <font color="#808080">9</font>&nbsp;<font color="#7f0055"><b>public&nbsp;</b></font>
 1363  
      * <font color="#7f0055"><b>void&nbsp;</b></font><font color="#000000">dummyMethod</font>
 1364  
      * <font color="#000000">(&nbsp;</font><font color="#000000">String&nbsp;s&nbsp;</font>
 1365  
      * <font color="#000000">){}</font>
 1366  
      * </code>
 1367  
      *
 1368  
      * @param buffer not null
 1369  
      * @param javaMethod not null
 1370  
      * @param indent not null
 1371  
      * @throws MojoExecutionException if any
 1372  
      * @see #getDefaultMethodJavadocComment(JavaMethod)
 1373  
      * @see #appendDefaultSinceTag(StringBuffer, String)
 1374  
      */
 1375  
     private void addDefaultMethodComment( final StringWriter stringWriter, final JavaMethod javaMethod,
 1376  
                                           final String indent )
 1377  
         throws MojoExecutionException
 1378  
     {
 1379  21
         StringBuffer sb = new StringBuffer();
 1380  
 
 1381  
         // special case
 1382  21
         if ( isInherited( javaMethod ) )
 1383  
         {
 1384  6
             sb.append( indent ).append( INHERITED_JAVADOC );
 1385  6
             sb.append( EOL );
 1386  
 
 1387  6
             stringWriter.write( sb.toString() );
 1388  6
             return;
 1389  
         }
 1390  
 
 1391  15
         sb.append( indent ).append( START_JAVADOC );
 1392  15
         sb.append( EOL );
 1393  15
         sb.append( indent ).append( SEPARATOR_JAVADOC );
 1394  15
         sb.append( getDefaultMethodJavadocComment( javaMethod ) );
 1395  15
         sb.append( EOL );
 1396  
 
 1397  15
         boolean separatorAdded = false;
 1398  15
         if ( fixTag( PARAM_TAG ) )
 1399  
         {
 1400  15
             if ( javaMethod.getParameters() != null )
 1401  
             {
 1402  39
                 for ( int i = 0; i < javaMethod.getParameters().length; i++ )
 1403  
                 {
 1404  24
                     JavaParameter javaParameter = javaMethod.getParameters()[i];
 1405  
 
 1406  24
                     separatorAdded = appendDefaultParamTag( sb, indent, separatorAdded, javaParameter );
 1407  
                 }
 1408  
             }
 1409  
             // is generic?
 1410  15
             if ( javaMethod.getTypeParameters() != null )
 1411  
             {
 1412  22
                 for ( int i = 0; i < javaMethod.getTypeParameters().length; i++ )
 1413  
                 {
 1414  7
                     TypeVariable typeParam = javaMethod.getTypeParameters()[i];
 1415  
 
 1416  7
                     separatorAdded = appendDefaultParamTag( sb, indent, separatorAdded, typeParam );
 1417  
                 }
 1418  
             }
 1419  
         }
 1420  15
         if ( fixTag( RETURN_TAG ) && javaMethod.getReturns() != null && !javaMethod.getReturns().isVoid() )
 1421  
         {
 1422  6
             separatorAdded = appendDefaultReturnTag( sb, indent, separatorAdded, javaMethod );
 1423  
         }
 1424  15
         if ( fixTag( THROWS_TAG ) && javaMethod.getExceptions() != null && javaMethod.getExceptions().length > 0 )
 1425  
         {
 1426  2
             for ( int i = 0; i < javaMethod.getExceptions().length; i++ )
 1427  
             {
 1428  1
                 Type exception = javaMethod.getExceptions()[i];
 1429  
 
 1430  1
                 separatorAdded = appendDefaultThrowsTag( sb, indent, separatorAdded, exception );
 1431  
             }
 1432  
         }
 1433  15
         if ( fixTag( SINCE_TAG ) && isNewMethodFromLastRevision( javaMethod ) )
 1434  
         {
 1435  5
             separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
 1436  
         }
 1437  
 
 1438  15
         sb.append( indent ).append( " " ).append( END_JAVADOC );
 1439  15
         sb.append( EOL );
 1440  
 
 1441  15
         stringWriter.write( sb.toString() );
 1442  15
     }
 1443  
 
 1444  
     /**
 1445  
      * @param stringWriter not null
 1446  
      * @param originalContent not null
 1447  
      * @param entity not null
 1448  
      * @param indent not null
 1449  
      * @throws MojoExecutionException if any
 1450  
      * @throws IOException if any
 1451  
      */
 1452  
     private void updateEntityComment( final StringWriter stringWriter, final String originalContent,
 1453  
                                       final AbstractInheritableJavaEntity entity, final String indent )
 1454  
         throws MojoExecutionException, IOException
 1455  
     {
 1456  44
         String s = stringWriter.toString();
 1457  44
         int i = s.lastIndexOf( START_JAVADOC );
 1458  44
         if ( i != -1 )
 1459  
         {
 1460  44
             String tmp = s.substring( 0, i );
 1461  44
             if ( tmp.lastIndexOf( EOL ) != -1 )
 1462  
             {
 1463  44
                 tmp = tmp.substring( 0, tmp.lastIndexOf( EOL ) );
 1464  
             }
 1465  44
             stringWriter.getBuffer().delete( 0, stringWriter.getBuffer().length() );
 1466  44
             stringWriter.write( tmp );
 1467  44
             stringWriter.write( EOL );
 1468  
         }
 1469  
 
 1470  44
         updateJavadocComment( stringWriter, originalContent, entity, indent );
 1471  44
     }
 1472  
 
 1473  
     /**
 1474  
      * @param stringWriter not null
 1475  
      * @param originalContent not null
 1476  
      * @param entity not null
 1477  
      * @param indent not null
 1478  
      * @throws MojoExecutionException if any
 1479  
      * @throws IOException if any
 1480  
      */
 1481  
     private void updateJavadocComment( final StringWriter stringWriter, final String originalContent,
 1482  
                                        final AbstractInheritableJavaEntity entity, final String indent )
 1483  
         throws MojoExecutionException, IOException
 1484  
     {
 1485  44
         if ( entity.getComment() == null && ( entity.getTags() == null || entity.getTags().length == 0 ) )
 1486  
         {
 1487  0
             return;
 1488  
         }
 1489  
 
 1490  44
         boolean isJavaMethod = false;
 1491  44
         if ( entity instanceof JavaMethod )
 1492  
         {
 1493  39
             isJavaMethod = true;
 1494  
         }
 1495  
 
 1496  44
         StringBuffer sb = new StringBuffer();
 1497  
 
 1498  
         // special case for inherited method
 1499  44
         if ( isJavaMethod )
 1500  
         {
 1501  39
             JavaMethod javaMethod = (JavaMethod) entity;
 1502  
 
 1503  39
             if ( isInherited( javaMethod ) )
 1504  
             {
 1505  
                 // QDOX-154 could be empty
 1506  8
                 if ( StringUtils.isEmpty( javaMethod.getComment() ) )
 1507  
                 {
 1508  1
                     sb.append( indent ).append( INHERITED_JAVADOC );
 1509  1
                     sb.append( EOL );
 1510  1
                     stringWriter.write( sb.toString() );
 1511  1
                     return;
 1512  
                 }
 1513  
 
 1514  7
                 String javadoc = getJavadocComment( originalContent, javaMethod );
 1515  
 
 1516  
                 // case: /** {@inheritDoc} */ or no tags
 1517  7
                 if ( hasInheritedTag( javadoc )
 1518  
                     && ( javaMethod.getTags() == null || javaMethod.getTags().length == 0 ) )
 1519  
                 {
 1520  3
                     sb.append( indent ).append( INHERITED_JAVADOC );
 1521  3
                     sb.append( EOL );
 1522  3
                     stringWriter.write( sb.toString() );
 1523  3
                     return;
 1524  
                 }
 1525  
 
 1526  4
                 if ( javadoc.indexOf( START_JAVADOC ) != -1 )
 1527  
                 {
 1528  0
                     javadoc = javadoc.substring( javadoc.indexOf( START_JAVADOC ) + START_JAVADOC.length() );
 1529  
                 }
 1530  4
                 if ( javadoc.indexOf( END_JAVADOC ) != -1 )
 1531  
                 {
 1532  0
                     javadoc = javadoc.substring( 0, javadoc.indexOf( END_JAVADOC ) );
 1533  
                 }
 1534  
 
 1535  4
                 sb.append( indent ).append( START_JAVADOC );
 1536  4
                 sb.append( EOL );
 1537  4
                 if ( javadoc.indexOf( INHERITED_TAG ) == -1 )
 1538  
                 {
 1539  2
                     sb.append( indent ).append( SEPARATOR_JAVADOC ).append( INHERITED_TAG );
 1540  2
                     sb.append( EOL );
 1541  2
                     appendSeparator( sb, indent );
 1542  
                 }
 1543  4
                 javadoc = removeLastEmptyJavadocLines( javadoc );
 1544  4
                 javadoc = alignIndentationJavadocLines( javadoc, indent );
 1545  4
                 sb.append( javadoc );
 1546  4
                 sb.append( EOL );
 1547  4
                 if ( javaMethod.getTags() != null )
 1548  
                 {
 1549  6
                     for ( int i = 0; i < javaMethod.getTags().length; i++ )
 1550  
                     {
 1551  2
                         DocletTag docletTag = javaMethod.getTags()[i];
 1552  
 
 1553  
                         // Voluntary ignore these tags
 1554  2
                         if ( docletTag.getName().equals( PARAM_TAG )
 1555  
                             || docletTag.getName().equals( RETURN_TAG )
 1556  
                             || docletTag.getName().equals( THROWS_TAG ) )
 1557  
                         {
 1558  0
                             continue;
 1559  
                         }
 1560  
 
 1561  0
                         String s = getJavadocComment( originalContent, entity, docletTag );
 1562  0
                         s = removeLastEmptyJavadocLines( s );
 1563  0
                         s = alignIndentationJavadocLines( s, indent );
 1564  0
                         sb.append( s );
 1565  0
                         sb.append( EOL );
 1566  
                     }
 1567  
                 }
 1568  4
                 sb.append( indent ).append( " " ).append( END_JAVADOC );
 1569  4
                 sb.append( EOL );
 1570  
 
 1571  4
                 if ( hasInheritedTag( sb.toString().trim() ) )
 1572  
                 {
 1573  1
                     sb = new StringBuffer();
 1574  1
                     sb.append( indent ).append( INHERITED_JAVADOC );
 1575  1
                     sb.append( EOL );
 1576  1
                     stringWriter.write( sb.toString() );
 1577  1
                     return;
 1578  
                 }
 1579  
 
 1580  3
                 stringWriter.write( sb.toString() );
 1581  3
                 return;
 1582  
             }
 1583  
         }
 1584  
 
 1585  36
         sb.append( indent ).append( START_JAVADOC );
 1586  36
         sb.append( EOL );
 1587  
 
 1588  
         // comment
 1589  36
         if ( StringUtils.isNotEmpty( entity.getComment() ) )
 1590  
         {
 1591  31
             updateJavadocComment( sb, originalContent, entity, indent );
 1592  
         }
 1593  
         else
 1594  
         {
 1595  5
             addDefaultJavadocComment( sb, entity, indent, isJavaMethod );
 1596  
         }
 1597  
 
 1598  
         // tags
 1599  36
         if ( entity.getTags() != null && entity.getTags().length > 0 )
 1600  
         {
 1601  17
             updateJavadocTags( sb, originalContent, entity, indent, isJavaMethod );
 1602  
         }
 1603  
         else
 1604  
         {
 1605  19
             addDefaultJavadocTags( sb, entity, indent, isJavaMethod );
 1606  
         }
 1607  
 
 1608  36
         sb = new StringBuffer( removeLastEmptyJavadocLines( sb.toString() ) ).append( EOL );
 1609  
 
 1610  36
         sb.append( indent ).append( " " ).append( END_JAVADOC );
 1611  36
         sb.append( EOL );
 1612  
 
 1613  36
         stringWriter.write( sb.toString() );
 1614  36
     }
 1615  
 
 1616  
     /**
 1617  
      * @param sb not null
 1618  
      * @param originalContent not null
 1619  
      * @param entity not null
 1620  
      * @param indent not null
 1621  
      * @throws IOException if any
 1622  
      */
 1623  
     private void updateJavadocComment( final StringBuffer sb, final String originalContent,
 1624  
                                        final AbstractInheritableJavaEntity entity, final String indent )
 1625  
         throws IOException
 1626  
     {
 1627  31
         String comment = getJavadocComment( originalContent, entity );
 1628  31
         comment = removeLastEmptyJavadocLines( comment );
 1629  31
         comment = alignIndentationJavadocLines( comment, indent );
 1630  
 
 1631  31
         if ( comment.indexOf( START_JAVADOC ) != -1 )
 1632  
         {
 1633  0
             comment = comment.substring( comment.indexOf( START_JAVADOC ) + START_JAVADOC.length() );
 1634  0
             comment = indent + SEPARATOR_JAVADOC + comment.trim();
 1635  
         }
 1636  31
         if ( comment.indexOf( END_JAVADOC ) != -1 )
 1637  
         {
 1638  0
             comment = comment.substring( 0, comment.indexOf( END_JAVADOC ) );
 1639  
         }
 1640  
 
 1641  31
         String[] lines = getLines( comment );
 1642  62
         for ( int i = 0; i < lines.length; i++ )
 1643  
         {
 1644  31
             sb.append( indent ).append( " " ).append( lines[i].trim() );
 1645  31
             sb.append( EOL );
 1646  
         }
 1647  31
     }
 1648  
 
 1649  
     /**
 1650  
      * @param sb not null
 1651  
      * @param entity not null
 1652  
      * @param indent not null
 1653  
      * @param isJavaMethod
 1654  
      */
 1655  
     private void addDefaultJavadocComment( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
 1656  
                                            final String indent, final boolean isJavaMethod )
 1657  
     {
 1658  5
         sb.append( indent ).append( SEPARATOR_JAVADOC );
 1659  5
         if ( isJavaMethod )
 1660  
         {
 1661  5
             sb.append( getDefaultMethodJavadocComment( (JavaMethod) entity ) );
 1662  
         }
 1663  
         else
 1664  
         {
 1665  0
             sb.append( getDefaultClassJavadocComment( (JavaClass) entity ) );
 1666  
         }
 1667  5
         sb.append( EOL );
 1668  5
     }
 1669  
 
 1670  
     /**
 1671  
      * @param sb not null
 1672  
      * @param originalContent not null
 1673  
      * @param entity not null
 1674  
      * @param indent not null
 1675  
      * @param isJavaMethod
 1676  
      * @throws IOException if any
 1677  
      * @throws MojoExecutionException if any
 1678  
      */
 1679  
     private void updateJavadocTags( final StringBuffer sb, final String originalContent,
 1680  
                                     final AbstractInheritableJavaEntity entity, final String indent,
 1681  
                                     final boolean isJavaMethod )
 1682  
         throws IOException, MojoExecutionException
 1683  
     {
 1684  17
         appendSeparator( sb, indent );
 1685  
 
 1686  
         // parse tags
 1687  17
         JavaEntityTags javaEntityTags = parseJavadocTags( originalContent, entity, indent, isJavaMethod );
 1688  
 
 1689  
         // update and write tags
 1690  17
         updateJavadocTags( sb, entity, isJavaMethod, javaEntityTags );
 1691  
 
 1692  
         // add missing tags...
 1693  17
         addMissingJavadocTags( sb, entity, indent, isJavaMethod, javaEntityTags );
 1694  17
     }
 1695  
 
 1696  
     /**
 1697  
      * Parse entity tags
 1698  
      *
 1699  
      * @param originalContent not null
 1700  
      * @param entity not null
 1701  
      * @param indent not null
 1702  
      * @param isJavaMethod
 1703  
      * @return an instance of {@link JavaEntityTags}
 1704  
      * @throws IOException if any
 1705  
      */
 1706  
     private JavaEntityTags parseJavadocTags( final String originalContent,
 1707  
                                              final AbstractInheritableJavaEntity entity, final String indent,
 1708  
                                              final boolean isJavaMethod )
 1709  
         throws IOException
 1710  
     {
 1711  17
         JavaEntityTags javaEntityTags = new JavaEntityTags( entity, isJavaMethod );
 1712  49
         for ( int i = 0; i < entity.getTags().length; i++ )
 1713  
         {
 1714  32
             DocletTag docletTag = entity.getTags()[i];
 1715  
 
 1716  32
             String originalJavadocTag = getJavadocComment( originalContent, entity, docletTag );
 1717  32
             originalJavadocTag = removeLastEmptyJavadocLines( originalJavadocTag );
 1718  32
             originalJavadocTag = alignIndentationJavadocLines( originalJavadocTag, indent );
 1719  
 
 1720  32
             javaEntityTags.getNamesTags().add( docletTag.getName() );
 1721  
 
 1722  32
             if ( isJavaMethod )
 1723  
             {
 1724  32
                 String[] params = docletTag.getParameters();
 1725  32
                 if ( params.length < 1 )
 1726  
                 {
 1727  1
                     continue;
 1728  
                 }
 1729  
 
 1730  31
                 params = fixQdox173( params );
 1731  31
                 String paramName = params[0];
 1732  31
                 if ( docletTag.getName().equals( PARAM_TAG ) )
 1733  
                 {
 1734  18
                     javaEntityTags.putJavadocParamTag( paramName, originalJavadocTag );
 1735  
                 }
 1736  13
                 else if ( docletTag.getName().equals( RETURN_TAG ) )
 1737  
                 {
 1738  8
                     javaEntityTags.setJavadocReturnTag( originalJavadocTag );
 1739  
                 }
 1740  5
                 else if ( docletTag.getName().equals( THROWS_TAG ) )
 1741  
                 {
 1742  5
                     javaEntityTags.putJavadocThrowsTag( paramName, originalJavadocTag );
 1743  
                 }
 1744  
                 else
 1745  
                 {
 1746  0
                     javaEntityTags.getUnknownTags().add( originalJavadocTag );
 1747  
                 }
 1748  31
             }
 1749  
             else
 1750  
             {
 1751  0
                 javaEntityTags.getUnknownTags().add( originalJavadocTag );
 1752  
             }
 1753  
         }
 1754  
 
 1755  17
         return javaEntityTags;
 1756  
     }
 1757  
 
 1758  
     /**
 1759  
      * Write tags according javaEntityTags.
 1760  
      *
 1761  
      * @param sb not null
 1762  
      * @param entity not null
 1763  
      * @param isJavaMethod
 1764  
      * @param javaEntityTags not null
 1765  
      */
 1766  
     private void updateJavadocTags( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
 1767  
                                     final boolean isJavaMethod, final JavaEntityTags javaEntityTags )
 1768  
     {
 1769  49
         for ( int i = 0; i < entity.getTags().length; i++ )
 1770  
         {
 1771  32
             DocletTag docletTag = entity.getTags()[i];
 1772  
 
 1773  32
             if ( isJavaMethod )
 1774  
             {
 1775  32
                 JavaMethod javaMethod = (JavaMethod) entity;
 1776  
 
 1777  32
                 String[] params = docletTag.getParameters();
 1778  32
                 if ( params.length < 1 )
 1779  
                 {
 1780  1
                     continue;
 1781  
                 }
 1782  
 
 1783  31
                 if ( docletTag.getName().equals( PARAM_TAG ) )
 1784  
                 {
 1785  18
                     writeParamTag( sb, javaMethod, javaEntityTags, params );
 1786  
                 }
 1787  13
                 else if ( docletTag.getName().equals( RETURN_TAG ) )
 1788  
                 {
 1789  8
                     writeReturnTag( sb, javaMethod, javaEntityTags );
 1790  
                 }
 1791  5
                 else if ( docletTag.getName().equals( THROWS_TAG ) )
 1792  
                 {
 1793  5
                     writeThrowsTag( sb, javaMethod, javaEntityTags, params );
 1794  
                 }
 1795  
                 else
 1796  
                 {
 1797  
                     // write unknown tags
 1798  0
                     for ( Iterator it = javaEntityTags.getUnknownTags().iterator(); it.hasNext(); )
 1799  
                     {
 1800  0
                         String originalJavadocTag = it.next().toString();
 1801  
 
 1802  0
                         if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim()
 1803  
                                         .indexOf( "@" + docletTag.getName() ) != -1 )
 1804  
                         {
 1805  0
                             it.remove();
 1806  0
                             sb.append( originalJavadocTag );
 1807  0
                             sb.append( EOL );
 1808  
                         }
 1809  0
                     }
 1810  
                 }
 1811  31
             }
 1812  
             else
 1813  
             {
 1814  0
                 for ( Iterator it = javaEntityTags.getUnknownTags().iterator(); it.hasNext(); )
 1815  
                 {
 1816  0
                     String originalJavadocTag = it.next().toString();
 1817  
 
 1818  0
                     if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim()
 1819  
                                     .indexOf( "@" + docletTag.getName() ) != -1 )
 1820  
                     {
 1821  0
                         it.remove();
 1822  0
                         sb.append( originalJavadocTag );
 1823  0
                         sb.append( EOL );
 1824  
                     }
 1825  0
                 }
 1826  
             }
 1827  
 
 1828  31
             if ( sb.toString().endsWith( EOL ) )
 1829  
             {
 1830  0
                 sb.delete( sb.toString().lastIndexOf( EOL ), sb.toString().length() );
 1831  
             }
 1832  
 
 1833  31
             sb.append( EOL );
 1834  
         }
 1835  17
     }
 1836  
 
 1837  
     private void writeParamTag( final StringBuffer sb, final JavaMethod javaMethod,
 1838  
                                 final JavaEntityTags javaEntityTags, String[] params )
 1839  
     {
 1840  18
         params = fixQdox173( params );
 1841  
 
 1842  18
         String paramName = params[0];
 1843  
 
 1844  18
         if ( !fixTag( PARAM_TAG ) )
 1845  
         {
 1846  
             // write original param tag if found
 1847  0
             String originalJavadocTag = javaEntityTags.getJavadocParamTag( paramName );
 1848  0
             if ( originalJavadocTag != null )
 1849  
             {
 1850  0
                 sb.append( originalJavadocTag );
 1851  
             }
 1852  0
             return;
 1853  
         }
 1854  
 
 1855  18
         boolean found = false;
 1856  18
         JavaParameter javaParam = javaMethod.getParameterByName( paramName );
 1857  18
         if ( javaParam == null )
 1858  
         {
 1859  
             // is generic?
 1860  6
             TypeVariable[] typeParams = javaMethod.getTypeParameters();
 1861  14
             for ( int i = 0; i < typeParams.length; i++ )
 1862  
             {
 1863  8
                 if ( typeParams[i].getGenericValue().equals( paramName ) )
 1864  
                 {
 1865  2
                     found = true;
 1866  
                 }
 1867  
             }
 1868  6
         }
 1869  
         else
 1870  
         {
 1871  12
             found = true;
 1872  
         }
 1873  
 
 1874  18
         if ( !found )
 1875  
         {
 1876  4
             if ( getLog().isWarnEnabled() )
 1877  
             {
 1878  4
                 StringBuffer warn = new StringBuffer();
 1879  
 
 1880  4
                 warn.append( "Fixed unknown param '" ).append( paramName ).append( "' defined in " );
 1881  4
                 warn.append( getJavaMethodAsString( javaMethod ) );
 1882  
 
 1883  4
                 getLog().warn( warn.toString() );
 1884  
             }
 1885  
 
 1886  4
             if ( sb.toString().endsWith( EOL ) )
 1887  
             {
 1888  4
                 sb.delete( sb.toString().lastIndexOf( EOL ), sb.toString().length() );
 1889  
             }
 1890  
         }
 1891  
         else
 1892  
         {
 1893  14
             String originalJavadocTag = javaEntityTags.getJavadocParamTag( paramName );
 1894  14
             if ( originalJavadocTag != null )
 1895  
             {
 1896  14
                 sb.append( originalJavadocTag );
 1897  14
                 String s = "@" + PARAM_TAG + " " + paramName;
 1898  14
                 if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim().endsWith( s ) )
 1899  
                 {
 1900  3
                     sb.append( " " );
 1901  3
                     sb.append( getDefaultJavadocForType( javaParam.getType() ) );
 1902  
                 }
 1903  
             }
 1904  
         }
 1905  18
     }
 1906  
 
 1907  
     private void writeReturnTag( final StringBuffer sb, final JavaMethod javaMethod,
 1908  
                                  final JavaEntityTags javaEntityTags )
 1909  
     {
 1910  8
         String originalJavadocTag = javaEntityTags.getJavadocReturnTag();
 1911  8
         if ( originalJavadocTag == null )
 1912  
         {
 1913  0
             return;
 1914  
         }
 1915  
 
 1916  8
         if ( !fixTag( RETURN_TAG ) )
 1917  
         {
 1918  
             // write original param tag if found
 1919  0
             sb.append( originalJavadocTag );
 1920  0
             return;
 1921  
         }
 1922  
 
 1923  8
         if ( StringUtils.isNotEmpty( originalJavadocTag ) && javaMethod.getReturns() != null
 1924  
             && !javaMethod.getReturns().isVoid() )
 1925  
         {
 1926  8
             sb.append( originalJavadocTag );
 1927  8
             if ( originalJavadocTag.trim().endsWith( "@" + RETURN_TAG ) )
 1928  
             {
 1929  0
                 sb.append( " " );
 1930  0
                 sb.append( getDefaultJavadocForType( javaMethod.getReturns() ) );
 1931  
             }
 1932  
         }
 1933  8
     }
 1934  
 
 1935  
     private void writeThrowsTag( final StringBuffer sb, final JavaMethod javaMethod,
 1936  
                                  final JavaEntityTags javaEntityTags, final String[] params )
 1937  
     {
 1938  5
         String exceptionClassName = params[0];
 1939  
 
 1940  5
         String originalJavadocTag = javaEntityTags.getJavadocThrowsTag( exceptionClassName );
 1941  5
         if ( originalJavadocTag == null )
 1942  
         {
 1943  0
             return;
 1944  
         }
 1945  
 
 1946  5
         if ( !fixTag( THROWS_TAG ) )
 1947  
         {
 1948  
             // write original param tag if found
 1949  0
             sb.append( originalJavadocTag );
 1950  0
             return;
 1951  
         }
 1952  
 
 1953  5
         if ( javaMethod.getExceptions() != null )
 1954  
         {
 1955  5
             for ( int j = 0; j < javaMethod.getExceptions().length; j++ )
 1956  
             {
 1957  2
                 Type exception = javaMethod.getExceptions()[j];
 1958  
 
 1959  2
                 if ( exception.getValue().endsWith( exceptionClassName ) )
 1960  
                 {
 1961  2
                     originalJavadocTag =
 1962  
                         StringUtils.replace( originalJavadocTag, exceptionClassName, exception.getValue() );
 1963  2
                     if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim()
 1964  
                                     .endsWith( "@" + THROWS_TAG + " " + exception.getValue() ) )
 1965  
                     {
 1966  0
                         originalJavadocTag += " if any.";
 1967  
                     }
 1968  
 
 1969  2
                     sb.append( originalJavadocTag );
 1970  
 
 1971  
                     // added qualified name
 1972  2
                     javaEntityTags.putJavadocThrowsTag( exception.getValue(), originalJavadocTag );
 1973  
 
 1974  2
                     return;
 1975  
                 }
 1976  
             }
 1977  
         }
 1978  
 
 1979  
         // Maybe a RuntimeException
 1980  3
         Class clazz = getRuntimeExceptionClass( javaMethod.getParentClass(), exceptionClassName );
 1981  3
         if ( clazz != null )
 1982  
         {
 1983  2
             sb.append( StringUtils.replace( originalJavadocTag, exceptionClassName, clazz.getName() ) );
 1984  
 
 1985  
             // added qualified name
 1986  2
             javaEntityTags.putJavadocThrowsTag( clazz.getName(), originalJavadocTag );
 1987  
 
 1988  2
             return;
 1989  
         }
 1990  
 
 1991  1
         if ( getLog().isWarnEnabled() )
 1992  
         {
 1993  1
             StringBuffer warn = new StringBuffer();
 1994  
 
 1995  1
             warn.append( "Unknown throws exception '" ).append( exceptionClassName ).append( "' defined in " );
 1996  1
             warn.append( getJavaMethodAsString( javaMethod ) );
 1997  
 
 1998  1
             getLog().warn( warn.toString() );
 1999  
         }
 2000  
 
 2001  1
         sb.append( originalJavadocTag );
 2002  1
         if ( params.length == 1 )
 2003  
         {
 2004  0
             sb.append( " if any." );
 2005  
         }
 2006  1
     }
 2007  
 
 2008  
     /**
 2009  
      * Add missing tags not already written.
 2010  
      *
 2011  
      * @param sb not null
 2012  
      * @param entity not null
 2013  
      * @param indent not null
 2014  
      * @param isJavaMethod
 2015  
      * @param javaEntityTags not null
 2016  
      * @throws MojoExecutionException if any
 2017  
      */
 2018  
     private void addMissingJavadocTags( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
 2019  
                                         final String indent, final boolean isJavaMethod,
 2020  
                                         final JavaEntityTags javaEntityTags )
 2021  
         throws MojoExecutionException
 2022  
     {
 2023  17
         if ( isJavaMethod )
 2024  
         {
 2025  17
             JavaMethod javaMethod = (JavaMethod) entity;
 2026  
 
 2027  17
             if ( fixTag( PARAM_TAG ) )
 2028  
             {
 2029  17
                 if ( javaMethod.getParameters() != null )
 2030  
                 {
 2031  35
                     for ( int i = 0; i < javaMethod.getParameters().length; i++ )
 2032  
                     {
 2033  18
                         JavaParameter javaParameter = javaMethod.getParameters()[i];
 2034  
 
 2035  18
                         if ( javaEntityTags.getJavadocParamTag( javaParameter.getName(), true ) == null )
 2036  
                         {
 2037  6
                             appendDefaultParamTag( sb, indent, javaParameter );
 2038  
                         }
 2039  
                     }
 2040  
                 }
 2041  
                 // is generic?
 2042  17
                 if ( javaMethod.getTypeParameters() != null )
 2043  
                 {
 2044  21
                     for ( int i = 0; i < javaMethod.getTypeParameters().length; i++ )
 2045  
                     {
 2046  4
                         TypeVariable typeParam = javaMethod.getTypeParameters()[i];
 2047  
 
 2048  4
                         if ( javaEntityTags.getJavadocParamTag( "<" + typeParam.getName() + ">", true ) == null )
 2049  
                         {
 2050  2
                             appendDefaultParamTag( sb, indent, typeParam );
 2051  
                         }
 2052  
                     }
 2053  
                 }
 2054  
             }
 2055  
 
 2056  17
             if ( fixTag( RETURN_TAG ) && StringUtils.isEmpty( javaEntityTags.getJavadocReturnTag() )
 2057  
                 && javaMethod.getReturns() != null && !javaMethod.getReturns().isVoid() )
 2058  
             {
 2059  2
                 appendDefaultReturnTag( sb, indent, javaMethod );
 2060  
             }
 2061  
 
 2062  17
             if ( fixTag( THROWS_TAG ) && javaMethod.getExceptions() != null )
 2063  
             {
 2064  19
                 for ( int i = 0; i < javaMethod.getExceptions().length; i++ )
 2065  
                 {
 2066  2
                     Type exception = javaMethod.getExceptions()[i];
 2067  
 
 2068  2
                     if ( javaEntityTags.getJavadocThrowsTag( exception.getValue(), true ) == null )
 2069  
                     {
 2070  0
                         appendDefaultThrowsTag( sb, indent, exception );
 2071  
                     }
 2072  
                 }
 2073  
             }
 2074  17
         }
 2075  
         else
 2076  
         {
 2077  0
             if ( !javaEntityTags.getNamesTags().contains( AUTHOR_TAG ) )
 2078  
             {
 2079  0
                 appendDefaultAuthorTag( sb, indent );
 2080  
             }
 2081  0
             if ( !javaEntityTags.getNamesTags().contains( VERSION_TAG ) )
 2082  
             {
 2083  0
                 appendDefaultVersionTag( sb, indent );
 2084  
             }
 2085  
         }
 2086  17
         if ( fixTag( SINCE_TAG ) && !javaEntityTags.getNamesTags().contains( SINCE_TAG ) )
 2087  
         {
 2088  17
             if ( !isJavaMethod )
 2089  
             {
 2090  0
                 if ( !ignoreClirr )
 2091  
                 {
 2092  0
                     if ( isNewClassFromLastVersion( (JavaClass) entity ) )
 2093  
                     {
 2094  0
                         appendDefaultSinceTag( sb, indent );
 2095  
                     }
 2096  
                 }
 2097  
                 else
 2098  
                 {
 2099  0
                     appendDefaultSinceTag( sb, indent );
 2100  0
                     addSinceClasses( (JavaClass) entity );
 2101  
                 }
 2102  
             }
 2103  
             else
 2104  
             {
 2105  17
                 if ( !ignoreClirr )
 2106  
                 {
 2107  17
                     if ( isNewMethodFromLastRevision( (JavaMethod) entity ) )
 2108  
                     {
 2109  2
                         appendDefaultSinceTag( sb, indent );
 2110  
                     }
 2111  
                 }
 2112  
                 else
 2113  
                 {
 2114  0
                     if ( sinceClasses != null && !sinceClassesContains( ( (JavaMethod) entity ).getParentClass() ) )
 2115  
                     {
 2116  0
                         appendDefaultSinceTag( sb, indent );
 2117  
                     }
 2118  
                 }
 2119  
             }
 2120  
         }
 2121  17
     }
 2122  
 
 2123  
     /**
 2124  
      * @param sb not null
 2125  
      * @param entity not null
 2126  
      * @param indent not null
 2127  
      * @param isJavaMethod
 2128  
      * @throws MojoExecutionException if any
 2129  
      */
 2130  
     private void addDefaultJavadocTags( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
 2131  
                                         final String indent, final boolean isJavaMethod )
 2132  
         throws MojoExecutionException
 2133  
     {
 2134  19
         boolean separatorAdded = false;
 2135  19
         if ( isJavaMethod )
 2136  
         {
 2137  14
             JavaMethod javaMethod = (JavaMethod) entity;
 2138  
 
 2139  14
             if ( fixTag( PARAM_TAG ) && javaMethod.getParameters() != null )
 2140  
             {
 2141  29
                 for ( int i = 0; i < javaMethod.getParameters().length; i++ )
 2142  
                 {
 2143  15
                     JavaParameter javaParameter = javaMethod.getParameters()[i];
 2144  
 
 2145  15
                     separatorAdded = appendDefaultParamTag( sb, indent, separatorAdded, javaParameter );
 2146  
                 }
 2147  
             }
 2148  
 
 2149  14
             if ( fixTag( RETURN_TAG ) )
 2150  
             {
 2151  14
                 if ( javaMethod.getReturns() != null && !javaMethod.getReturns().isVoid() )
 2152  
                 {
 2153  8
                     separatorAdded = appendDefaultReturnTag( sb, indent, separatorAdded, javaMethod );
 2154  
                 }
 2155  
             }
 2156  
 
 2157  14
             if ( fixTag( THROWS_TAG ) && javaMethod.getExceptions() != null )
 2158  
             {
 2159  15
                 for ( int i = 0; i < javaMethod.getExceptions().length; i++ )
 2160  
                 {
 2161  1
                     Type exception = javaMethod.getExceptions()[i];
 2162  
 
 2163  1
                     separatorAdded = appendDefaultThrowsTag( sb, indent, separatorAdded, exception );
 2164  
                 }
 2165  
             }
 2166  14
         }
 2167  
         else
 2168  
         {
 2169  5
             separatorAdded = appendDefaultAuthorTag( sb, indent, separatorAdded );
 2170  
 
 2171  5
             separatorAdded = appendDefaultVersionTag( sb, indent, separatorAdded );
 2172  
         }
 2173  
 
 2174  19
         if ( fixTag( SINCE_TAG ) )
 2175  
         {
 2176  19
             if ( !isJavaMethod )
 2177  
             {
 2178  5
                 JavaClass javaClass = (JavaClass) entity;
 2179  
 
 2180  5
                 if ( !ignoreClirr )
 2181  
                 {
 2182  5
                     if ( isNewClassFromLastVersion( javaClass ) )
 2183  
                     {
 2184  0
                         separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
 2185  
                     }
 2186  
                 }
 2187  
                 else
 2188  
                 {
 2189  0
                     separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
 2190  
 
 2191  0
                     addSinceClasses( javaClass );
 2192  
                 }
 2193  5
             }
 2194  
             else
 2195  
             {
 2196  14
                 JavaMethod javaMethod = (JavaMethod) entity;
 2197  
 
 2198  14
                 if ( !ignoreClirr )
 2199  
                 {
 2200  14
                     if ( isNewMethodFromLastRevision( javaMethod ) )
 2201  
                     {
 2202  4
                         separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
 2203  
                     }
 2204  
                 }
 2205  
                 else
 2206  
                 {
 2207  0
                     if ( sinceClasses != null && !sinceClassesContains( javaMethod.getParentClass() ) )
 2208  
                     {
 2209  0
                         separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
 2210  
                     }
 2211  
                 }
 2212  
             }
 2213  
         }
 2214  19
     }
 2215  
 
 2216  
     /**
 2217  
      * @param sb not null
 2218  
      * @param indent not null
 2219  
      * @param separatorAdded
 2220  
      * @return true if separator has been added.
 2221  
      */
 2222  
     private boolean appendDefaultAuthorTag( final StringBuffer sb, final String indent, boolean separatorAdded )
 2223  
     {
 2224  5
         if ( !fixTag( AUTHOR_TAG ) )
 2225  
         {
 2226  0
             return separatorAdded;
 2227  
         }
 2228  
 
 2229  5
         if ( !separatorAdded )
 2230  
         {
 2231  5
             appendSeparator( sb, indent );
 2232  5
             separatorAdded = true;
 2233  
         }
 2234  
 
 2235  5
         appendDefaultAuthorTag( sb, indent );
 2236  5
         return separatorAdded;
 2237  
     }
 2238  
 
 2239  
     /**
 2240  
      * @param sb not null
 2241  
      * @param indent not null
 2242  
      */
 2243  
     private void appendDefaultAuthorTag( final StringBuffer sb, final String indent )
 2244  
     {
 2245  9
         if ( !fixTag( AUTHOR_TAG ) )
 2246  
         {
 2247  0
             return;
 2248  
         }
 2249  
 
 2250  9
         sb.append( indent ).append( " * @" ).append( AUTHOR_TAG ).append( " " );
 2251  9
         sb.append( defaultAuthor );
 2252  9
         sb.append( EOL );
 2253  9
     }
 2254  
 
 2255  
     /**
 2256  
      * @param sb not null
 2257  
      * @param indent not null
 2258  
      * @param separatorAdded
 2259  
      * @return true if separator has been added.
 2260  
      */
 2261  
     private boolean appendDefaultSinceTag( final StringBuffer sb, final String indent, boolean separatorAdded )
 2262  
     {
 2263  9
         if ( !fixTag( SINCE_TAG ) )
 2264  
         {
 2265  0
             return separatorAdded;
 2266  
         }
 2267  
 
 2268  9
         if ( !separatorAdded )
 2269  
         {
 2270  0
             appendSeparator( sb, indent );
 2271  0
             separatorAdded = true;
 2272  
         }
 2273  
 
 2274  9
         appendDefaultSinceTag( sb, indent );
 2275  9
         return separatorAdded;
 2276  
     }
 2277  
 
 2278  
     /**
 2279  
      * @param sb not null
 2280  
      * @param indent not null
 2281  
      */
 2282  
     private void appendDefaultSinceTag( final StringBuffer sb, final String indent )
 2283  
     {
 2284  11
         if ( !fixTag( SINCE_TAG ) )
 2285  
         {
 2286  0
             return;
 2287  
         }
 2288  
 
 2289  11
         sb.append( indent ).append( " * @" ).append( SINCE_TAG ).append( " " );
 2290  11
         sb.append( defaultSince );
 2291  11
         sb.append( EOL );
 2292  11
     }
 2293  
 
 2294  
     /**
 2295  
      * @param sb not null
 2296  
      * @param indent not null
 2297  
      * @param separatorAdded
 2298  
      * @return true if separator has been added.
 2299  
      */
 2300  
     private boolean appendDefaultVersionTag( final StringBuffer sb, final String indent, boolean separatorAdded )
 2301  
     {
 2302  5
         if ( !fixTag( VERSION_TAG ) )
 2303  
         {
 2304  0
             return separatorAdded;
 2305  
         }
 2306  
 
 2307  5
         if ( !separatorAdded )
 2308  
         {
 2309  0
             appendSeparator( sb, indent );
 2310  0
             separatorAdded = true;
 2311  
         }
 2312  
 
 2313  5
         appendDefaultVersionTag( sb, indent );
 2314  5
         return separatorAdded;
 2315  
     }
 2316  
 
 2317  
     /**
 2318  
      * @param sb not null
 2319  
      * @param indent not null
 2320  
      */
 2321  
     private void appendDefaultVersionTag( final StringBuffer sb, final String indent )
 2322  
     {
 2323  9
         if ( !fixTag( VERSION_TAG ) )
 2324  
         {
 2325  0
             return;
 2326  
         }
 2327  
 
 2328  9
         sb.append( indent ).append( " * @" ).append( VERSION_TAG ).append( " " );
 2329  9
         sb.append( defaultVersion );
 2330  9
         sb.append( EOL );
 2331  9
     }
 2332  
 
 2333  
     /**
 2334  
      * @param sb not null
 2335  
      * @param indent not null
 2336  
      * @param separatorAdded
 2337  
      * @param javaParameter not null
 2338  
      * @return true if separator has been added.
 2339  
      */
 2340  
     private boolean appendDefaultParamTag( final StringBuffer sb, final String indent, boolean separatorAdded,
 2341  
                                            final JavaParameter javaParameter )
 2342  
     {
 2343  39
         if ( !fixTag( PARAM_TAG ) )
 2344  
         {
 2345  0
             return separatorAdded;
 2346  
         }
 2347  
 
 2348  39
         if ( !separatorAdded )
 2349  
         {
 2350  25
             appendSeparator( sb, indent );
 2351  25
             separatorAdded = true;
 2352  
         }
 2353  
 
 2354  39
         appendDefaultParamTag( sb, indent, javaParameter );
 2355  39
         return separatorAdded;
 2356  
     }
 2357  
 
 2358  
     /**
 2359  
      * @param sb not null
 2360  
      * @param indent not null
 2361  
      * @param separatorAdded
 2362  
      * @param typeParameter not null
 2363  
      * @return true if separator has been added.
 2364  
      */
 2365  
     private boolean appendDefaultParamTag( final StringBuffer sb, final String indent, boolean separatorAdded,
 2366  
                                            final TypeVariable typeParameter )
 2367  
     {
 2368  7
         if ( !fixTag( PARAM_TAG ) )
 2369  
         {
 2370  0
             return separatorAdded;
 2371  
         }
 2372  
 
 2373  7
         if ( !separatorAdded )
 2374  
         {
 2375  0
             appendSeparator( sb, indent );
 2376  0
             separatorAdded = true;
 2377  
         }
 2378  
 
 2379  7
         appendDefaultParamTag( sb, indent, typeParameter );
 2380  7
         return separatorAdded;
 2381  
     }
 2382  
 
 2383  
     /**
 2384  
      * @param sb not null
 2385  
      * @param indent not null
 2386  
      * @param javaParameter not null
 2387  
      */
 2388  
     private void appendDefaultParamTag( final StringBuffer sb, final String indent,
 2389  
                                         final JavaParameter javaParameter )
 2390  
     {
 2391  45
         if ( !fixTag( PARAM_TAG ) )
 2392  
         {
 2393  0
             return;
 2394  
         }
 2395  
 
 2396  45
         sb.append( indent ).append( " * @" ).append( PARAM_TAG ).append( " " );
 2397  45
         sb.append( javaParameter.getName() );
 2398  45
         sb.append( " " );
 2399  45
         sb.append( getDefaultJavadocForType( javaParameter.getType() ) );
 2400  45
         sb.append( EOL );
 2401  45
     }
 2402  
 
 2403  
     /**
 2404  
      * @param sb not null
 2405  
      * @param indent not null
 2406  
      * @param typeParameter not null
 2407  
      */
 2408  
     private void appendDefaultParamTag( final StringBuffer sb, final String indent,
 2409  
                                         final TypeVariable typeParameter )
 2410  
     {
 2411  9
         if ( !fixTag( PARAM_TAG ) )
 2412  
         {
 2413  0
             return;
 2414  
         }
 2415  
 
 2416  9
         sb.append( indent ).append( " * @" ).append( PARAM_TAG ).append( " " );
 2417  9
         sb.append( "<" + typeParameter.getName() + ">" );
 2418  9
         sb.append( " " );
 2419  9
         sb.append( getDefaultJavadocForType( typeParameter ) );
 2420  9
         sb.append( EOL );
 2421  9
     }
 2422  
 
 2423  
     /**
 2424  
      * @param sb not null
 2425  
      * @param indent not null
 2426  
      * @param separatorAdded
 2427  
      * @param javaMethod not null
 2428  
      * @return true if separator has been added.
 2429  
      */
 2430  
     private boolean appendDefaultReturnTag( final StringBuffer sb, final String indent, boolean separatorAdded,
 2431  
                                             final JavaMethod javaMethod )
 2432  
     {
 2433  14
         if ( !fixTag( RETURN_TAG ) )
 2434  
         {
 2435  0
             return separatorAdded;
 2436  
         }
 2437  
 
 2438  14
         if ( !separatorAdded )
 2439  
         {
 2440  0
             appendSeparator( sb, indent );
 2441  0
             separatorAdded = true;
 2442  
         }
 2443  
 
 2444  14
         appendDefaultReturnTag( sb, indent, javaMethod );
 2445  14
         return separatorAdded;
 2446  
     }
 2447  
 
 2448  
     /**
 2449  
      * @param sb not null
 2450  
      * @param indent not null
 2451  
      * @param javaMethod not null
 2452  
      */
 2453  
     private void appendDefaultReturnTag( final StringBuffer sb, final String indent, final JavaMethod javaMethod )
 2454  
     {
 2455  16
         if ( !fixTag( RETURN_TAG ) )
 2456  
         {
 2457  0
             return;
 2458  
         }
 2459  
 
 2460  16
         sb.append( indent ).append( " * @" ).append( RETURN_TAG ).append( " " );
 2461  16
         sb.append( getDefaultJavadocForType( javaMethod.getReturns() ) );
 2462  16
         sb.append( EOL );
 2463  16
     }
 2464  
 
 2465  
     /**
 2466  
      * @param sb not null
 2467  
      * @param indent not null
 2468  
      * @param separatorAdded
 2469  
      * @param exception not null
 2470  
      * @return true if separator has been added.
 2471  
      */
 2472  
     private boolean appendDefaultThrowsTag( final StringBuffer sb, final String indent, boolean separatorAdded,
 2473  
                                             final Type exception )
 2474  
     {
 2475  2
         if ( !fixTag( THROWS_TAG ) )
 2476  
         {
 2477  0
             return separatorAdded;
 2478  
         }
 2479  
 
 2480  2
         if ( !separatorAdded )
 2481  
         {
 2482  0
             appendSeparator( sb, indent );
 2483  0
             separatorAdded = true;
 2484  
         }
 2485  
 
 2486  2
         appendDefaultThrowsTag( sb, indent, exception );
 2487  2
         return separatorAdded;
 2488  
     }
 2489  
 
 2490  
     /**
 2491  
      * @param sb not null
 2492  
      * @param indent not null
 2493  
      * @param exception not null
 2494  
      */
 2495  
     private void appendDefaultThrowsTag( final StringBuffer sb, final String indent, final Type exception )
 2496  
     {
 2497  2
         if ( !fixTag( THROWS_TAG ) )
 2498  
         {
 2499  0
             return;
 2500  
         }
 2501  
 
 2502  2
         sb.append( indent ).append( " * @" ).append( THROWS_TAG ).append( " " );
 2503  2
         sb.append( exception.getJavaClass().getFullyQualifiedName() );
 2504  2
         sb.append( " if any." );
 2505  2
         sb.append( EOL );
 2506  2
     }
 2507  
 
 2508  
     /**
 2509  
      * @param sb not null
 2510  
      * @param indent not null
 2511  
      */
 2512  
     private void appendSeparator( final StringBuffer sb, final String indent )
 2513  
     {
 2514  53
         sb.append( indent ).append( " *" );
 2515  53
         sb.append( EOL );
 2516  53
     }
 2517  
 
 2518  
     /**
 2519  
      * Verify if a method has <code>&#64;java.lang.Override()</code> annotation or if it is an inherited method
 2520  
      * from an interface or a super class. The goal is to handle <code>&#123;&#64;inheritDoc&#125;</code> tag.
 2521  
      *
 2522  
      * @param javaMethod not null
 2523  
      * @return <code>true</code> if the method is inherited, <code>false</code> otherwise.
 2524  
      * @throws MojoExecutionException if any
 2525  
      */
 2526  
     private boolean isInherited( JavaMethod javaMethod )
 2527  
         throws MojoExecutionException, SecurityException
 2528  
     {
 2529  60
         if ( javaMethod.getAnnotations() != null )
 2530  
         {
 2531  60
             for ( int i = 0; i < javaMethod.getAnnotations().length; i++ )
 2532  
             {
 2533  1
                 Annotation annotation = javaMethod.getAnnotations()[i];
 2534  
 
 2535  1
                 if ( annotation.toString().equals( "@java.lang.Override()" ) )
 2536  
                 {
 2537  1
                     return true;
 2538  
                 }
 2539  
             }
 2540  
         }
 2541  
 
 2542  59
         Class clazz = getClass( javaMethod.getParentClass().getFullyQualifiedName() );
 2543  
 
 2544  59
         List interfaces = ClassUtils.getAllInterfaces( clazz );
 2545  59
         for ( Iterator it = interfaces.iterator(); it.hasNext(); )
 2546  
         {
 2547  46
             Class intface = (Class) it.next();
 2548  
 
 2549  46
             if ( isInherited( intface, javaMethod ) )
 2550  
             {
 2551  13
                 return true;
 2552  
             }
 2553  33
         }
 2554  
 
 2555  46
         List classes = ClassUtils.getAllSuperclasses( clazz );
 2556  46
         for ( Iterator it = classes.iterator(); it.hasNext(); )
 2557  
         {
 2558  33
             Class superClass = (Class) it.next();
 2559  
 
 2560  33
             if ( isInherited( superClass, javaMethod ) )
 2561  
             {
 2562  0
                 return true;
 2563  
             }
 2564  33
         }
 2565  
 
 2566  46
         return false;
 2567  
     }
 2568  
 
 2569  
     /**
 2570  
      * @param clazz the Java class object, not null
 2571  
      * @param javaMethod the QDox JavaMethod object not null
 2572  
      * @return <code>true</code> if <code>javaMethod</code> exists in the given <code>clazz</code>,
 2573  
      * <code>false</code> otherwise.
 2574  
      * @see #isInherited(JavaMethod)
 2575  
      */
 2576  
     private boolean isInherited( Class clazz, JavaMethod javaMethod )
 2577  
     {
 2578  79
         Method[] methods = clazz.getDeclaredMethods();
 2579  634
         for ( int i = 0; i < methods.length; i++ )
 2580  
         {
 2581  568
             if ( !methods[i].getName().equals( javaMethod.getName() ) )
 2582  
             {
 2583  555
                 continue;
 2584  
             }
 2585  
 
 2586  13
             if ( methods[i].getParameterTypes().length != javaMethod.getParameters().length )
 2587  
             {
 2588  0
                 continue;
 2589  
             }
 2590  
 
 2591  13
             boolean found = false;
 2592  30
             for ( int j = 0; j < methods[i].getParameterTypes().length; j++ )
 2593  
             {
 2594  17
                 String name1 = methods[i].getParameterTypes()[j].getName();
 2595  17
                 String name2 = javaMethod.getParameters()[j].getType().getFullQualifiedName();
 2596  17
                 if ( name1.equals( name2 ) )
 2597  
                 {
 2598  17
                     found = true;
 2599  
                 }
 2600  
                 else
 2601  
                 {
 2602  0
                     found = found && false;
 2603  
                 }
 2604  
             }
 2605  
 
 2606  13
             return found;
 2607  
         }
 2608  
 
 2609  66
         return false;
 2610  
     }
 2611  
 
 2612  
     /**
 2613  
      * @param type
 2614  
      * @return
 2615  
      */
 2616  
     private String getDefaultJavadocForType( Type type )
 2617  
     {
 2618  73
         StringBuffer sb = new StringBuffer();
 2619  
 
 2620  73
         if ( !TypeVariable.class.isAssignableFrom( type.getClass() ) && type.isPrimitive() )
 2621  
         {
 2622  12
             if ( type.isArray() )
 2623  
             {
 2624  0
                 sb.append( "an array of " );
 2625  
             }
 2626  
             else
 2627  
             {
 2628  12
                 sb.append( "a " );
 2629  
             }
 2630  12
             sb.append( type.getJavaClass().getFullyQualifiedName() );
 2631  12
             sb.append( "." );
 2632  12
             return sb.toString();
 2633  
         }
 2634  
 
 2635  61
         StringBuffer javadocLink = new StringBuffer();
 2636  
         try
 2637  
         {
 2638  61
             getClass( type.getJavaClass().getFullyQualifiedName() );
 2639  
 
 2640  50
             javadocLink.append( "{@link " );
 2641  50
             String s = type.getJavaClass().getFullyQualifiedName();
 2642  50
             s = StringUtils.replace( s, "$", "." );
 2643  50
             javadocLink.append( s );
 2644  50
             javadocLink.append( "}" );
 2645  
         }
 2646  11
         catch ( Exception e )
 2647  
         {
 2648  11
             javadocLink.append( type.getJavaClass().getFullyQualifiedName() );
 2649  50
         }
 2650  
 
 2651  61
         if ( type.isArray() )
 2652  
         {
 2653  0
             sb.append( "an array of " );
 2654  0
             sb.append( javadocLink.toString() );
 2655  0
             sb.append( " objects." );
 2656  
         }
 2657  
         else
 2658  
         {
 2659  61
             sb.append( "a " ).append( javadocLink.toString() ).append( " object." );
 2660  
         }
 2661  
 
 2662  61
         return sb.toString();
 2663  
     }
 2664  
 
 2665  
     /**
 2666  
      * Check under Clirr if this given class is newer from the last version.
 2667  
      *
 2668  
      * @param javaClass a given class not null
 2669  
      * @return <code>true</code> if Clirr said that this class is added from the last version,
 2670  
      * <code>false</code> otherwise or if {@link #clirrNewClasses} is null.
 2671  
      */
 2672  
     private boolean isNewClassFromLastVersion( JavaClass javaClass )
 2673  
     {
 2674  9
         if ( clirrNewClasses == null )
 2675  
         {
 2676  0
             return false;
 2677  
         }
 2678  
 
 2679  9
         return clirrNewClasses.contains( javaClass.getFullyQualifiedName() );
 2680  
     }
 2681  
 
 2682  
     /**
 2683  
      * Check under Clirr if this given method is newer from the last version.
 2684  
      *
 2685  
      * @param javaMethod a given method not null
 2686  
      * @return <code>true</code> if Clirr said that this method is added from the last version,
 2687  
      * <code>false</code> otherwise or if {@link #clirrNewMethods} is null.
 2688  
      * @throws MojoExecutionException  if any
 2689  
      */
 2690  
     private boolean isNewMethodFromLastRevision( JavaMethod javaMethod )
 2691  
         throws MojoExecutionException
 2692  
     {
 2693  46
         if ( clirrNewMethods == null )
 2694  
         {
 2695  0
             return false;
 2696  
         }
 2697  
 
 2698  46
         List clirrMethods = (List) clirrNewMethods.get( javaMethod.getParentClass().getFullyQualifiedName() );
 2699  46
         if ( clirrMethods == null )
 2700  
         {
 2701  0
             return false;
 2702  
         }
 2703  
 
 2704  46
         for ( Iterator it = clirrMethods.iterator(); it.hasNext(); )
 2705  
         {
 2706  
             // see net.sf.clirr.core.internal.checks.MethodSetCheck#getMethodId(JavaType clazz, Method method)
 2707  88
             String clirrMethod = (String) it.next();
 2708  
 
 2709  88
             String retrn = "";
 2710  88
             if ( javaMethod.getReturns() != null )
 2711  
             {
 2712  66
                 retrn = javaMethod.getReturns().getFullQualifiedName();
 2713  
             }
 2714  88
             StringBuffer params = new StringBuffer();
 2715  88
             JavaParameter[] parameters = javaMethod.getParameters();
 2716  189
             for ( int i = 0; i < parameters.length; i++ )
 2717  
             {
 2718  101
                 params.append( parameters[i].getResolvedValue() );
 2719  101
                 if ( i < parameters.length - 1 )
 2720  
                 {
 2721  32
                     params.append( ", " );
 2722  
                 }
 2723  
             }
 2724  88
             if ( ( clirrMethod.indexOf( retrn + " " ) != -1 )
 2725  
                 && ( clirrMethod.indexOf( javaMethod.getName() + "(" ) != -1 )
 2726  
                 && ( clirrMethod.indexOf( "(" + params.toString() + ")" ) != -1 ) )
 2727  
             {
 2728  11
                 return true;
 2729  
             }
 2730  77
         }
 2731  
 
 2732  35
         return false;
 2733  
     }
 2734  
 
 2735  
     /**
 2736  
      * @param className not null
 2737  
      * @return the Class corresponding to the given class name using the project classloader.
 2738  
      * @throws MojoExecutionException if class not found
 2739  
      * @see {@link ClassUtils#getClass(ClassLoader, String, boolean)}
 2740  
      * @see {@link #getProjectClassLoader()}
 2741  
      */
 2742  
     private Class getClass( String className )
 2743  
         throws MojoExecutionException
 2744  
     {
 2745  
         try
 2746  
         {
 2747  131
             return ClassUtils.getClass( getProjectClassLoader(), className, false );
 2748  
         }
 2749  20
         catch ( ClassNotFoundException e )
 2750  
         {
 2751  20
             throw new MojoExecutionException( "ClassNotFoundException: " + e.getMessage(), e );
 2752  
         }
 2753  
     }
 2754  
 
 2755  
     /**
 2756  
      * Returns the Class object assignable for {@link RuntimeException} class and associated with the given
 2757  
      * exception class name.
 2758  
      *
 2759  
      * @param currentClass not null
 2760  
      * @param exceptionClassName not null, an exception class name defined as:
 2761  
      * <ul>
 2762  
      * <li>exception class fully qualified</li>
 2763  
      * <li>exception class in the same package</li>
 2764  
      * <li>exception inner class</li>
 2765  
      * <li>exception class in java.lang package</li>
 2766  
      * </ul>
 2767  
      * @return a RuntimeException assignable class.
 2768  
      * @see #getClass(String)
 2769  
      */
 2770  
     private Class getRuntimeExceptionClass( JavaClass currentClass, String exceptionClassName )
 2771  
     {
 2772  3
         String[] potentialClassNames =
 2773  
             new String[] { exceptionClassName, currentClass.getPackage().getName() + "." + exceptionClassName,
 2774  
                 currentClass.getPackage().getName() + "." + currentClass.getName() + "$" + exceptionClassName,
 2775  
                 "java.lang." + exceptionClassName };
 2776  
 
 2777  3
         Class clazz = null;
 2778  12
         for ( int i = 0; i < potentialClassNames.length; i++ )
 2779  
         {
 2780  
             try
 2781  
             {
 2782  11
                 clazz = getClass( potentialClassNames[i] );
 2783  
             }
 2784  9
             catch ( MojoExecutionException e )
 2785  
             {
 2786  
                 // nop
 2787  2
             }
 2788  11
             if ( clazz != null && ClassUtils.isAssignable( clazz, RuntimeException.class ) )
 2789  
             {
 2790  2
                 return clazz;
 2791  
             }
 2792  
         }
 2793  
 
 2794  1
         return null;
 2795  
     }
 2796  
 
 2797  
     /**
 2798  
      * @param javaClass not null
 2799  
      */
 2800  
     private void addSinceClasses( JavaClass javaClass )
 2801  
     {
 2802  0
         if ( sinceClasses == null )
 2803  
         {
 2804  0
             sinceClasses = new ArrayList();
 2805  
         }
 2806  0
         sinceClasses.add( javaClass.getFullyQualifiedName() );
 2807  0
     }
 2808  
 
 2809  
     private boolean sinceClassesContains( JavaClass javaClass )
 2810  
     {
 2811  0
         return sinceClasses.contains( javaClass.getFullyQualifiedName() );
 2812  
     }
 2813  
 
 2814  
     // ----------------------------------------------------------------------
 2815  
     // Static methods
 2816  
     // ----------------------------------------------------------------------
 2817  
 
 2818  
     /**
 2819  
      * @param javaFile not null
 2820  
      * @param encoding not null
 2821  
      * @return the content with unified line separator of the given javaFile using the given encoding.
 2822  
      * @throws IOException if any
 2823  
      */
 2824  
     private static String readFile( final File javaFile, final String encoding )
 2825  
         throws IOException
 2826  
     {
 2827  11
         Reader fileReader = null;
 2828  
         try
 2829  
         {
 2830  11
             fileReader = ReaderFactory.newReader( javaFile, encoding );
 2831  11
             return StringUtils.unifyLineSeparators( IOUtil.toString( fileReader ) );
 2832  
         }
 2833  
         finally
 2834  
         {
 2835  11
             IOUtil.close( fileReader );
 2836  
         }
 2837  
     }
 2838  
 
 2839  
     /**
 2840  
      * Write content into the given javaFile and using the given encoding.
 2841  
      * All line separators will be unified.
 2842  
      *
 2843  
      * @param javaFile not null
 2844  
      * @param encoding not null
 2845  
      * @param content not null
 2846  
      * @throws IOException if any
 2847  
      */
 2848  
     private static void writeFile( final File javaFile, final String encoding, final String content )
 2849  
         throws IOException
 2850  
     {
 2851  9
         Writer writer = null;
 2852  
         try
 2853  
         {
 2854  9
             writer = WriterFactory.newWriter( javaFile, encoding );
 2855  9
             writer.write( StringUtils.unifyLineSeparators( content ) );
 2856  
         }
 2857  
         finally
 2858  
         {
 2859  9
             IOUtil.close( writer );
 2860  9
         }
 2861  9
     }
 2862  
 
 2863  
     /**
 2864  
      * @return the full clirr goal, i.e. <code>groupId:artifactId:version:goal</code>. The clirr-plugin version
 2865  
      * could be load from the pom.properties in the clirr-maven-plugin dependency.
 2866  
      */
 2867  
     private static String getFullClirrGoal()
 2868  
     {
 2869  2
         StringBuffer sb = new StringBuffer();
 2870  
 
 2871  2
         sb.append( CLIRR_MAVEN_PLUGIN_GROUPID ).append( ":" );
 2872  2
         sb.append( CLIRR_MAVEN_PLUGIN_ARTIFACTID ).append( ":" );
 2873  2
         String clirrVersion = CLIRR_MAVEN_PLUGIN_VERSION;
 2874  2
         InputStream resourceAsStream = null;
 2875  
         try
 2876  
         {
 2877  2
             String resource =
 2878  
                 "META-INF/maven/" + CLIRR_MAVEN_PLUGIN_GROUPID + "/" + CLIRR_MAVEN_PLUGIN_ARTIFACTID
 2879  
                     + "/pom.properties";
 2880  2
             resourceAsStream = AbstractFixJavadocMojo.class.getClassLoader().getResourceAsStream( resource );
 2881  
 
 2882  2
             if ( resourceAsStream != null )
 2883  
             {
 2884  0
                 Properties properties = new Properties();
 2885  0
                 properties.load( resourceAsStream );
 2886  
 
 2887  0
                 if ( StringUtils.isNotEmpty( properties.getProperty( "version" ) ) )
 2888  
                 {
 2889  0
                     clirrVersion = properties.getProperty( "version" );
 2890  
                 }
 2891  
             }
 2892  
         }
 2893  0
         catch ( IOException e )
 2894  
         {
 2895  
             // nop
 2896  
         }
 2897  
         finally
 2898  
         {
 2899  2
             IOUtil.close( resourceAsStream );
 2900  2
         }
 2901  
 
 2902  2
         sb.append( clirrVersion ).append( ":" );
 2903  2
         sb.append( CLIRR_MAVEN_PLUGIN_GOAL );
 2904  
 
 2905  2
         return sb.toString();
 2906  
     }
 2907  
 
 2908  
     /**
 2909  
      * Default comment for class.
 2910  
      *
 2911  
      * @param javaClass not null
 2912  
      * @return a default comment for class.
 2913  
      */
 2914  
     private static String getDefaultClassJavadocComment( final JavaClass javaClass )
 2915  
     {
 2916  4
         StringBuffer sb = new StringBuffer();
 2917  
 
 2918  4
         sb.append( "<p>" );
 2919  4
         if ( Arrays.asList( javaClass.getModifiers() ).contains( "abstract" ) )
 2920  
         {
 2921  0
             sb.append( "Abstract " );
 2922  
         }
 2923  
 
 2924  4
         sb.append( javaClass.getName() );
 2925  
 
 2926  4
         if ( !javaClass.isInterface() )
 2927  
         {
 2928  2
             sb.append( " class." );
 2929  
         }
 2930  
         else
 2931  
         {
 2932  2
             sb.append( " interface." );
 2933  
         }
 2934  
 
 2935  4
         sb.append( "</p>" );
 2936  
 
 2937  4
         return sb.toString();
 2938  
     }
 2939  
 
 2940  
     /**
 2941  
      * Default comment for method with taking care of getter/setter in the javaMethod name.
 2942  
      *
 2943  
      * @param javaMethod not null
 2944  
      * @return a default comment for method.
 2945  
      */
 2946  
     private static String getDefaultMethodJavadocComment( final JavaMethod javaMethod )
 2947  
     {
 2948  20
         StringBuffer sb = new StringBuffer();
 2949  
 
 2950  20
         if ( javaMethod.isConstructor() )
 2951  
         {
 2952  5
             sb.append( "<p>Constructor for " );
 2953  5
             sb.append( javaMethod.getName() ).append( ".</p>" );
 2954  5
             return sb.toString();
 2955  
         }
 2956  
 
 2957  15
         if ( javaMethod.getName().length() > 3
 2958  
             && ( javaMethod.getName().startsWith( "get" ) || javaMethod.getName().startsWith( "set" ) ) )
 2959  
         {
 2960  0
             String field = StringUtils.lowercaseFirstLetter( javaMethod.getName().substring( 3 ) );
 2961  
 
 2962  0
             JavaClass clazz = javaMethod.getParentClass();
 2963  
 
 2964  0
             if ( clazz.getFieldByName( field ) == null )
 2965  
             {
 2966  0
                 sb.append( "<p>" ).append( javaMethod.getName() ).append( "</p>" );
 2967  0
                 return sb.toString();
 2968  
             }
 2969  
 
 2970  0
             sb.append( "<p>" );
 2971  0
             if ( javaMethod.getName().startsWith( "get" ) )
 2972  
             {
 2973  0
                 sb.append( "Getter " );
 2974  
             }
 2975  0
             if ( javaMethod.getName().startsWith( "set" ) )
 2976  
             {
 2977  0
                 sb.append( "Setter " );
 2978  
             }
 2979  0
             sb.append( "for the field <code>" ).append( field ).append( "</code>." );
 2980  0
             sb.append( "</p>" );
 2981  
 
 2982  0
             return sb.toString();
 2983  
         }
 2984  
 
 2985  15
         sb.append( "<p>" ).append( javaMethod.getName() ).append( "</p>" );
 2986  
 
 2987  15
         return sb.toString();
 2988  
     }
 2989  
 
 2990  
     /**
 2991  
      * Try to find if a Javadoc comment has an {@link #INHERITED_TAG} for instance:
 2992  
      * <pre>
 2993  
      * &#47;&#42;&#42; {&#64;inheritDoc} &#42;&#47;
 2994  
      * </pre>
 2995  
      * or
 2996  
      * <pre>
 2997  
      * &#47;&#42;&#42;
 2998  
      * &#32;&#42; {&#64;inheritDoc}
 2999  
      * &#32;&#42;&#47;
 3000  
      * </pre>
 3001  
      *
 3002  
      * @param content not null
 3003  
      * @return <code>true</code> if the content has an inherited tag, <code>false</code> otherwise.
 3004  
      */
 3005  
     private static boolean hasInheritedTag( final String content )
 3006  
     {
 3007  18
         final String inheritedTagPattern =
 3008  
             "^\\s*(\\/\\*\\*)?(\\s*(\\*)?)*(\\{)@inheritDoc\\s*(\\})(\\s*(\\*)?)*(\\*\\/)?$";
 3009  18
         return Pattern.matches( inheritedTagPattern, StringUtils.removeDuplicateWhitespace( content ) );
 3010  
     }
 3011  
 
 3012  
     /**
 3013  
      * Workaround for QDOX-146 about whitespace.
 3014  
      * Ideally we want to use <code>entity.getComment()</code>
 3015  
      * <br/>
 3016  
      * For instance, with the following snippet:
 3017  
      * <br/>
 3018  
      *
 3019  
      * <code>
 3020  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff"></font><br />
 3021  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3022  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 3023  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3024  
      * <font color="#3f5fbf">&#42;&nbsp;Dummy&nbsp;Javadoc&nbsp;comment.</font><br />
 3025  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3026  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 3027  
      * <font color="#3f5fbf">s&nbsp;a&nbsp;String</font><br />
 3028  
      * <font color="#808080">5</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3029  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 3030  
      * <font color="#808080">6</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3031  
      * <font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font>
 3032  
      * <font color="#000000">dummyMethod</font><font color="#000000">(&nbsp;</font>
 3033  
      * <font color="#000000">String&nbsp;s&nbsp;</font><font color="#000000">){}</font><br />
 3034  
      * </code>
 3035  
      *
 3036  
      * <br/>
 3037  
      * The return will be:
 3038  
      * <br/>
 3039  
      *
 3040  
      * <code>
 3041  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3042  
      * <font color="#3f5fbf">&#42;&nbsp;Dummy&nbsp;Javadoc&nbsp;comment.</font><br />
 3043  
      * </code>
 3044  
      *
 3045  
      * @param javaClassContent original class content not null
 3046  
      * @param entity not null
 3047  
      * @return the javadoc comment for the entity without any tags.
 3048  
      * @throws IOException if any
 3049  
      */
 3050  
     private static String getJavadocComment( final String javaClassContent, final AbstractJavaEntity entity )
 3051  
         throws IOException
 3052  
     {
 3053  40
         if ( entity.getComment() == null )
 3054  
         {
 3055  0
             return "";
 3056  
         }
 3057  
 
 3058  40
         String originalJavadoc = extractOriginalJavadocContent( javaClassContent, entity );
 3059  
 
 3060  40
         StringBuffer sb = new StringBuffer();
 3061  40
         BufferedReader lr = new BufferedReader( new StringReader( originalJavadoc ) );
 3062  
         String line;
 3063  101
         while ( ( line = lr.readLine() ) != null )
 3064  
         {
 3065  77
             if ( StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "* @" )
 3066  
                 || StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "*@" ) )
 3067  
             {
 3068  0
                 break;
 3069  
             }
 3070  61
             sb.append( line ).append( EOL );
 3071  
         }
 3072  
 
 3073  40
         return trimRight( sb.toString() );
 3074  
     }
 3075  
 
 3076  
     /**
 3077  
      * Work around for QDOX-146 about whitespace.
 3078  
      * Ideally we want to use <code>docletTag.getValue()</code>
 3079  
      * <br/>
 3080  
      * For instance, with the following snippet:
 3081  
      * <br/>
 3082  
      *
 3083  
      * <code>
 3084  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff"></font><br />
 3085  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3086  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 3087  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3088  
      * <font color="#3f5fbf">&#42;&nbsp;Dummy&nbsp;Javadoc&nbsp;comment.</font><br />
 3089  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3090  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 3091  
      * <font color="#3f5fbf">s&nbsp;a&nbsp;String</font><br />
 3092  
      * <font color="#808080">5</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3093  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 3094  
      * <font color="#808080">6</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3095  
      * <font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font>
 3096  
      * <font color="#000000">dummyMethod</font><font color="#000000">(&nbsp;</font>
 3097  
      * <font color="#000000">String&nbsp;s&nbsp;</font><font color="#000000">){}</font><br />
 3098  
      * </code>
 3099  
      *
 3100  
      * <br/>
 3101  
      * The return will be:
 3102  
      * <br/>
 3103  
      *
 3104  
      * <code>
 3105  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3106  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 3107  
      * <font color="#3f5fbf">s&nbsp;a&nbsp;String</font><br />
 3108  
      * </code>
 3109  
      *
 3110  
      * @param javaClassContent original class content not null
 3111  
      * @param entity not null
 3112  
      * @param docletTag not null
 3113  
      * @return the javadoc comment for the entity without Javadoc tags.
 3114  
      * @throws IOException if any
 3115  
      */
 3116  
     private static String getJavadocComment( final String javaClassContent,
 3117  
                                              final AbstractInheritableJavaEntity entity, final DocletTag docletTag )
 3118  
         throws IOException
 3119  
     {
 3120  41
         if ( docletTag.getValue() == null )
 3121  
         {
 3122  0
             return "";
 3123  
         }
 3124  41
         if ( docletTag.getParameters().length == 0 )
 3125  
         {
 3126  1
             return "";
 3127  
         }
 3128  
 
 3129  40
         String originalJavadoc = extractOriginalJavadocContent( javaClassContent, entity );
 3130  
 
 3131  40
         String[] params = fixQdox173( docletTag.getParameters() );
 3132  40
         String paramValue = params[0];
 3133  
 
 3134  40
         StringBuffer sb = new StringBuffer();
 3135  40
         BufferedReader lr = new BufferedReader( new StringReader( originalJavadoc ) );
 3136  
         String line;
 3137  40
         boolean found = false;
 3138  311
         while ( ( line = lr.readLine() ) != null )
 3139  
         {
 3140  271
             if ( StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith(
 3141  
                                                                                   "* @" + docletTag.getName()
 3142  
                                                                                       + " " + paramValue )
 3143  
                 || StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith(
 3144  
                                                                                     "*@" + docletTag.getName()
 3145  
                                                                                         + " " + paramValue ) )
 3146  
             {
 3147  40
                 sb.append( line ).append( EOL );
 3148  40
                 found = true;
 3149  
             }
 3150  
             else
 3151  
             {
 3152  231
                 if ( StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "* @" )
 3153  
                     || StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "*@" ) )
 3154  
                 {
 3155  79
                     found = false;
 3156  
                 }
 3157  231
                 if ( found )
 3158  
                 {
 3159  19
                     sb.append( line ).append( EOL );
 3160  
                 }
 3161  
             }
 3162  
         }
 3163  
 
 3164  40
         return trimRight( sb.toString() );
 3165  
     }
 3166  
 
 3167  
     /**
 3168  
      * Extract the original Javadoc and others comments up to {@link #START_JAVADOC} form the entity. This method
 3169  
      * takes care of the Javadoc indentation. All javadoc lines will be trimmed on right.
 3170  
      * <br/>
 3171  
      * For instance, with the following snippet:
 3172  
      * <br/>
 3173  
      *
 3174  
      * <code>
 3175  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff"></font><br />
 3176  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3177  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 3178  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3179  
      * <font color="#3f5fbf">&#42;&nbsp;Dummy&nbsp;Javadoc&nbsp;comment.</font><br />
 3180  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3181  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 3182  
      * <font color="#3f5fbf">s&nbsp;a&nbsp;String</font><br />
 3183  
      * <font color="#808080">5</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3184  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 3185  
      * <font color="#808080">6</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3186  
      * <font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font>
 3187  
      * <font color="#000000">dummyMethod</font><font color="#000000">(&nbsp;</font>
 3188  
      * <font color="#000000">String&nbsp;s&nbsp;</font><font color="#000000">){}</font><br />
 3189  
      * </code>
 3190  
      *
 3191  
      * <br/>
 3192  
      * The return will be:
 3193  
      * <br/>
 3194  
      *
 3195  
      * <code>
 3196  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3197  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 3198  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3199  
      * <font color="#3f5fbf">&#42;&nbsp;Dummy&nbsp;Javadoc&nbsp;comment.</font><br />
 3200  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3201  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 3202  
      * <font color="#3f5fbf">s&nbsp;a&nbsp;String</font><br />
 3203  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3204  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 3205  
      * </code>
 3206  
      *
 3207  
      * @param javaClassContent not null
 3208  
      * @param entity not null
 3209  
      * @return return the original javadoc as String for the current entity
 3210  
      * @throws IOException if any
 3211  
      */
 3212  
     private static String extractOriginalJavadoc( final String javaClassContent, final AbstractJavaEntity entity )
 3213  
         throws IOException
 3214  
     {
 3215  126
         if ( entity.getComment() == null )
 3216  
         {
 3217  0
             return "";
 3218  
         }
 3219  
 
 3220  126
         String[] javaClassContentLines = getLines( javaClassContent );
 3221  126
         List list = new LinkedList();
 3222  761
         for ( int i = entity.getLineNumber() - 2; i >= 0; i-- )
 3223  
         {
 3224  761
             String line = javaClassContentLines[i];
 3225  
 
 3226  761
             list.add( trimRight( line ) );
 3227  761
             if ( line.trim().startsWith( START_JAVADOC ) )
 3228  
             {
 3229  126
                 break;
 3230  
             }
 3231  
         }
 3232  
 
 3233  126
         Collections.reverse( list );
 3234  
 
 3235  126
         return StringUtils.join( list.iterator(), EOL );
 3236  
     }
 3237  
 
 3238  
     /**
 3239  
      * Extract the Javadoc comment between {@link #START_JAVADOC} and {@link #END_JAVADOC} form the entity. This method
 3240  
      * takes care of the Javadoc indentation. All javadoc lines will be trimmed on right.
 3241  
      * <br/>
 3242  
      * For instance, with the following snippet:
 3243  
      * <br/>
 3244  
      *
 3245  
      * <code>
 3246  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff"></font><br />
 3247  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3248  
      * <font color="#3f5fbf">&#47;&#42;&#42;</font><br />
 3249  
      * <font color="#808080">3</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3250  
      * <font color="#3f5fbf">&#42;&nbsp;Dummy&nbsp;Javadoc&nbsp;comment.</font><br />
 3251  
      * <font color="#808080">4</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3252  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 3253  
      * <font color="#3f5fbf">s&nbsp;a&nbsp;String</font><br />
 3254  
      * <font color="#808080">5</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3255  
      * <font color="#3f5fbf">&#42;&#47;</font><br />
 3256  
      * <font color="#808080">6</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3257  
      * <font color="#7f0055"><b>public&nbsp;</b></font><font color="#7f0055"><b>void&nbsp;</b></font>
 3258  
      * <font color="#000000">dummyMethod</font><font color="#000000">(&nbsp;</font>
 3259  
      * <font color="#000000">String&nbsp;s&nbsp;</font><font color="#000000">){}</font><br />
 3260  
      * </code>
 3261  
      *
 3262  
      * <br/>
 3263  
      * The return will be:
 3264  
      * <br/>
 3265  
      *
 3266  
      * <code>
 3267  
      * <font color="#808080">1</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3268  
      * <font color="#3f5fbf">&#42;&nbsp;Dummy&nbsp;Javadoc&nbsp;comment.</font><br />
 3269  
      * <font color="#808080">2</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>
 3270  
      * <font color="#3f5fbf">&#42;&nbsp;</font><font color="#7f9fbf">@param&nbsp;</font>
 3271  
      * <font color="#3f5fbf">s&nbsp;a&nbsp;String</font><br />
 3272  
      * </code>
 3273  
      *
 3274  
      * @param javaClassContent not null
 3275  
      * @param entity not null
 3276  
      * @return return the original javadoc as String for the current entity
 3277  
      * @throws IOException if any
 3278  
      */
 3279  
     private static String extractOriginalJavadocContent( final String javaClassContent,
 3280  
                                                          final AbstractJavaEntity entity )
 3281  
         throws IOException
 3282  
     {
 3283  81
         if ( entity.getComment() == null )
 3284  
         {
 3285  0
             return "";
 3286  
         }
 3287  
 
 3288  81
         String originalJavadoc = extractOriginalJavadoc( javaClassContent, entity );
 3289  81
         if ( originalJavadoc.indexOf( START_JAVADOC ) != -1 )
 3290  
         {
 3291  81
             originalJavadoc =
 3292  
                 originalJavadoc.substring( originalJavadoc.indexOf( START_JAVADOC ) + START_JAVADOC.length() );
 3293  
         }
 3294  81
         if ( originalJavadoc.indexOf( END_JAVADOC ) != -1 )
 3295  
         {
 3296  81
             originalJavadoc = originalJavadoc.substring( 0, originalJavadoc.indexOf( END_JAVADOC ) );
 3297  
         }
 3298  81
         if ( originalJavadoc.startsWith( "\r\n" ) )
 3299  
         {
 3300  75
             originalJavadoc = originalJavadoc.substring( 2 );
 3301  
         }
 3302  6
         else if ( originalJavadoc.startsWith( "\n" ) || originalJavadoc.startsWith( "\r" ) )
 3303  
         {
 3304  0
             originalJavadoc = originalJavadoc.substring( 1 );
 3305  
         }
 3306  
 
 3307  81
         return trimRight( originalJavadoc );
 3308  
     }
 3309  
 
 3310  
     /**
 3311  
      * @param content not null
 3312  
      * @return the content without last lines containing javadoc separator (ie <code> * </code>)
 3313  
      * @throws IOException if any
 3314  
      * @see #getJavadocComment(String, AbstractInheritableJavaEntity, DocletTag)
 3315  
      */
 3316  
     private static String removeLastEmptyJavadocLines( final String content )
 3317  
         throws IOException
 3318  
     {
 3319  110
         if ( content.indexOf( EOL ) == -1 )
 3320  
         {
 3321  46
             return content;
 3322  
         }
 3323  
 
 3324  64
         String[] lines = getLines( content );
 3325  64
         if ( lines.length == 1 )
 3326  
         {
 3327  0
             return content;
 3328  
         }
 3329  
 
 3330  64
         List linesList = new LinkedList();
 3331  64
         linesList.addAll( Arrays.asList( lines ) );
 3332  
 
 3333  64
         Collections.reverse( linesList );
 3334  
 
 3335  64
         for ( Iterator it = linesList.iterator(); it.hasNext(); )
 3336  
         {
 3337  84
             String line = (String) it.next();
 3338  
 
 3339  84
             if ( line.trim().equals( "*" ) )
 3340  
             {
 3341  20
                 it.remove();
 3342  
             }
 3343  
             else
 3344  
             {
 3345  
                 break;
 3346  
             }
 3347  20
         }
 3348  
 
 3349  64
         Collections.reverse( linesList );
 3350  
 
 3351  64
         return StringUtils.join( linesList.iterator(), EOL );
 3352  
     }
 3353  
 
 3354  
     /**
 3355  
      * @param content not null
 3356  
      * @return the javadoc comment with the given indentation
 3357  
      * @throws IOException if any
 3358  
      * @see #getJavadocComment(String, AbstractInheritableJavaEntity, DocletTag)
 3359  
      */
 3360  
     private static String alignIndentationJavadocLines( final String content, final String indent )
 3361  
         throws IOException
 3362  
     {
 3363  67
         String[] lines = getLines( content );
 3364  
 
 3365  67
         StringBuffer sb = new StringBuffer();
 3366  145
         for ( int i = 0; i < lines.length; i++ )
 3367  
         {
 3368  78
             String line = lines[i];
 3369  78
             if ( !line.trim().startsWith( "*" ) )
 3370  
             {
 3371  1
                 line = "*" + line;
 3372  
             }
 3373  78
             sb.append( indent ).append( " " ).append( trimLeft( line ) );
 3374  78
             if ( i < lines.length - 1 )
 3375  
             {
 3376  12
                 sb.append( EOL );
 3377  
             }
 3378  
         }
 3379  
 
 3380  67
         return sb.toString();
 3381  
     }
 3382  
 
 3383  
     /**
 3384  
      * Autodetect the indentation of a given line:
 3385  
      * <pre>
 3386  
      * autodetectIndentation( null ) = "";
 3387  
      * autodetectIndentation( "a" ) = "";
 3388  
      * autodetectIndentation( "    a" ) = "    ";
 3389  
      * autodetectIndentation( "\ta" ) = "\t";
 3390  
      * </pre>
 3391  
      *
 3392  
      * @param line not null
 3393  
      * @return the indentation for the given line.
 3394  
      */
 3395  
     private static String autodetectIndentation( final String line )
 3396  
     {
 3397  805
         if ( StringUtils.isEmpty( line ) )
 3398  
         {
 3399  109
             return "";
 3400  
         }
 3401  
 
 3402  696
         return line.substring( 0, line.indexOf( trimLeft( line ) ) );
 3403  
     }
 3404  
 
 3405  
     /**
 3406  
      * @param content not null
 3407  
      * @return an array of all content lines
 3408  
      * @throws IOException if any
 3409  
      */
 3410  
     private static String[] getLines( final String content )
 3411  
         throws IOException
 3412  
     {
 3413  293
         List lines = new LinkedList();
 3414  
 
 3415  293
         BufferedReader reader = new BufferedReader( new StringReader( content ) );
 3416  293
         String line = reader.readLine();
 3417  23180
         while ( line != null )
 3418  
         {
 3419  22887
             lines.add( line );
 3420  22887
             line = reader.readLine();
 3421  
         }
 3422  
 
 3423  293
         return (String[]) lines.toArray( new String[0] );
 3424  
     }
 3425  
 
 3426  
     /**
 3427  
      * Trim a given line on the left:
 3428  
      * <pre>
 3429  
      * trimLeft( null ) = "";
 3430  
      * trimLeft( "  " ) = "";
 3431  
      * trimLeft( "a" ) = "a";
 3432  
      * trimLeft( "    a" ) = "a";
 3433  
      * trimLeft( "\ta" ) = "a";
 3434  
      * trimLeft( "    a    " ) = "a    ";
 3435  
      * </pre>
 3436  
      *
 3437  
      * @param text
 3438  
      * @return the text trimmed on left side or empty if text is null.
 3439  
      */
 3440  
     private static String trimLeft( final String text )
 3441  
     {
 3442  782
         if ( StringUtils.isEmpty( text ) || StringUtils.isEmpty( text.trim() ) )
 3443  
         {
 3444  3
             return "";
 3445  
         }
 3446  
 
 3447  779
         String textTrimmed = text.trim();
 3448  779
         return text.substring( text.indexOf( textTrimmed ), text.length() );
 3449  
     }
 3450  
 
 3451  
     /**
 3452  
      * Trim a given line on the right:
 3453  
      * <pre>
 3454  
      * trimRight( null ) = "";
 3455  
      * trimRight( "  " ) = "";
 3456  
      * trimRight( "a" ) = "a";
 3457  
      * trimRight( "a\t" ) = "a";
 3458  
      * trimRight( "    a    " ) = "    a";
 3459  
      * </pre>
 3460  
      *
 3461  
      * @param text
 3462  
      * @return the text trimmed on tight side or empty if text is null.
 3463  
      */
 3464  
     private static String trimRight( final String text )
 3465  
     {
 3466  974
         if ( StringUtils.isEmpty( text ) || StringUtils.isEmpty( text.trim() ) )
 3467  
         {
 3468  3
             return "";
 3469  
         }
 3470  
 
 3471  971
         String textTrimmed = text.trim();
 3472  971
         return text.substring( 0, text.indexOf( textTrimmed ) + textTrimmed.length() );
 3473  
     }
 3474  
 
 3475  
     /**
 3476  
      * Workaroung for QDOX-173 about generic.
 3477  
      *
 3478  
      * @param params not null
 3479  
      * @return the wanted params.
 3480  
      */
 3481  
     private static String[] fixQdox173( String[] params )
 3482  
     {
 3483  89
         if ( params == null || params.length == 0 )
 3484  
         {
 3485  0
             return params;
 3486  
         }
 3487  89
         if ( params.length < 3 )
 3488  
         {
 3489  25
             return params;
 3490  
         }
 3491  
 
 3492  64
         if ( params[0].trim().equals( "<" ) && params[2].trim().equals( ">" ) )
 3493  
         {
 3494  14
             String param = params[1];
 3495  14
             List l = new ArrayList( Arrays.asList( params ) );
 3496  14
             l.set( 1, "<" + param + ">" );
 3497  14
             l.remove( 0 );
 3498  14
             l.remove( 1 );
 3499  
 
 3500  14
             return (String[]) l.toArray( new String[0] );
 3501  
         }
 3502  
 
 3503  50
         return params;
 3504  
     }
 3505  
 
 3506  
     /**
 3507  
      * Wrapper class for the entity's tags.
 3508  
      */
 3509  2
     private class JavaEntityTags
 3510  
     {
 3511  
         private final AbstractInheritableJavaEntity entity;
 3512  
 
 3513  
         private final boolean isJavaMethod;
 3514  
 
 3515  
         /** List of tag names. */
 3516  
         private List namesTags;
 3517  
 
 3518  
         /** Map with java parameter as key and original Javadoc lines as values. */
 3519  
         private Map tagParams;
 3520  
 
 3521  
         /** Original javadoc lines. */
 3522  
         private String tagReturn;
 3523  
 
 3524  
         /** Map with java throw as key and original Javadoc lines as values. */
 3525  
         private Map tagThrows;
 3526  
 
 3527  
         /** Original javadoc lines for unknown tags. */
 3528  
         private List unknownsTags;
 3529  
 
 3530  
         public JavaEntityTags( AbstractInheritableJavaEntity entity, boolean isJavaMethod )
 3531  17
         {
 3532  17
             this.entity = entity;
 3533  17
             this.isJavaMethod = isJavaMethod;
 3534  17
             this.namesTags = new LinkedList();
 3535  17
             this.tagParams = new LinkedHashMap();
 3536  17
             this.tagThrows = new LinkedHashMap();
 3537  17
             this.unknownsTags = new LinkedList();
 3538  17
         }
 3539  
 
 3540  
         public List getNamesTags()
 3541  
         {
 3542  49
             return namesTags;
 3543  
         }
 3544  
 
 3545  
         public String getJavadocReturnTag()
 3546  
         {
 3547  25
             return tagReturn;
 3548  
         }
 3549  
 
 3550  
         public void setJavadocReturnTag( String s )
 3551  
         {
 3552  8
             tagReturn = s;
 3553  8
         }
 3554  
 
 3555  
         public List getUnknownTags()
 3556  
         {
 3557  0
             return unknownsTags;
 3558  
         }
 3559  
 
 3560  
         public void putJavadocParamTag( String paramName, String originalJavadocTag )
 3561  
         {
 3562  18
             tagParams.put( paramName, originalJavadocTag );
 3563  18
         }
 3564  
 
 3565  
         public String getJavadocParamTag( String paramName )
 3566  
         {
 3567  14
             return getJavadocParamTag( paramName, false );
 3568  
         }
 3569  
 
 3570  
         public String getJavadocParamTag( String paramName, boolean nullable )
 3571  
         {
 3572  36
             String originalJavadocTag = (String) tagParams.get( paramName );
 3573  36
             if ( !nullable && originalJavadocTag == null && getLog().isWarnEnabled() )
 3574  
             {
 3575  0
                 getLog().warn( getMessage( paramName, "javaEntityTags.tagParams" ) );
 3576  
             }
 3577  
 
 3578  36
             return originalJavadocTag;
 3579  
         }
 3580  
 
 3581  
         public void putJavadocThrowsTag( String paramName, String originalJavadocTag )
 3582  
         {
 3583  9
             tagThrows.put( paramName, originalJavadocTag );
 3584  9
         }
 3585  
 
 3586  
         public String getJavadocThrowsTag( String paramName )
 3587  
         {
 3588  5
             return getJavadocThrowsTag( paramName, false );
 3589  
         }
 3590  
 
 3591  
         public String getJavadocThrowsTag( String paramName, boolean nullable )
 3592  
         {
 3593  7
             String originalJavadocTag = (String) tagThrows.get( paramName );
 3594  7
             if ( !nullable && originalJavadocTag == null && getLog().isWarnEnabled() )
 3595  
             {
 3596  0
                 getLog().warn( getMessage( paramName, "javaEntityTags.tagThrows" ) );
 3597  
             }
 3598  
 
 3599  7
             return originalJavadocTag;
 3600  
         }
 3601  
 
 3602  
         private String getMessage( String paramName, String mapName )
 3603  
         {
 3604  0
             StringBuffer msg = new StringBuffer();
 3605  0
             msg.append( "No param '" ).append( paramName );
 3606  0
             msg.append( "' key found in " + mapName + " for the entity: " );
 3607  0
             if ( isJavaMethod )
 3608  
             {
 3609  0
                 JavaMethod javaMethod = (JavaMethod) entity;
 3610  0
                 msg.append( getJavaMethodAsString( javaMethod ) );
 3611  0
             }
 3612  
             else
 3613  
             {
 3614  0
                 JavaClass javaClass = (JavaClass) entity;
 3615  0
                 msg.append( javaClass.getFullyQualifiedName() );
 3616  
             }
 3617  
 
 3618  0
             return msg.toString();
 3619  
         }
 3620  
 
 3621  
         /** {@inheritDoc} */
 3622  
         public String toString()
 3623  
         {
 3624  0
             StringBuffer sb = new StringBuffer();
 3625  
 
 3626  0
             sb.append( "namesTags=" ).append( namesTags ).append( "\n" );
 3627  0
             sb.append( "tagParams=" ).append( tagParams ).append( "\n" );
 3628  0
             sb.append( "tagReturn=" ).append( tagReturn ).append( "\n" );
 3629  0
             sb.append( "tagThrows=" ).append( tagThrows ).append( "\n" );
 3630  0
             sb.append( "unknownsTags=" ).append( unknownsTags ).append( "\n" );
 3631  
 
 3632  0
             return sb.toString();
 3633  
         }
 3634  
     }
 3635  
 }