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