Coverage Report - org.apache.maven.plugin.changes.ChangesReportGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
ChangesReportGenerator
0%
0/230
0%
0/92
2.323
 
 1  
 package org.apache.maven.plugin.changes;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.util.HashMap;
 24  
 import java.util.Iterator;
 25  
 import java.util.LinkedHashMap;
 26  
 import java.util.List;
 27  
 import java.util.Map;
 28  
 import java.util.ResourceBundle;
 29  
 
 30  
 import org.apache.commons.lang.StringUtils;
 31  
 import org.apache.maven.doxia.sink.Sink;
 32  
 import org.apache.maven.doxia.util.HtmlTools;
 33  
 import org.apache.maven.plugin.logging.Log;
 34  
 import org.apache.maven.plugins.changes.model.Action;
 35  
 import org.apache.maven.plugins.changes.model.DueTo;
 36  
 import org.apache.maven.plugins.changes.model.FixedIssue;
 37  
 import org.apache.maven.plugins.changes.model.Release;
 38  
 
 39  
 /**
 40  
  * Generates a changes report.
 41  
  *
 42  
  * @version $Id: org.apache.maven.plugin.changes.ChangesReportGenerator.html 816588 2012-05-08 12:37:27Z hboutemy $
 43  
  */
 44  
 public class ChangesReportGenerator
 45  
 {
 46  
 
 47  
     /**
 48  
      * The token in {@link #issueLink} denoting the base URL for the issue management.
 49  
      */
 50  
     private static final String URL_TOKEN = "%URL%";
 51  
 
 52  
     /**
 53  
      * The token in {@link #issueLink} denoting the issue ID.
 54  
      */
 55  
     private static final String ISSUE_TOKEN = "%ISSUE%";
 56  
 
 57  
     private static final String DEFAULT_ISSUE_SYSTEM_KEY = "default";
 58  
 
 59  
     private ChangesXML report;
 60  
 
 61  
     private String url;
 62  
 
 63  
     private Map issueLinksPerSystem;
 64  
 
 65  
     private boolean addActionDate;
 66  
 
 67  
     public ChangesReportGenerator()
 68  0
     {
 69  0
         issueLinksPerSystem = new HashMap();
 70  0
     }
 71  
 
 72  
     public ChangesReportGenerator( File xmlPath, Log log )
 73  
     {
 74  0
         this();
 75  0
         report = new ChangesXML( xmlPath, log );
 76  0
     }
 77  
 
 78  
     /**
 79  
      * @deprecated
 80  
      */
 81  
     public void setIssueLink( String issueLink )
 82  
     {
 83  0
         if ( this.issueLinksPerSystem == null )
 84  
         {
 85  0
             this.issueLinksPerSystem = new HashMap();
 86  
         }
 87  0
         this.issueLinksPerSystem.put( DEFAULT_ISSUE_SYSTEM_KEY, issueLink );
 88  0
     }
 89  
 
 90  
     /**
 91  
      * @deprecated
 92  
      */
 93  
     public String getIssueLink()
 94  
     {
 95  0
         return (String) issueLinksPerSystem.get( DEFAULT_ISSUE_SYSTEM_KEY );
 96  
     }
 97  
 
 98  
     public void setUrl( String url )
 99  
     {
 100  0
         this.url = url;
 101  0
     }
 102  
 
 103  
     public String getUrl()
 104  
     {
 105  0
         return url;
 106  
     }
 107  
 
 108  
     public Map getIssueLinksPerSystem()
 109  
     {
 110  0
         return issueLinksPerSystem;
 111  
     }
 112  
 
 113  
     public void setIssueLinksPerSystem( Map issueLinksPerSystem )
 114  
     {
 115  0
         if ( this.issueLinksPerSystem != null && issueLinksPerSystem == null )
 116  
         {
 117  0
             return;
 118  
         }
 119  0
         this.issueLinksPerSystem = issueLinksPerSystem;
 120  0
     }
 121  
 
 122  
     public boolean isAddActionDate()
 123  
     {
 124  0
         return addActionDate;
 125  
     }
 126  
 
 127  
     public void setAddActionDate( boolean addActionDate )
 128  
     {
 129  0
         this.addActionDate = addActionDate;
 130  0
     }
 131  
 
 132  
     /**
 133  
      * Checks whether links to the issues can be generated.
 134  
      *
 135  
      * @return <code>true</code> if issue links can be generated, <code>false</code> otherwise.
 136  
      */
 137  
     public boolean canGenerateIssueLinks( String system )
 138  
     {
 139  0
         if ( !this.issueLinksPerSystem.containsKey( system ) )
 140  
         {
 141  0
             return false;
 142  
         }
 143  0
         String issueLink = (String) this.issueLinksPerSystem.get( system );
 144  0
         return !StringUtils.isBlank( issueLink )
 145  
             && ( !StringUtils.isBlank( getUrl() ) || issueLink.indexOf( URL_TOKEN ) < 0 );
 146  
     }
 147  
 
 148  
     public boolean canGenerateIssueLinks()
 149  
     {
 150  0
         if ( this.issueLinksPerSystem == null || this.issueLinksPerSystem.isEmpty() )
 151  
         {
 152  0
             return false;
 153  
         }
 154  0
         return this.issueLinksPerSystem.containsKey( DEFAULT_ISSUE_SYSTEM_KEY );
 155  
     }
 156  
 
 157  
     public void doGenerateEmptyReport( ResourceBundle bundle, Sink sink, String message )
 158  
     {
 159  0
         sinkBeginReport( sink, bundle );
 160  
 
 161  0
         sink.text( message );
 162  
 
 163  0
         sinkEndReport( sink );
 164  0
     }
 165  
 
 166  
     public void doGenerateReport( ResourceBundle bundle, Sink sink )
 167  
     {
 168  0
         sinkBeginReport( sink, bundle );
 169  
 
 170  0
         constructReleaseHistory( sink, bundle );
 171  
 
 172  0
         constructReleases( sink, bundle );
 173  
 
 174  0
         sinkEndReport( sink );
 175  0
     }
 176  
 
 177  
     private void constructActions( Sink sink, List actionList, ResourceBundle bundle )
 178  
     {
 179  0
         sink.table();
 180  
 
 181  0
         sink.tableRow();
 182  
 
 183  0
         sinkHeader( sink, bundle.getString( "report.changes.label.type" ) );
 184  
 
 185  0
         sinkHeader( sink, bundle.getString( "report.changes.label.changes" ) );
 186  
 
 187  0
         sinkHeader( sink, bundle.getString( "report.changes.label.by" ) );
 188  
 
 189  0
         if ( this.isAddActionDate() )
 190  
         {
 191  0
             sinkHeader( sink, bundle.getString( "report.changes.label.date" ) );
 192  
         }
 193  0
         sink.tableRow_();
 194  
 
 195  0
         for ( int idx = 0; idx < actionList.size(); idx++ )
 196  
         {
 197  0
             Action action = (Action) actionList.get( idx );
 198  
 
 199  0
             sink.tableRow();
 200  
 
 201  0
             sinkShowTypeIcon( sink, action.getType() );
 202  
 
 203  0
             sink.tableCell();
 204  
 
 205  0
             sink.rawText( action.getAction() );
 206  
 
 207  
             // no null check needed classes from modello return a new ArrayList
 208  0
             if ( StringUtils.isNotEmpty( action.getIssue() ) || ( !action.getFixedIssues().isEmpty() ) )
 209  
             {
 210  0
                 sink.text( " " + bundle.getString( "report.changes.text.fixes" ) + " " );
 211  
 
 212  0
                 String system = action.getSystem();
 213  0
                 system = StringUtils.isEmpty( system ) ? DEFAULT_ISSUE_SYSTEM_KEY : system;
 214  0
                 if ( !canGenerateIssueLinks( system ) )
 215  
                 {
 216  0
                     constructIssueText( action.getIssue(), sink, action.getFixedIssues() );
 217  
                 }
 218  
                 else
 219  
                 {
 220  0
                     constructIssueLink( action.getIssue(), system, sink, action.getFixedIssues() );
 221  
                 }
 222  0
                 sink.text( "." );
 223  
             }
 224  
 
 225  0
             if ( StringUtils.isNotEmpty( action.getDueTo() ) || ( !action.getDueTos().isEmpty() ) )
 226  
             {
 227  0
                 constructDueTo( sink, action, bundle, action.getDueTos() );
 228  
             }
 229  
 
 230  0
             sink.tableCell_();
 231  
 
 232  0
             sinkCellLink( sink, action.getDev(), "team-list.html#" + action.getDev() );
 233  
 
 234  0
             if ( this.isAddActionDate() )
 235  
             {
 236  0
                 sinkCell( sink, action.getDate() );
 237  
             }
 238  
 
 239  0
             sink.tableRow_();
 240  
         }
 241  
 
 242  0
         sink.table_();
 243  0
     }
 244  
 
 245  
     private void constructReleaseHistory( Sink sink, ResourceBundle bundle )
 246  
     {
 247  0
         sink.section2();
 248  
 
 249  0
         sinkSectionTitle2Anchor( sink, bundle.getString( "report.changes.label.releasehistory" ), bundle
 250  
             .getString( "report.changes.label.releasehistory" ) );
 251  
 
 252  0
         List releaseList = report.getReleaseList();
 253  
 
 254  0
         sink.table();
 255  
 
 256  0
         sink.tableRow();
 257  
 
 258  0
         sinkHeader( sink, bundle.getString( "report.changes.label.version" ) );
 259  
 
 260  0
         sinkHeader( sink, bundle.getString( "report.changes.label.date" ) );
 261  
 
 262  0
         sinkHeader( sink, bundle.getString( "report.changes.label.description" ) );
 263  
 
 264  0
         sink.tableRow_();
 265  
 
 266  0
         for ( int idx = 0; idx < releaseList.size(); idx++ )
 267  
         {
 268  0
             Release release = (Release) releaseList.get( idx );
 269  
 
 270  0
             sink.tableRow();
 271  
 
 272  0
             sinkCellLink( sink, release.getVersion(), "#" + HtmlTools.encodeId( release.getVersion() ) );
 273  
 
 274  0
             sinkCell( sink, release.getDateRelease() );
 275  
 
 276  0
             sinkCell( sink, release.getDescription() );
 277  
 
 278  0
             sink.tableRow_();
 279  
         }
 280  
 
 281  0
         sink.table_();
 282  
 
 283  
         // @todo Temporarily commented out until MCHANGES-46 is completely solved
 284  
         //        sink.rawText( bundle.getString( "report.changes.text.rssfeed" ) );
 285  
         //        sink.text( " " );
 286  
         //        sink.link( "changes.rss" );
 287  
         //        sinkFigure( "images/rss.png", sink );
 288  
         //        sink.link_();
 289  
         //
 290  
         //        sink.lineBreak();
 291  
 
 292  0
         sink.section2_();
 293  0
     }
 294  
 
 295  
     private void constructReleases( Sink sink, ResourceBundle bundle )
 296  
     {
 297  0
         List releaseList = report.getReleaseList();
 298  
 
 299  0
         for ( int idx = 0; idx < releaseList.size(); idx++ )
 300  
         {
 301  0
             Release release = (Release) releaseList.get( idx );
 302  
 
 303  0
             sink.section2();
 304  
 
 305  0
             sinkSectionTitle2Anchor( sink, bundle.getString( "report.changes.label.release" ) + " "
 306  
                 + release.getVersion() + " - " + release.getDateRelease(), HtmlTools.encodeId( release.getVersion() ) );
 307  
 
 308  0
             constructActions( sink, release.getActions(), bundle );
 309  
 
 310  0
             sink.section2_();
 311  
         }
 312  0
     }
 313  
 
 314  
     private String parseIssueLink( String issue, String system )
 315  
     {
 316  
         String parseLink;
 317  0
         String issueLink = (String) this.issueLinksPerSystem.get( system );
 318  0
         parseLink = issueLink.replaceFirst( ISSUE_TOKEN, issue );
 319  
 
 320  0
         if ( parseLink.indexOf( URL_TOKEN ) >= 0 )
 321  
         {
 322  0
             String url = this.url.substring( 0, this.url.lastIndexOf( "/" ) );
 323  0
             parseLink = parseLink.replaceFirst( URL_TOKEN, url );
 324  
         }
 325  
 
 326  0
         return parseLink;
 327  
     }
 328  
 
 329  
     private void sinkBeginReport( Sink sink, ResourceBundle bundle )
 330  
     {
 331  0
         sink.head();
 332  0
         String title = null;
 333  0
         if ( report.getTitle() != null )
 334  
         {
 335  0
             title = report.getTitle();
 336  
         }
 337  
         else
 338  
         {
 339  0
             title = bundle.getString( "report.changes.header" );
 340  
         }
 341  0
         sink.title();
 342  0
         sink.text( title );
 343  0
         sink.title_();
 344  
 
 345  0
         if ( StringUtils.isNotEmpty( report.getAuthor() ) )
 346  
         {
 347  0
             sink.author();
 348  0
             sink.text( report.getAuthor() );
 349  0
             sink.author_();
 350  
         }
 351  
 
 352  0
         sink.head_();
 353  
 
 354  0
         sink.body();
 355  
 
 356  0
         sink.section1();
 357  
 
 358  0
         sinkSectionTitle1Anchor( sink, title, title );
 359  0
     }
 360  
 
 361  
     private void sinkCell( Sink sink, String text )
 362  
     {
 363  0
         sink.tableCell();
 364  
 
 365  0
         sink.text( text );
 366  
 
 367  0
         sink.tableCell_();
 368  0
     }
 369  
 
 370  
     private void sinkCellLink( Sink sink, String text, String link )
 371  
     {
 372  0
         sink.tableCell();
 373  
 
 374  0
         sinkLink( sink, text, link );
 375  
 
 376  0
         sink.tableCell_();
 377  0
     }
 378  
 
 379  
     private void sinkEndReport( Sink sink )
 380  
     {
 381  0
         sink.section1_();
 382  
 
 383  0
         sink.body_();
 384  
 
 385  0
         sink.flush();
 386  
 
 387  0
         sink.close();
 388  0
     }
 389  
 
 390  
     private void sinkFigure( String image, Sink sink, String altText )
 391  
     {
 392  0
         sink.figure();
 393  
 
 394  0
         sink.figureGraphics( image );
 395  
 
 396  0
         sink.figureCaption();
 397  
 
 398  0
         sink.text( altText );
 399  
 
 400  0
         sink.figureCaption_();
 401  
 
 402  0
         sink.figure_();
 403  0
     }
 404  
 
 405  
     private void sinkHeader( Sink sink, String header )
 406  
     {
 407  0
         sink.tableHeaderCell();
 408  
 
 409  0
         sink.text( header );
 410  
 
 411  0
         sink.tableHeaderCell_();
 412  0
     }
 413  
 
 414  
     private void sinkLink( Sink sink, String text, String link )
 415  
     {
 416  0
         sink.link( link );
 417  
 
 418  0
         sink.text( text );
 419  
 
 420  0
         sink.link_();
 421  0
     }
 422  
 
 423  
     private void sinkSectionTitle1Anchor( Sink sink, String text, String anchor )
 424  
     {
 425  0
         sink.sectionTitle1();
 426  0
         sink.anchor( anchor );
 427  0
         sink.anchor_();
 428  0
         sink.text( text );
 429  0
         sink.sectionTitle1_();
 430  0
     }
 431  
 
 432  
     private void sinkSectionTitle2Anchor( Sink sink, String text, String anchor )
 433  
     {
 434  0
         sink.sectionTitle2();
 435  0
         sink.anchor( anchor );
 436  0
         sink.anchor_();
 437  0
         sink.text( text );
 438  0
         sink.sectionTitle2_();
 439  0
     }
 440  
 
 441  
     private void sinkShowTypeIcon( Sink sink, String type )
 442  
     {
 443  0
         String image = "";
 444  0
         String altText = "";
 445  
 
 446  0
         if ( type == null )
 447  
         {
 448  0
             image = "images/icon_help_sml.gif";
 449  0
             altText = "?";
 450  
         }
 451  0
         else if ( type.equals( "fix" ) )
 452  
         {
 453  0
             image = "images/fix.gif";
 454  0
             altText = "fix";
 455  
         }
 456  0
         else if ( type.equals( "update" ) )
 457  
         {
 458  0
             image = "images/update.gif";
 459  0
             altText = "update";
 460  
         }
 461  0
         else if ( type.equals( "add" ) )
 462  
         {
 463  0
             image = "images/add.gif";
 464  0
             altText = "add";
 465  
         }
 466  0
         else if ( type.equals( "remove" ) )
 467  
         {
 468  0
             image = "images/remove.gif";
 469  0
             altText = "remove";
 470  
         }
 471  
 
 472  0
         sink.tableCell();
 473  
 
 474  0
         sinkFigure( image, sink, altText );
 475  
 
 476  0
         sink.tableCell_();
 477  0
     }
 478  
 
 479  
     /**
 480  
      * @param issue The issue specified by attributes
 481  
      * @param fixes The List of issues specified as fixes elements
 482  
      */
 483  
     private void constructIssueLink( String issue, String system, Sink sink, List fixes )
 484  
     {
 485  0
         if ( StringUtils.isNotEmpty( issue ) )
 486  
         {
 487  0
             sink.link( parseIssueLink( issue, system ) );
 488  
 
 489  0
             sink.text( issue );
 490  
 
 491  0
             sink.link_();
 492  
 
 493  0
             if ( !fixes.isEmpty() )
 494  
             {
 495  0
                 sink.text( ", " );
 496  
             }
 497  
         }
 498  
 
 499  0
         for ( Iterator iterator = fixes.iterator(); iterator.hasNext(); )
 500  
         {
 501  0
             FixedIssue fixedIssue = (FixedIssue) iterator.next();
 502  0
             String currentIssueId = fixedIssue.getIssue();
 503  0
             if ( StringUtils.isNotEmpty( currentIssueId ) )
 504  
             {
 505  0
                 sink.link( parseIssueLink( currentIssueId, system ) );
 506  
 
 507  0
                 sink.text( currentIssueId );
 508  
 
 509  0
                 sink.link_();
 510  
             }
 511  
 
 512  0
             if ( iterator.hasNext() )
 513  
             {
 514  0
                 sink.text( ", " );
 515  
             }
 516  
         }
 517  0
     }
 518  
 
 519  
     /**
 520  
      * @param issue The issue specified by attributes
 521  
      * @param fixes The List of issues specified as fixes elements
 522  
      */
 523  
     private void constructIssueText( String issue, Sink sink, List fixes )
 524  
     {
 525  0
         if ( StringUtils.isNotEmpty( issue ) )
 526  
         {
 527  0
             sink.text( issue );
 528  
 
 529  0
             if ( !fixes.isEmpty() )
 530  
             {
 531  0
                 sink.text( ", " );
 532  
             }
 533  
         }
 534  
 
 535  0
         for ( Iterator iterator = fixes.iterator(); iterator.hasNext(); )
 536  
         {
 537  0
             FixedIssue fixedIssue = (FixedIssue) iterator.next();
 538  
 
 539  0
             String currentIssueId = fixedIssue.getIssue();
 540  0
             if ( StringUtils.isNotEmpty( currentIssueId ) )
 541  
             {
 542  0
                 sink.text( currentIssueId );
 543  
             }
 544  
 
 545  0
             if ( iterator.hasNext() )
 546  
             {
 547  0
                 sink.text( ", " );
 548  
             }
 549  
         }
 550  0
     }
 551  
 
 552  
     /**
 553  
      *
 554  
      * @param sink
 555  
      * @param action
 556  
      * @param bundle
 557  
      */
 558  
     private void constructDueTo( Sink sink, Action action, ResourceBundle bundle, List dueTos )
 559  
     {
 560  
 
 561  
         // Create a Map with key : dueTo name, value : dueTo email
 562  0
         Map namesEmailMap = new LinkedHashMap();
 563  
 
 564  
         // Only add the dueTo specified as attributes, if it has either a dueTo or a dueToEmail
 565  0
         if ( StringUtils.isNotEmpty( action.getDueTo() ) || StringUtils.isNotEmpty( action.getDueToEmail() ) )
 566  
         {
 567  0
             namesEmailMap.put( action.getDueTo(), action.getDueToEmail() );
 568  
         }
 569  
 
 570  0
         for (Iterator iterator = dueTos.iterator();iterator.hasNext();)
 571  
         {
 572  0
             DueTo dueTo = (DueTo) iterator.next();
 573  0
             namesEmailMap.put( dueTo.getName(), dueTo.getEmail() );
 574  
         }
 575  
 
 576  0
         if (namesEmailMap.isEmpty())
 577  
         {
 578  0
             return;
 579  
         }
 580  
 
 581  0
         sink.text( " " + bundle.getString( "report.changes.text.thanx" ) + " " );
 582  0
         int i = 0;
 583  0
         for (Iterator iterator = namesEmailMap.keySet().iterator(); iterator.hasNext();)
 584  
         {
 585  0
             String currentDueTo = (String) iterator.next();
 586  0
             String currentDueToEmail = (String) namesEmailMap.get( currentDueTo );
 587  0
             i++;
 588  
 
 589  0
             if ( StringUtils.isNotEmpty( currentDueToEmail ) )
 590  
             {
 591  0
                 sinkLink( sink, currentDueTo, "mailto:" + currentDueToEmail );
 592  
             }
 593  0
             else if ( StringUtils.isNotEmpty( currentDueTo ) )
 594  
             {
 595  0
                 sink.text( currentDueTo );
 596  
             }
 597  
 
 598  0
             if ( i < namesEmailMap.size() )
 599  
             {
 600  0
                 sink.text( ", " );
 601  
             }
 602  
         }
 603  
 
 604  0
         sink.text( "." );
 605  0
     }
 606  
 
 607  
 }