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