Coverage Report - org.apache.maven.tools.plugin.javadoc.AbstractMojoTaglet
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractMojoTaglet
0%
0/117
0%
0/74
3.6
 
 1  
 package org.apache.maven.tools.plugin.javadoc;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.util.ArrayList;
 23  
 import java.util.Arrays;
 24  
 import java.util.Collections;
 25  
 import java.util.Enumeration;
 26  
 import java.util.List;
 27  
 import java.util.StringTokenizer;
 28  
 
 29  
 import javax.swing.text.AttributeSet;
 30  
 import javax.swing.text.MutableAttributeSet;
 31  
 import javax.swing.text.SimpleAttributeSet;
 32  
 
 33  
 import com.sun.javadoc.Tag;
 34  
 import com.sun.tools.doclets.Taglet;
 35  
 
 36  
 /**
 37  
  * Abstract <code>Taglet</code> for <a href="http://maven.codehaus.org/"/>Maven</a> Mojo annotations.
 38  
  * <br/>
 39  
  * A Mojo annotation is defined like the following:
 40  
  * <pre>
 41  
  * &#64;annotation &lt;annotationValue&gt; &lt;parameterName="parameterValue"&gt;
 42  
  * </pre>
 43  
  *
 44  
  * @see <a href="package-summary.html#package_description">package-summary.html</a>
 45  
  *
 46  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 47  
  * @version $Id: AbstractMojoTaglet.java 1405630 2012-11-04 20:38:18Z rfscholte $
 48  
  */
 49  0
 public abstract class AbstractMojoTaglet
 50  
     implements Taglet
 51  
 {
 52  
     /** {@inheritDoc} */
 53  
     public String toString( Tag tag )
 54  
     {
 55  0
         if ( tag == null )
 56  
         {
 57  0
             return null;
 58  
         }
 59  
 
 60  0
         String tagValue = getTagValue( tag );
 61  0
         MutableAttributeSet tagAttributes = getTagAttributes( tag );
 62  
 
 63  0
         StringBuilder sb = new StringBuilder();
 64  
 
 65  0
         appendTag( sb, tag, tagAttributes, tagValue );
 66  
 
 67  0
         return sb.toString();
 68  
     }
 69  
 
 70  
     /** {@inheritDoc} */
 71  
     public String toString( Tag[] tags )
 72  
     {
 73  0
         if ( tags.length == 0 )
 74  
         {
 75  0
             return null;
 76  
         }
 77  
 
 78  0
         StringBuilder sb = new StringBuilder();
 79  0
         for ( int i = 0; i < tags.length; i++ )
 80  
         {
 81  0
             String tagValue = getTagValue( tags[i] );
 82  0
             MutableAttributeSet tagAttributes = getTagAttributes( tags[i] );
 83  
 
 84  0
             appendTag( sb, tags[i], tagAttributes, tagValue );
 85  
         }
 86  
 
 87  0
         return sb.toString();
 88  
     }
 89  
 
 90  
     /**
 91  
      * @return the header, i.e. the message, to display
 92  
      */
 93  
     public abstract String getHeader();
 94  
 
 95  
     /**
 96  
      * @return the given annotation value, or <code>null</code> if the given Mojo annotation/tag does't allow
 97  
      * annotation value.
 98  
      * <br/>
 99  
      * <b>Note</b>: the value could be a pattern value, i.e.: <code>*</code> for every values, <code>a|b|c</code>
 100  
      * for <code>a OR b OR c</code>.
 101  
      */
 102  
     public abstract String getAllowedValue();
 103  
 
 104  
     /**
 105  
      * @return an array of the allowed parameter names for the given Mojo annotation/tag, or <code>null</code>
 106  
      * if the annotation/tag doesn't allow parameter.
 107  
      */
 108  
     public abstract String[] getAllowedParameterNames();
 109  
 
 110  
     /**
 111  
      * @return <code>true</code> if taglet has annotation value, <code>false</code> otherwise.
 112  
      * @see #getAllowedValue()
 113  
      */
 114  
     public boolean hasAnnotationValue()
 115  
     {
 116  0
         return getAllowedValue() != null;
 117  
     }
 118  
 
 119  
     /**
 120  
      * @return <code>true</code> if taglet has parameters, <code>false</code> otherwise.
 121  
      * @see #getAllowedParameterNames()
 122  
      */
 123  
     public boolean hasAnnotationParameters()
 124  
     {
 125  0
         return getAllowedParameterNames() != null;
 126  
     }
 127  
 
 128  
     /**
 129  
      * @param tag not null.
 130  
      * @return a not null String or <code>null</code> if no annotation value was found.
 131  
      */
 132  
     private String getTagValue( Tag tag )
 133  
     {
 134  0
         if ( tag == null )
 135  
         {
 136  0
             throw new IllegalArgumentException( "tag should be not null" );
 137  
         }
 138  
 
 139  0
         String text = tag.text();
 140  0
         if ( isEmpty( text ) )
 141  
         {
 142  
             // using pattern: @annotation
 143  0
             return null;
 144  
         }
 145  
 
 146  0
         String tagValue = null;
 147  0
         StringTokenizer token = new StringTokenizer( text, " " );
 148  0
         while ( token.hasMoreTokens() )
 149  
         {
 150  0
             String nextToken = token.nextToken();
 151  
 
 152  0
             if ( nextToken.indexOf( '=' ) == -1 )
 153  
             {
 154  
                 // using pattern: @annotation <annotationValue>
 155  0
                 tagValue = nextToken;
 156  
             }
 157  0
         }
 158  
 
 159  0
         return tagValue;
 160  
     }
 161  
 
 162  
     /**
 163  
      * @param tag not null.
 164  
      * @return a not null MutableAttributeSet.
 165  
      */
 166  
     private MutableAttributeSet getTagAttributes( Tag tag )
 167  
     {
 168  0
         if ( tag == null )
 169  
         {
 170  0
             throw new IllegalArgumentException( "tag should be not null" );
 171  
         }
 172  
 
 173  0
         String text = tag.text();
 174  
 
 175  0
         StringTokenizer token = new StringTokenizer( text, " " );
 176  0
         MutableAttributeSet tagAttributes = new SimpleAttributeSet();
 177  0
         while ( token.hasMoreTokens() )
 178  
         {
 179  0
             String nextToken = token.nextToken();
 180  
 
 181  0
             if ( nextToken.indexOf( '=' ) == -1 )
 182  
             {
 183  
                 // using pattern: @annotation <annotationValue>
 184  0
                 continue;
 185  
             }
 186  
 
 187  0
             StringTokenizer token2 = new StringTokenizer( nextToken, "=" );
 188  0
             if ( token2.countTokens() != 2 )
 189  
             {
 190  0
                 System.err.println( "The annotation '" + tag.name() + "' has no name/value pairs parameter: "
 191  
                     + tag.name() + " " + text + " (" + tag.position().file() + ":" + tag.position().line() + ":"
 192  
                     + tag.position().column() + ")" );
 193  0
                 tagAttributes.addAttribute( token2.nextToken(), "" );
 194  0
                 continue;
 195  
             }
 196  
 
 197  0
             String name = token2.nextToken();
 198  0
             String value = token2.nextToken().replaceAll( "\"", "" );
 199  
 
 200  0
             if ( getAllowedParameterNames() != null && !Arrays.asList( getAllowedParameterNames() ).contains( name ) )
 201  
             {
 202  0
                 System.err.println( "The annotation '" + tag.name() + "' has wrong parameter name: " + tag.name() + " "
 203  
                     + text + " (" + tag.position().file() + ":" + tag.position().line() + ":" + tag.position().column()
 204  
                     + ")" );
 205  
             }
 206  
 
 207  0
             tagAttributes.addAttribute( name, value );
 208  0
         }
 209  
 
 210  0
         return tagAttributes;
 211  
     }
 212  
 
 213  
     /**
 214  
      * Append a tag
 215  
      *
 216  
      * @param sb not null
 217  
      * @param tag not null
 218  
      * @param tagAttributes not null
 219  
      * @param tagValue not null
 220  
      */
 221  
     private void appendTag( StringBuilder sb, Tag tag, MutableAttributeSet tagAttributes, String tagValue )
 222  
     {
 223  0
         if ( !hasAnnotationParameters() )
 224  
         {
 225  0
             if ( tagAttributes.getAttributeCount() > 0 )
 226  
             {
 227  0
                 System.err.println( "The annotation '@" + getName() + "' should have no attribute ("
 228  
                     + tag.position().file() + ":" + tag.position().line() + ":" + tag.position().column() + ")" );
 229  
             }
 230  
 
 231  0
             if ( hasAnnotationValue() )
 232  
             {
 233  0
                 sb.append( "<DT><B>" ).append( getHeader() ).append( ":</B></DT>" );
 234  0
                 if ( isEveryValues( getAllowedValue() ) )
 235  
                 {
 236  0
                     if ( isNotEmpty( tagValue ) )
 237  
                     {
 238  0
                         sb.append( "<DD>" ).append( tagValue ).append( "</DD>" );
 239  
                     }
 240  
                     else
 241  
                     {
 242  0
                         System.err.println( "The annotation '@" + getName() + "' is specified to have a value but "
 243  
                             + "no value is defined (" + tag.position().file() + ":" + tag.position().line() + ":"
 244  
                             + tag.position().column() + ")" );
 245  0
                         sb.append( "<DD>" ).append( "NOT DEFINED" ).append( "</DD>" );
 246  
                     }
 247  
                 }
 248  
                 else
 249  
                 {
 250  0
                     List<String> l = getOnlyValues( getAllowedValue() );
 251  0
                     if ( isNotEmpty( tagValue ) )
 252  
                     {
 253  0
                         if ( l.contains( tagValue ) )
 254  
                         {
 255  0
                             sb.append( "<DD>" ).append( tagValue ).append( "</DD>" );
 256  
                         }
 257  
                         else
 258  
                         {
 259  0
                             System.err.println( "The annotation '@" + getName() + "' is specified to be a value of "
 260  
                                 + l + " (" + tag.position().file() + ":" + tag.position().line() + ":"
 261  
                                 + tag.position().column() + ")" );
 262  0
                             sb.append( "<DD>" ).append( tagValue ).append( "</DD>" );
 263  
                         }
 264  
                     }
 265  
                     else
 266  
                     {
 267  0
                         sb.append( "<DD>" ).append( l.get( 0 ) ).append( "</DD>" );
 268  
                     }
 269  0
                 }
 270  
             }
 271  
             else
 272  
             {
 273  0
                 if ( isNotEmpty( tagValue ) )
 274  
                 {
 275  0
                     System.err.println( "The annotation '@" + getName() + "' should have no value ("
 276  
                         + tag.position().file() + ":" + tag.position().line() + ":" + tag.position().column() + ")" );
 277  
                 }
 278  0
                 sb.append( "<DT><B>" ).append( getHeader() ).append( "</B></DT>" );
 279  0
                 sb.append( "<DD></DD>" );
 280  
             }
 281  
         }
 282  
         else
 283  
         {
 284  0
             if ( hasAnnotationValue() )
 285  
             {
 286  0
                 sb.append( "<DT><B>" ).append( getHeader() ).append( ":</B></DT>" );
 287  0
                 if ( isEveryValues( getAllowedValue() ) )
 288  
                 {
 289  0
                     if ( isNotEmpty( tagValue ) )
 290  
                     {
 291  0
                         sb.append( "<DD>" ).append( tagValue );
 292  
                     }
 293  
                     else
 294  
                     {
 295  0
                         System.err.println( "The annotation '@" + getName() + "' is specified to have a value but "
 296  
                             + "no value is defined (" + tag.position().file() + ":" + tag.position().line() + ":"
 297  
                             + tag.position().column() + ")" );
 298  0
                         sb.append( "<DD>" ).append( "NOT DEFINED" );
 299  
                     }
 300  
                 }
 301  
                 else
 302  
                 {
 303  0
                     List<String> l = getOnlyValues( getAllowedValue() );
 304  0
                     if ( isNotEmpty( tagValue ) )
 305  
                     {
 306  0
                         if ( l.contains( tagValue ) )
 307  
                         {
 308  0
                             sb.append( "<DD>" ).append( tagValue );
 309  
                         }
 310  
                         else
 311  
                         {
 312  0
                             System.err.println( "The annotation '@" + getName() + "' is specified to be a value in "
 313  
                                 + l + " (" + tag.position().file() + ":" + tag.position().line() + ":"
 314  
                                 + tag.position().column() + ")" );
 315  0
                             sb.append( "<DD>" ).append( tagValue );
 316  
                         }
 317  
                     }
 318  
                     else
 319  
                     {
 320  0
                         sb.append( "<DD>" ).append( l.get( 0 ) );
 321  
                     }
 322  0
                 }
 323  
             }
 324  
             else
 325  
             {
 326  0
                 if ( isNotEmpty( tagValue ) )
 327  
                 {
 328  0
                     System.err.println( "The annotation '@" + getName() + "' should have no value ("
 329  
                         + tag.position().file() + ":" + tag.position().line() + ":" + tag.position().column() + ")" );
 330  
                 }
 331  0
                 sb.append( "<DT><B>" ).append( getHeader() ).append( ":</B></DT>" );
 332  0
                 sb.append( "<DD>" );
 333  
             }
 334  
 
 335  0
             appendAnnotationParameters( sb, tagAttributes );
 336  0
             sb.append( "</DD>" );
 337  
         }
 338  0
     }
 339  
 
 340  
     /**
 341  
      * Append the annotation parameters as a definition list.
 342  
      *
 343  
      * @param sb not null
 344  
      * @param att not null
 345  
      */
 346  
     private static void appendAnnotationParameters( StringBuilder sb, MutableAttributeSet att )
 347  
     {
 348  0
         sb.append( "<DL>" );
 349  
 
 350  0
         Enumeration<?> names = att.getAttributeNames();
 351  0
         while ( names.hasMoreElements() )
 352  
         {
 353  0
             Object key = names.nextElement();
 354  0
             Object value = att.getAttribute( key );
 355  
 
 356  0
             if ( value instanceof AttributeSet )
 357  
             {
 358  
                 // ignored
 359  
             }
 360  
             else
 361  
             {
 362  0
                 sb.append( "<DT><B>" ).append( key ).append( ":</B></DT>" );
 363  0
                 sb.append( "<DD>" ).append( value ).append( "</DD>" );
 364  
             }
 365  0
         }
 366  
 
 367  0
         sb.append( "</DL>" );
 368  0
     }
 369  
 
 370  
     /**
 371  
      * @param text not null
 372  
      * @return <code>true</code> if text contains <code>*</code>, <code>false</code> otherwise.
 373  
      */
 374  
     private static boolean isEveryValues( String text )
 375  
     {
 376  0
         return text.trim().equals( "*" );
 377  
     }
 378  
 
 379  
     /**
 380  
      * Splits the provided text into a array, using pipe as the separator.
 381  
      *
 382  
      * @param text not null
 383  
      * @return a list of parsed Strings or <code>Collections.EMPTY_LIST</code>.
 384  
      * By convention, the default value is the first element.
 385  
      */
 386  
     private static List<String> getOnlyValues( String text )
 387  
     {
 388  0
         if ( text.indexOf( '|' ) == -1 )
 389  
         {
 390  0
             return Collections.emptyList();
 391  
         }
 392  
 
 393  0
         List<String> l = new ArrayList<String>();
 394  0
         StringTokenizer token = new StringTokenizer( text, "|" );
 395  0
         while ( token.hasMoreTokens() )
 396  
         {
 397  0
             l.add( token.nextToken() );
 398  
         }
 399  
 
 400  0
         return l;
 401  
     }
 402  
 
 403  
     /**
 404  
      * <p>Checks if a String is non <code>null</code> and is
 405  
      * not empty (<code>length > 0</code>).</p>
 406  
      *
 407  
      * @param str the String to check
 408  
      * @return true if the String is non-null, and not length zero
 409  
      */
 410  
     private static boolean isNotEmpty( String str )
 411  
     {
 412  0
         return ( str != null && str.length() > 0 );
 413  
     }
 414  
 
 415  
     /**
 416  
      * <p>Checks if a (trimmed) String is <code>null</code> or empty.</p>
 417  
      *
 418  
      * @param str the String to check
 419  
      * @return <code>true</code> if the String is <code>null</code>, or
 420  
      *  length zero once trimmed
 421  
      */
 422  
     private static boolean isEmpty( String str )
 423  
     {
 424  0
         return ( str == null || str.trim().length() == 0 );
 425  
     }
 426  
 }