View Javadoc

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