Coverage Report - org.apache.maven.plugin.jira.AbstractJiraDownloader
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractJiraDownloader
0%
0/270
0%
0/146
3,433
 
 1  
 package org.apache.maven.plugin.jira;
 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 org.apache.commons.httpclient.Credentials;
 23  
 import org.apache.commons.httpclient.Header;
 24  
 import org.apache.commons.httpclient.HostConfiguration;
 25  
 import org.apache.commons.httpclient.HttpClient;
 26  
 import org.apache.commons.httpclient.HttpException;
 27  
 import org.apache.commons.httpclient.HttpState;
 28  
 import org.apache.commons.httpclient.HttpStatus;
 29  
 import org.apache.commons.httpclient.StatusLine;
 30  
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 31  
 import org.apache.commons.httpclient.params.HttpClientParams;
 32  
 import org.apache.commons.httpclient.auth.AuthScope;
 33  
 import org.apache.commons.httpclient.methods.GetMethod;
 34  
 import org.apache.maven.plugin.logging.Log;
 35  
 import org.apache.maven.project.MavenProject;
 36  
 import org.apache.maven.settings.Proxy;
 37  
 import org.apache.maven.settings.Settings;
 38  
 import org.apache.maven.wagon.proxy.ProxyInfo;
 39  
 import org.codehaus.plexus.util.IOUtil;
 40  
 import org.codehaus.plexus.util.StringUtils;
 41  
 
 42  
 import java.io.File;
 43  
 import java.io.FileOutputStream;
 44  
 import java.io.IOException;
 45  
 import java.io.InputStream;
 46  
 import java.io.OutputStream;
 47  
 import java.net.URLEncoder;
 48  
 import java.util.Collections;
 49  
 import java.util.HashMap;
 50  
 import java.util.List;
 51  
 import java.util.Locale;
 52  
 import java.util.Map;
 53  
 
 54  
 /**
 55  
  * Gets relevant issues in RSS from a given JIRA installation.
 56  
  * <p/>
 57  
  * Based on version 1.1.2 and patch by Dr. Spock (MPJIRA-8).
 58  
  *
 59  
  * @author mfranken@xebia.com
 60  
  * @author jruiz@exist.com
 61  
  * @version $Id: org.apache.maven.plugin.jira.AbstractJiraDownloader.html 816598 2012-05-08 12:46:49Z hboutemy $
 62  
  */
 63  0
 public abstract class AbstractJiraDownloader
 64  
 {
 65  
     private static final String UTF_8 = "UTF-8";
 66  
 
 67  
     /** Log for debug output. */
 68  
     private Log log;
 69  
     /** Output file for xml document. */
 70  
     private File output;
 71  
     /** The maximum number of entries to show. */
 72  
     private int nbEntriesMax;
 73  
     /** The filter to apply to query to JIRA. */
 74  
     private String filter;
 75  
     /** Ids of fix versions to show, as comma separated string. */
 76  
     private String fixVersionIds;
 77  
     /** Ids of status to show, as comma separated string. */
 78  
     private String statusIds;
 79  
     /** Ids of resolution to show, as comma separated string. */
 80  
     private String resolutionIds;
 81  
     /** Ids of priority to show, as comma separated string. */
 82  
     private String priorityIds;
 83  
     /** The component to show. */
 84  
     private String component;
 85  
     /** Ids of types to show, as comma separated string. */
 86  
     private String typeIds;
 87  
     /** Column names to sort by, as comma separated string. */
 88  
     private String sortColumnNames;
 89  
     /** The username to log into JIRA. */
 90  
     private String jiraUser;
 91  
     /** The password to log into JIRA. */
 92  
     private String jiraPassword;
 93  
     /** The username to log into webserver. */
 94  
     private String webUser;
 95  
     /** The password to log into webserver. */
 96  
     private String webPassword;
 97  
     /** The maven project. */
 98  
     private MavenProject project;
 99  
     /** The maven settings. */
 100  
     private Settings settings;
 101  
     /** Mapping containing all allowed JIRA status values. */
 102  0
     protected final Map statusMap = new HashMap( 8 );
 103  
     /** Mapping containing all allowed JIRA resolution values. */
 104  0
     protected final Map resolutionMap = new HashMap( 8 );
 105  
     /** Mapping containing all allowed JIRA priority values. */
 106  0
     protected final Map priorityMap = new HashMap( 8 );
 107  
     /** Mapping containing all allowed JIRA type values. */
 108  0
     protected final Map typeMap = new HashMap( 8 );
 109  
     /** The pattern used to parse dates from the JIRA xml file. */
 110  
     private String jiraDatePattern;
 111  
 
 112  
     /**
 113  
      * Creates a filter given the parameters and some defaults.
 114  
      *
 115  
      * @return request parameters to be added to URL used for downloading the JIRA issues
 116  
      */
 117  
     private String createFilter()
 118  
     {
 119  
         // If the user has defined a filter - use that
 120  0
         if ( ( this.filter != null ) && ( this.filter.length() > 0 ) )
 121  
         {
 122  0
             return this.filter;
 123  
         }
 124  
 
 125  0
         StringBuffer localFilter = new StringBuffer( 16 );
 126  
 
 127  
         // add fix versions
 128  0
         if ( fixVersionIds != null )
 129  
         {
 130  0
             String[] fixVersions = fixVersionIds.split( "," );
 131  
 
 132  0
             for ( int i = 0; i < fixVersions.length; i++ )
 133  
             {
 134  0
                 if ( fixVersions[i].length() > 0 )
 135  
                 {
 136  0
                     localFilter.append( "&fixfor=" ).append( fixVersions[i].trim() );
 137  
                 }
 138  
             }
 139  
         }
 140  
 
 141  
         // get the Status Ids
 142  0
         if ( statusIds != null )
 143  
         {
 144  0
             String[] stats = statusIds.split( "," );
 145  
 
 146  0
             for ( int i = 0; i < stats.length; i++ )
 147  
             {
 148  0
                 String statusParam = (String) statusMap.get( stats[i] );
 149  
 
 150  0
                 if ( statusParam != null )
 151  
                 {
 152  0
                     localFilter.append( "&statusIds=" ).append( statusParam );
 153  
                 }
 154  
             }
 155  
         }
 156  
 
 157  
         // get the Priority Ids
 158  0
         if ( priorityIds != null )
 159  
         {
 160  0
             String[] prios = priorityIds.split( "," );
 161  
 
 162  0
             for ( int i = 0; i < prios.length; i++ )
 163  
             {
 164  0
                 String priorityParam = (String) priorityMap.get( prios[i] );
 165  
 
 166  0
                 if ( priorityParam != null )
 167  
                 {
 168  0
                     localFilter.append( "&priorityIds=" ).append( priorityParam );
 169  
                 }
 170  
             }
 171  
         }
 172  
 
 173  
         // get the Resolution Ids
 174  0
         if ( resolutionIds != null )
 175  
         {
 176  0
             String[] resos = resolutionIds.split( "," );
 177  
 
 178  0
             for ( int i = 0; i < resos.length; i++ )
 179  
             {
 180  0
                 String resoParam = (String) resolutionMap.get( resos[i] );
 181  
 
 182  0
                 if ( resoParam != null )
 183  
                 {
 184  0
                     localFilter.append( "&resolutionIds=" ).append( resoParam );
 185  
                 }
 186  
             }
 187  
         }
 188  
 
 189  
         // add components
 190  0
         if ( component != null )
 191  
         {
 192  0
             String[] components = component.split( "," );
 193  
 
 194  0
             for ( int i = 0; i < components.length; i++ )
 195  
             {
 196  0
                 if ( components[i].length() > 0 )
 197  
                 {
 198  0
                     localFilter.append( "&component=" ).append( components[i] );
 199  
                 }
 200  
             }
 201  
         }
 202  
 
 203  
         // get the Type Ids
 204  0
         if ( typeIds != null )
 205  
         {
 206  0
             String[] types = typeIds.split( "," );
 207  
 
 208  0
             for ( int i = 0; i < types.length; i++ )
 209  
             {
 210  0
                 String typeParam = (String) typeMap.get( types[i].trim() );
 211  
 
 212  0
                 if ( typeParam != null )
 213  
                 {
 214  0
                     localFilter.append( "&type=" ).append( typeParam );
 215  
                 }
 216  
             }
 217  
         }
 218  
 
 219  
         // get the Sort order
 220  0
         int validSortColumnNames = 0;
 221  0
         if ( sortColumnNames != null )
 222  
         {
 223  0
             String[] sortColumnNamesArray = sortColumnNames.split( "," );
 224  
             // N.B. Add in reverse order (it's the way JIRA 3 likes it!!)
 225  0
             for ( int i = sortColumnNamesArray.length - 1; i >= 0; i-- )
 226  
             {
 227  0
                 String lowerColumnName = sortColumnNamesArray[i].trim().toLowerCase( Locale.ENGLISH );
 228  0
                 boolean descending = false;
 229  0
                 String fieldName = null;
 230  0
                 if ( lowerColumnName.endsWith( "desc" ) )
 231  
                 {
 232  0
                     descending = true;
 233  0
                     lowerColumnName = lowerColumnName.substring( 0, lowerColumnName.length() - 4 ).trim();
 234  
                 }
 235  0
                 else if ( lowerColumnName.endsWith( "asc" ) )
 236  
                 {
 237  0
                     descending = false;
 238  0
                     lowerColumnName = lowerColumnName.substring( 0, lowerColumnName.length() - 3 ).trim();
 239  
                 }
 240  
 
 241  0
                 if ( "key".equals( lowerColumnName ) )
 242  
                 {
 243  0
                     fieldName = "issuekey";
 244  
                 }
 245  0
                 else if ( "summary".equals( lowerColumnName ) )
 246  
                 {
 247  0
                     fieldName = lowerColumnName;
 248  
                 }
 249  0
                 else if ( "status".equals( lowerColumnName ) )
 250  
                 {
 251  0
                     fieldName = lowerColumnName;
 252  
                 }
 253  0
                 else if ( "resolution".equals( lowerColumnName ) )
 254  
                 {
 255  0
                     fieldName = lowerColumnName;
 256  
                 }
 257  0
                 else if ( "assignee".equals( lowerColumnName ) )
 258  
                 {
 259  0
                     fieldName = lowerColumnName;
 260  
                 }
 261  0
                 else if ( "reporter".equals( lowerColumnName ) )
 262  
                 {
 263  0
                     fieldName = lowerColumnName;
 264  
                 }
 265  0
                 else if ( "type".equals( lowerColumnName ) )
 266  
                 {
 267  0
                     fieldName = "issuetype";
 268  
                 }
 269  0
                 else if ( "priority".equals( lowerColumnName ) )
 270  
                 {
 271  0
                     fieldName = lowerColumnName;
 272  
                 }
 273  0
                 else if ( "version".equals( lowerColumnName ) )
 274  
                 {
 275  0
                     fieldName = "versions";
 276  
                 }
 277  0
                 else if ( "fix version".equals( lowerColumnName ) )
 278  
                 {
 279  0
                     fieldName = "fixVersions";
 280  
                 }
 281  0
                 else if ( "component".equals( lowerColumnName ) )
 282  
                 {
 283  0
                     fieldName = "components";
 284  
                 }
 285  0
                 else if ( "created".equals( lowerColumnName ) )
 286  
                 {
 287  0
                     fieldName = lowerColumnName;
 288  
                 }
 289  0
                 else if ( "updated".equals( lowerColumnName ) )
 290  
                 {
 291  0
                     fieldName = lowerColumnName;
 292  
                 }
 293  0
                 if ( fieldName != null )
 294  
                 {
 295  0
                     localFilter.append( "&sorter/field=" );
 296  0
                     localFilter.append( fieldName );
 297  0
                     localFilter.append( "&sorter/order=" );
 298  0
                     localFilter.append( descending ? "DESC" : "ASC" );
 299  0
                     validSortColumnNames++;
 300  
                 }
 301  
                 else
 302  
                 {
 303  
                     // Error in the configuration
 304  0
                     getLog().error(
 305  
                         "maven-changes-plugin: The configured value '" + lowerColumnName
 306  
                             + "' for sortColumnNames is not correct." );
 307  
                 }
 308  
             }
 309  
         }
 310  0
         if ( validSortColumnNames == 0 )
 311  
         {
 312  
             // Error in the configuration
 313  0
             getLog().error(
 314  
                 "maven-changes-plugin: None of the configured sortColumnNames '" + sortColumnNames + "' are correct." );
 315  
         }
 316  
 
 317  
 
 318  0
         return localFilter.toString();
 319  
     }
 320  
 
 321  
     /**
 322  
      * Execute the query on the JIRA server.
 323  
      *
 324  
      * @throws Exception on error
 325  
      */
 326  
     public void doExecute()
 327  
         throws Exception
 328  
     {
 329  
         try
 330  
         {
 331  0
             HttpClient client = new HttpClient();
 332  
 
 333  
             // MCHANGES-89 Allow circular redirects
 334  0
             HttpClientParams clientParams = client.getParams();
 335  0
             clientParams.setBooleanParameter( HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true );
 336  
 
 337  0
             HttpState state = new HttpState();
 338  
 
 339  0
             HostConfiguration hc = new HostConfiguration();
 340  
 
 341  0
             client.setHostConfiguration( hc );
 342  
 
 343  0
             client.setState( state );
 344  
 
 345  0
             Map urlMap = JiraHelper.getJiraUrlAndProjectId( project.getIssueManagement().getUrl() );
 346  
 
 347  0
             String jiraUrl = (String) urlMap.get( "url" );
 348  0
             getLog().debug( "JIRA lives at: " + jiraUrl );
 349  
 
 350  0
             String jiraId = (String) urlMap.get( "id" );
 351  
 
 352  0
             determineProxy( jiraUrl, client );
 353  
 
 354  0
             prepareBasicAuthentication( client );
 355  
 
 356  0
             boolean jiraAuthenticationSuccessful = false;
 357  0
             if ( isJiraAuthenticationConfigured() )
 358  
             {
 359  0
                 jiraAuthenticationSuccessful = doJiraAuthentication( client, jiraUrl );
 360  
             }
 361  
 
 362  0
             if ( ( isJiraAuthenticationConfigured() && jiraAuthenticationSuccessful )
 363  
                 || !isJiraAuthenticationConfigured() )
 364  
             {
 365  0
                 if ( jiraId == null || jiraId.length() == 0 )
 366  
                 {
 367  0
                     log.debug( "The JIRA URL " + project.getIssueManagement().getUrl()
 368  
                         + " doesn't include a pid, trying to extract it from JIRA." );
 369  0
                     jiraId = JiraHelper.getPidFromJira( log, project.getIssueManagement().getUrl(), client );
 370  
                 }
 371  
 
 372  0
                 if ( jiraId == null )
 373  
                 {
 374  0
                     getLog().error( "The issue management URL in the POM does not include a pid,"
 375  
                         + " and it was not possible to extract it from the page at that URL." );
 376  
                 }
 377  
                 else
 378  
                 {
 379  
                     // create the URL for getting the proper issues from JIRA
 380  0
                     String fullURL = jiraUrl + "/secure/IssueNavigator.jspa?view=rss&pid=" + jiraId;
 381  
 
 382  0
                     if ( getFixFor() != null )
 383  
                     {
 384  0
                         fullURL += "&fixfor=" + getFixFor();
 385  
                     }
 386  
 
 387  0
                     String createdFilter = createFilter();
 388  0
                     if ( createdFilter.charAt( 0 ) != '&' )
 389  
                     {
 390  0
                         fullURL += "&";
 391  
                     }
 392  0
                     fullURL += createdFilter;
 393  
 
 394  0
                     fullURL += ( "&tempMax=" + nbEntriesMax + "&reset=true&decorator=none" );
 395  
 
 396  0
                     if ( log.isDebugEnabled() )
 397  
                     {
 398  0
                         log.debug( "download jira issues from url " + fullURL );
 399  
                     }
 400  
 
 401  
                     // execute the GET
 402  0
                     download( client, fullURL );
 403  
                 }
 404  
             }
 405  
         }
 406  0
         catch ( Exception e )
 407  
         {
 408  0
             getLog().error( "Error accessing " + project.getIssueManagement().getUrl(), e );
 409  0
         }
 410  0
     }
 411  
 
 412  
     /**
 413  
      * Override this method if you need to get issues for a specific Fix For.
 414  
      *
 415  
      * @return A Fix For id or <code>null</code> if you don't have that need
 416  
      */
 417  
     protected String getFixFor()
 418  
     {
 419  0
         return null;
 420  
     }
 421  
 
 422  
     /**
 423  
      * Check and prepare for basic authentication.
 424  
      *
 425  
      * @param client The client to prepare
 426  
      */
 427  
     private void prepareBasicAuthentication( HttpClient client )
 428  
     {
 429  0
         if ( ( webUser != null ) && ( webUser.length() > 0 ) )
 430  
         {
 431  0
             client.getParams().setAuthenticationPreemptive( true );
 432  
 
 433  0
             Credentials defaultcreds = new UsernamePasswordCredentials( webUser, webPassword );
 434  
 
 435  0
             getLog().debug( "Using username: " + webUser + " for Basic Authentication." );
 436  
 
 437  0
             client.getState().setCredentials( new AuthScope( null, AuthScope.ANY_PORT, null, AuthScope.ANY_SCHEME ),
 438  
                                               defaultcreds );
 439  
         }
 440  0
     }
 441  
 
 442  
     /**
 443  
      * Authenticate against JIRA. This method relies on jiraUser and
 444  
      * jiraPassword being set. You can check this by calling
 445  
      * isJiraAuthenticationConfigured().
 446  
      *
 447  
      * @param client    the HttpClient
 448  
      * @param jiraUrl   the JIRA installation
 449  
      * @return <code>true</code> if the authentication was successful, otherwise <code>false</code>
 450  
      */
 451  
     private boolean doJiraAuthentication( HttpClient client, final String jiraUrl )
 452  
     {
 453  
         // log into JIRA if we have to
 454  0
         String loginUrl = null;
 455  
 
 456  0
         StringBuffer loginLink = new StringBuffer( jiraUrl );
 457  
 
 458  0
         loginLink.append( "/login.jsp?os_destination=/secure/" );
 459  
 
 460  
         try
 461  
         {
 462  0
             loginLink.append( "&os_username=" ).append( URLEncoder.encode( jiraUser, UTF_8 ) );
 463  
 
 464  0
             String password = null;
 465  0
             if ( jiraPassword != null )
 466  
             {
 467  0
                 password = StringUtils.repeat( "*", jiraPassword.length() );
 468  
             }
 469  0
             getLog().debug( "Login URL: " + loginLink + "&os_password=" + password );
 470  
 
 471  0
             loginLink.append( "&os_password=" ).append( URLEncoder.encode( jiraPassword, UTF_8 ) );
 472  
 
 473  0
             loginUrl = loginLink.toString();
 474  
 
 475  
             // execute the login
 476  0
             GetMethod loginGet = new GetMethod( loginUrl );
 477  
 
 478  0
             client.executeMethod( loginGet );
 479  
 
 480  0
             if ( loginSucceeded( loginGet ) )
 481  
             {
 482  0
                 getLog().debug( "Successfully logged in into JIRA." );
 483  0
                 return true;
 484  
             }
 485  
             else
 486  
             {
 487  0
                 getLog().warn( "Was unable to login into JIRA: wrong username and/or password." );
 488  
             }
 489  
         }
 490  0
         catch ( Exception e )
 491  
         {
 492  0
             if ( getLog().isDebugEnabled() )
 493  
             {
 494  0
                 getLog().error( "Error trying to login into JIRA.", e );
 495  
             }
 496  
             else
 497  
             {
 498  0
                 getLog().error( "Error trying to login into JIRA. Cause is: " + e.getLocalizedMessage() );
 499  
             }
 500  0
         }
 501  0
         return false;
 502  
     }
 503  
 
 504  
     /**
 505  
      * Check to see if we think that JIRA authentication is needed.
 506  
      *
 507  
      * @return <code>true</code> if jiraUser and jiraPassword are set, otherwise <code>false</code>
 508  
      */
 509  
     private boolean isJiraAuthenticationConfigured()
 510  
     {
 511  0
         return ( jiraUser != null ) && ( jiraUser.length() > 0 ) && ( jiraPassword != null );
 512  
     }
 513  
 
 514  
     /**
 515  
      * Evaluate if the login attempt to JIRA was successful or not. We can't
 516  
      * use the status code because JIRA returns 200 even if the login fails.
 517  
      *
 518  
      * @param loginGet The method that was executed
 519  
      * @return <code>false</code> if we find an error message in the response body, otherwise <code>true</code>
 520  
      * @todo There must be a nicer way to know whether we were able to login or not
 521  
      */
 522  
     private boolean loginSucceeded( GetMethod loginGet )
 523  
         throws IOException
 524  
     {
 525  0
         final String loginFailureResponse = "your username and password are incorrect";
 526  
 
 527  0
         return loginGet.getResponseBodyAsString().indexOf( loginFailureResponse ) == -1;
 528  
     }
 529  
 
 530  
     /**
 531  
      * Setup proxy access if we have to.
 532  
      *
 533  
      * @param client  the HttpClient
 534  
      */
 535  
     private void determineProxy( String jiraUrl, HttpClient client )
 536  
     {
 537  
         // see whether there is any proxy defined in maven
 538  0
         Proxy proxy = null;
 539  
 
 540  0
         String proxyHost = null;
 541  
 
 542  0
         int proxyPort = 0;
 543  
 
 544  0
         String proxyUser = null;
 545  
 
 546  0
         String proxyPass = null;
 547  
 
 548  0
         if ( project == null )
 549  
         {
 550  0
             getLog().error( "No project set. No proxy info available." );
 551  
 
 552  0
             return;
 553  
         }
 554  
 
 555  0
         if ( settings != null )
 556  
         {
 557  0
             proxy = settings.getActiveProxy();
 558  
         }
 559  
 
 560  0
         if ( proxy != null )
 561  
         {
 562  
 
 563  0
             ProxyInfo proxyInfo = new ProxyInfo();
 564  0
             proxyInfo.setNonProxyHosts( proxy.getNonProxyHosts() );
 565  
 
 566  
             // Validation of proxy method copied from org.apache.maven.wagon.proxy.ProxyUtils.
 567  
             // @todo Can use original when maven-changes-plugin references a more recent version of maven-project
 568  
 
 569  
             //if ( ProxyUtils.validateNonProxyHosts( proxyInfo, jiraUrl  ) )
 570  0
             if ( JiraHelper.validateNonProxyHosts( proxyInfo, jiraUrl  ) )
 571  
             {
 572  0
                 return;
 573  
             }
 574  
 
 575  0
             proxyHost = settings.getActiveProxy().getHost();
 576  
 
 577  0
             proxyPort = settings.getActiveProxy().getPort();
 578  
 
 579  0
             proxyUser = settings.getActiveProxy().getUsername();
 580  
 
 581  0
             proxyPass = settings.getActiveProxy().getPassword();
 582  
 
 583  0
             getLog().debug( proxyPass );
 584  
         }
 585  
 
 586  0
         if ( proxyHost != null )
 587  
         {
 588  0
             client.getHostConfiguration().setProxy( proxyHost, proxyPort );
 589  
 
 590  0
             getLog().debug( "Using proxy: " + proxyHost + " at port " + proxyPort );
 591  
 
 592  0
             if ( proxyUser != null )
 593  
             {
 594  0
                 getLog().debug( "Using proxy user: " + proxyUser );
 595  
 
 596  0
                 client.getState().setProxyCredentials(
 597  
                                                        new AuthScope( null, AuthScope.ANY_PORT, null,
 598  
                                                                       AuthScope.ANY_SCHEME ),
 599  
                                                        new UsernamePasswordCredentials( proxyUser, proxyPass ) );
 600  
             }
 601  
         }
 602  0
     }
 603  
 
 604  
     /**
 605  
      * Downloads the given link using the configured HttpClient, possibly following redirects.
 606  
      *
 607  
      * @param cl     the HttpClient
 608  
      * @param link   the URL to JIRA
 609  
      */
 610  
     private void download( final HttpClient cl, final String link )
 611  
     {
 612  
         try
 613  
         {
 614  0
             GetMethod gm = new GetMethod( link );
 615  
 
 616  0
             getLog().info( "Downloading from JIRA at: " + link );
 617  
 
 618  0
             gm.setFollowRedirects( true );
 619  
 
 620  0
             cl.executeMethod( gm );
 621  
 
 622  0
             StatusLine sl = gm.getStatusLine();
 623  
 
 624  0
             if ( sl == null )
 625  
             {
 626  0
                 getLog().error( "Unknown error validating link: " + link );
 627  
 
 628  0
                 return;
 629  
             }
 630  
 
 631  
             // if we get a redirect, do so
 632  0
             if ( gm.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY )
 633  
             {
 634  0
                 Header locationHeader = gm.getResponseHeader( "Location" );
 635  
 
 636  0
                 if ( locationHeader == null )
 637  
                 {
 638  0
                     getLog().warn( "Site sent redirect, but did not set Location header" );
 639  
                 }
 640  
                 else
 641  
                 {
 642  0
                     String newLink = locationHeader.getValue();
 643  
 
 644  0
                     getLog().debug( "Following redirect to " + newLink );
 645  
 
 646  0
                     download( cl, newLink );
 647  
                 }
 648  
             }
 649  
 
 650  0
             if ( gm.getStatusCode() == HttpStatus.SC_OK )
 651  
             {
 652  0
                 final InputStream responseBodyStream = gm.getResponseBodyAsStream();
 653  
 
 654  0
                 if ( !output.getParentFile().exists() )
 655  
                 {
 656  0
                     output.getParentFile().mkdirs();
 657  
                 }
 658  
 
 659  
                 // write the response to file
 660  0
                 OutputStream out = null;
 661  
                 try
 662  
                 {
 663  0
                     out = new FileOutputStream( output );
 664  0
                     IOUtil.copy( responseBodyStream, out );
 665  
                 }
 666  
                 finally
 667  
                 {
 668  0
                     IOUtil.close( out );
 669  0
                     IOUtil.close( responseBodyStream );
 670  0
                 }
 671  
 
 672  0
                 getLog().debug( "Downloading from JIRA was successful" );
 673  0
             }
 674  
             else
 675  
             {
 676  0
                 getLog().warn( "Downloading from JIRA failed. Received: [" + gm.getStatusCode() + "]" );
 677  
             }
 678  
         }
 679  0
         catch ( HttpException e )
 680  
         {
 681  0
             if ( getLog().isDebugEnabled() )
 682  
             {
 683  0
                 getLog().error( "Error downloading issues from JIRA:", e );
 684  
             }
 685  
             else
 686  
             {
 687  0
                 getLog().error( "Error downloading issues from JIRA url: " + e.getLocalizedMessage() );
 688  
 
 689  
             }
 690  
         }
 691  0
         catch ( IOException e )
 692  
         {
 693  0
             if ( getLog().isDebugEnabled() )
 694  
             {
 695  0
                 getLog().error( "Error downloading issues from JIRA:", e );
 696  
             }
 697  
             else
 698  
             {
 699  0
                 getLog().error( "Error downloading issues from JIRA. Cause is " + e.getLocalizedMessage() );
 700  
             }
 701  0
         }
 702  0
     }
 703  
 
 704  
     public List getIssueList()
 705  
     {
 706  0
         if ( output.isFile() )
 707  
         {
 708  0
             JiraXML jira = new JiraXML( log, jiraDatePattern );
 709  0
             jira.parseXML( output );
 710  0
             getLog().info( "The JIRA version is '" + jira.getJiraVersion() + "'" );
 711  0
             return jira.getIssueList();
 712  
         }
 713  
         else
 714  
         {
 715  0
             getLog().warn( "JIRA file " + output.getPath() + " doesn't exist." );
 716  0
             return Collections.EMPTY_LIST;
 717  
         }
 718  
     }
 719  
 
 720  
     public void setJiraDatePattern( String jiraDatePattern )
 721  
     {
 722  0
         this.jiraDatePattern = jiraDatePattern;
 723  0
     }
 724  
 
 725  
     /**
 726  
      * Set the output file for the log.
 727  
      *
 728  
      * @param thisOutput the output file
 729  
      */
 730  
     public void setOutput( File thisOutput )
 731  
     {
 732  0
         this.output = thisOutput;
 733  0
     }
 734  
 
 735  
     public File getOutput()
 736  
     {
 737  0
         return this.output;
 738  
     }
 739  
 
 740  
     /**
 741  
      * Sets the project.
 742  
      *
 743  
      * @param thisProject  The project to set
 744  
      */
 745  
     public void setMavenProject( Object thisProject )
 746  
     {
 747  0
         this.project = (MavenProject) thisProject;
 748  0
     }
 749  
 
 750  
     /**
 751  
      * Sets the maximum number of Issues to show.
 752  
      *
 753  
      * @param nbEntries  The maximum number of Issues
 754  
      */
 755  
     public void setNbEntries( final int nbEntries )
 756  
     {
 757  0
         nbEntriesMax = nbEntries;
 758  0
     }
 759  
 
 760  
     /**
 761  
      * Sets the statusIds.
 762  
      *
 763  
      * @param thisStatusIds   The id(s) of the status to show, as comma separated string
 764  
      */
 765  
     public void setStatusIds( String thisStatusIds )
 766  
     {
 767  0
         statusIds = thisStatusIds;
 768  0
     }
 769  
 
 770  
     /**
 771  
      * Sets the priorityIds.
 772  
      *
 773  
      * @param thisPriorityIds  The id(s) of the priority to show, as comma separated string
 774  
      */
 775  
     public void setPriorityIds( String thisPriorityIds )
 776  
     {
 777  0
         priorityIds = thisPriorityIds;
 778  0
     }
 779  
 
 780  
     /**
 781  
      * Sets the resolutionIds.
 782  
      *
 783  
      * @param thisResolutionIds  The id(s) of the resolution to show, as comma separated string
 784  
      */
 785  
     public void setResolutionIds( String thisResolutionIds )
 786  
     {
 787  0
         resolutionIds = thisResolutionIds;
 788  0
     }
 789  
 
 790  
     /**
 791  
      * Sets the sort column names.
 792  
      *
 793  
      * @param thisSortColumnNames The column names to sort by
 794  
      */
 795  
     public void setSortColumnNames( String thisSortColumnNames )
 796  
     {
 797  0
         sortColumnNames = thisSortColumnNames;
 798  0
     }
 799  
 
 800  
     /**
 801  
      * Sets the password for authentication against the webserver.
 802  
      *
 803  
      * @param thisWebPassword  The password of the webserver
 804  
      */
 805  
     public void setWebPassword( String thisWebPassword )
 806  
     {
 807  0
         this.webPassword = thisWebPassword;
 808  0
     }
 809  
 
 810  
     /**
 811  
      * Sets the username for authentication against the webserver.
 812  
      *
 813  
      * @param thisWebUser   The username of the webserver
 814  
      */
 815  
     public void setWebUser( String thisWebUser )
 816  
     {
 817  0
         this.webUser = thisWebUser;
 818  0
     }
 819  
 
 820  
     /**
 821  
      * Sets the password to log into a secured JIRA.
 822  
      *
 823  
      * @param thisJiraPassword  The password for JIRA
 824  
      */
 825  
     public void setJiraPassword( final String thisJiraPassword )
 826  
     {
 827  0
         this.jiraPassword = thisJiraPassword;
 828  0
     }
 829  
 
 830  
     /**
 831  
      * Sets the username to log into a secured JIRA.
 832  
      *
 833  
      * @param thisJiraUser  The username for JIRA
 834  
      */
 835  
     public void setJiraUser( String thisJiraUser )
 836  
     {
 837  0
         this.jiraUser = thisJiraUser;
 838  0
     }
 839  
 
 840  
     /**
 841  
      * Sets the filter to apply to query to JIRA.
 842  
      *
 843  
      * @param thisFilter  The filter to query JIRA
 844  
      */
 845  
     public void setFilter( String thisFilter )
 846  
     {
 847  0
         this.filter = thisFilter;
 848  0
     }
 849  
 
 850  
     /**
 851  
      * Sets the component(s) to apply to query JIRA.
 852  
      *
 853  
      * @param theseComponents   The id(s) of components to show, as comma separated string
 854  
      */
 855  
     public void setComponent( String theseComponents )
 856  
     {
 857  0
         this.component = theseComponents;
 858  0
     }
 859  
 
 860  
     /**
 861  
      * Sets the fix version id(s) to apply to query JIRA.
 862  
      *
 863  
      * @param theseFixVersionIds The id(s) of fix versions to show, as comma separated string
 864  
      */
 865  
     public void setFixVersionIds( String theseFixVersionIds )
 866  
     {
 867  0
         this.fixVersionIds = theseFixVersionIds;
 868  0
     }
 869  
 
 870  
     /**
 871  
      * Sets the typeIds.
 872  
      *
 873  
      * @param theseTypeIds  The id(s) of the types to show, as comma separated string
 874  
      */
 875  
     public void setTypeIds( String theseTypeIds )
 876  
     {
 877  0
         typeIds = theseTypeIds;
 878  0
     }
 879  
 
 880  
     public void setLog( Log log )
 881  
     {
 882  0
         this.log = log;
 883  0
     }
 884  
 
 885  
     private Log getLog()
 886  
     {
 887  0
         return log;
 888  
     }
 889  
 
 890  
     public void setSettings( Settings settings )
 891  
     {
 892  0
         this.settings = settings;
 893  0
     }
 894  
 }