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