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.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: AbstractJiraDownloader.html 816601 2012-05-08 12:50:18Z hboutemy $
65   */
66  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     protected final Map<String,String> statusMap = new HashMap<String,String>( 8 );
106     /** Mapping containing all allowed JIRA resolution values. */
107     protected final Map<String,String> resolutionMap = new HashMap<String,String>( 8 );
108     /** Mapping containing all allowed JIRA priority values. */
109     protected final Map<String,String> priorityMap = new HashMap<String,String>( 8 );
110     /** Mapping containing all allowed JIRA type values. */
111     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         if ( ( this.filter != null ) && ( this.filter.length() > 0 ) )
124         {
125             return this.filter;
126         }
127 
128         StringBuffer localFilter = new StringBuffer( 16 );
129 
130         // add fix versions
131         if ( fixVersionIds != null )
132         {
133             String[] fixVersions = fixVersionIds.split( "," );
134 
135             for ( int i = 0; i < fixVersions.length; i++ )
136             {
137                 if ( fixVersions[i].length() > 0 )
138                 {
139                     localFilter.append( "&fixfor=" ).append( fixVersions[i].trim() );
140                 }
141             }
142         }
143 
144         // get the Status Ids
145         if ( statusIds != null )
146         {
147             String[] stats = statusIds.split( "," );
148 
149             for ( int i = 0; i < stats.length; i++ )
150             {
151                 String statusParam = statusMap.get( stats[i] );
152 
153                 if ( statusParam != null )
154                 {
155                     localFilter.append( "&statusIds=" ).append( statusParam );
156                 }
157             }
158         }
159 
160         // get the Priority Ids
161         if ( priorityIds != null )
162         {
163             String[] prios = priorityIds.split( "," );
164 
165             for ( int i = 0; i < prios.length; i++ )
166             {
167                 String priorityParam = priorityMap.get( prios[i] );
168 
169                 if ( priorityParam != null )
170                 {
171                     localFilter.append( "&priorityIds=" ).append( priorityParam );
172                 }
173             }
174         }
175 
176         // get the Resolution Ids
177         if ( resolutionIds != null )
178         {
179             String[] resos = resolutionIds.split( "," );
180 
181             for ( int i = 0; i < resos.length; i++ )
182             {
183                 String resoParam = resolutionMap.get( resos[i] );
184 
185                 if ( resoParam != null )
186                 {
187                     localFilter.append( "&resolutionIds=" ).append( resoParam );
188                 }
189             }
190         }
191 
192         // add components
193         if ( component != null )
194         {
195             String[] components = component.split( "," );
196 
197             for ( int i = 0; i < components.length; i++ )
198             {
199                 if ( components[i].length() > 0 )
200                 {
201                     localFilter.append( "&component=" ).append( components[i] );
202                 }
203             }
204         }
205 
206         // get the Type Ids
207         if ( typeIds != null )
208         {
209             String[] types = typeIds.split( "," );
210 
211             for ( int i = 0; i < types.length; i++ )
212             {
213                 String typeParam = typeMap.get( types[i].trim() );
214 
215                 if ( typeParam != null )
216                 {
217                     localFilter.append( "&type=" ).append( typeParam );
218                 }
219             }
220         }
221 
222         // get the Sort order
223         int validSortColumnNames = 0;
224         if ( sortColumnNames != null )
225         {
226             String[] sortColumnNamesArray = sortColumnNames.split( "," );
227             // N.B. Add in reverse order (it's the way JIRA 3 likes it!!)
228             for ( int i = sortColumnNamesArray.length - 1; i >= 0; i-- )
229             {
230                 String lowerColumnName = sortColumnNamesArray[i].trim().toLowerCase( Locale.ENGLISH );
231                 boolean descending = false;
232                 String fieldName = null;
233                 if ( lowerColumnName.endsWith( "desc" ) )
234                 {
235                     descending = true;
236                     lowerColumnName = lowerColumnName.substring( 0, lowerColumnName.length() - 4 ).trim();
237                 }
238                 else if ( lowerColumnName.endsWith( "asc" ) )
239                 {
240                     descending = false;
241                     lowerColumnName = lowerColumnName.substring( 0, lowerColumnName.length() - 3 ).trim();
242                 }
243 
244                 if ( "key".equals( lowerColumnName ) )
245                 {
246                     fieldName = "issuekey";
247                 }
248                 else if ( "summary".equals( lowerColumnName ) )
249                 {
250                     fieldName = lowerColumnName;
251                 }
252                 else if ( "status".equals( lowerColumnName ) )
253                 {
254                     fieldName = lowerColumnName;
255                 }
256                 else if ( "resolution".equals( lowerColumnName ) )
257                 {
258                     fieldName = lowerColumnName;
259                 }
260                 else if ( "assignee".equals( lowerColumnName ) )
261                 {
262                     fieldName = lowerColumnName;
263                 }
264                 else if ( "reporter".equals( lowerColumnName ) )
265                 {
266                     fieldName = lowerColumnName;
267                 }
268                 else if ( "type".equals( lowerColumnName ) )
269                 {
270                     fieldName = "issuetype";
271                 }
272                 else if ( "priority".equals( lowerColumnName ) )
273                 {
274                     fieldName = lowerColumnName;
275                 }
276                 else if ( "version".equals( lowerColumnName ) )
277                 {
278                     fieldName = "versions";
279                 }
280                 else if ( "fix version".equals( lowerColumnName ) )
281                 {
282                     fieldName = "fixVersions";
283                 }
284                 else if ( "component".equals( lowerColumnName ) )
285                 {
286                     fieldName = "components";
287                 }
288                 else if ( "created".equals( lowerColumnName ) )
289                 {
290                     fieldName = lowerColumnName;
291                 }
292                 else if ( "updated".equals( lowerColumnName ) )
293                 {
294                     fieldName = lowerColumnName;
295                 }
296                 if ( fieldName != null )
297                 {
298                     localFilter.append( "&sorter/field=" );
299                     localFilter.append( fieldName );
300                     localFilter.append( "&sorter/order=" );
301                     localFilter.append( descending ? "DESC" : "ASC" );
302                     validSortColumnNames++;
303                 }
304                 else
305                 {
306                     // Error in the configuration
307                     getLog().error(
308                         "maven-changes-plugin: The configured value '" + lowerColumnName
309                             + "' for sortColumnNames is not correct." );
310                 }
311             }
312         }
313         if ( validSortColumnNames == 0 )
314         {
315             // Error in the configuration
316             getLog().error(
317                 "maven-changes-plugin: None of the configured sortColumnNames '" + sortColumnNames + "' are correct." );
318         }
319 
320 
321         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             HttpClient client = new HttpClient();
335 
336             // MCHANGES-89 Allow circular redirects
337             HttpClientParams clientParams = client.getParams();
338             clientParams.setBooleanParameter( HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true );
339 
340             HttpState state = new HttpState();
341 
342             HostConfiguration hc = new HostConfiguration();
343 
344             client.setHostConfiguration( hc );
345 
346             client.setState( state );
347 
348             Map<String,String> urlMap = JiraHelper.getJiraUrlAndProjectId( project.getIssueManagement().getUrl() );
349 
350             String jiraUrl = urlMap.get( "url" );
351             getLog().debug( "JIRA lives at: " + jiraUrl );
352 
353             String jiraId = urlMap.get( "id" );
354 
355             determineProxy( jiraUrl, client );
356 
357             prepareBasicAuthentication( client );
358 
359             boolean jiraAuthenticationSuccessful = false;
360             if ( isJiraAuthenticationConfigured() )
361             {
362                 jiraAuthenticationSuccessful = doJiraAuthentication( client, jiraUrl );
363             }
364 
365             if ( ( isJiraAuthenticationConfigured() && jiraAuthenticationSuccessful )
366                 || !isJiraAuthenticationConfigured() )
367             {
368                 if ( jiraId == null || jiraId.length() == 0 )
369                 {
370                     log.debug( "The JIRA URL " + project.getIssueManagement().getUrl()
371                         + " doesn't include a pid, trying to extract it from JIRA." );
372                     jiraId = JiraHelper.getPidFromJira( log, project.getIssueManagement().getUrl(), client );
373                 }
374 
375                 if ( jiraId == null )
376                 {
377                     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                     String fullURL = jiraUrl + "/secure/IssueNavigator.jspa?view=rss&pid=" + jiraId;
384 
385                     if ( getFixFor() != null )
386                     {
387                         fullURL += "&fixfor=" + getFixFor();
388                     }
389 
390                     String createdFilter = createFilter();
391                     if ( createdFilter.charAt( 0 ) != '&' )
392                     {
393                         fullURL += "&";
394                     }
395                     fullURL += createdFilter;
396 
397                     fullURL += ( "&tempMax=" + nbEntriesMax + "&reset=true&decorator=none" );
398 
399                     if ( log.isDebugEnabled() )
400                     {
401                         log.debug( "download jira issues from url " + fullURL );
402                     }
403 
404                     // execute the GET
405                     download( client, fullURL );
406                 }
407             }
408         }
409         catch ( Exception e )
410         {
411             getLog().error( "Error accessing " + project.getIssueManagement().getUrl(), e );
412         }
413     }
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         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         if ( ( webUser != null ) && ( webUser.length() > 0 ) )
433         {
434             client.getParams().setAuthenticationPreemptive( true );
435 
436             Credentials defaultcreds = new UsernamePasswordCredentials( webUser, webPassword );
437 
438             getLog().debug( "Using username: " + webUser + " for Basic Authentication." );
439 
440             client.getState().setCredentials( new AuthScope( null, AuthScope.ANY_PORT, null, AuthScope.ANY_SCHEME ),
441                                               defaultcreds );
442         }
443     }
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         String loginUrl = null;
458 
459         StringBuffer loginLink = new StringBuffer( jiraUrl );
460 
461         loginLink.append( "/login.jsp?os_destination=/secure/" );
462 
463         try
464         {
465             loginLink.append( "&os_username=" ).append( URLEncoder.encode( jiraUser, UTF_8 ) );
466 
467             String password = null;
468             if ( jiraPassword != null )
469             {
470                 password = StringUtils.repeat( "*", jiraPassword.length() );
471             }
472             getLog().debug( "Login URL: " + loginLink + "&os_password=" + password );
473 
474             loginLink.append( "&os_password=" ).append( URLEncoder.encode( jiraPassword, UTF_8 ) );
475 
476             loginUrl = loginLink.toString();
477 
478             // execute the login
479             GetMethod loginGet = new GetMethod( loginUrl );
480 
481             client.executeMethod( loginGet );
482 
483             if ( loginSucceeded( loginGet ) )
484             {
485                 getLog().debug( "Successfully logged in into JIRA." );
486                 return true;
487             }
488             else
489             {
490                 getLog().warn( "Was unable to login into JIRA: wrong username and/or password." );
491             }
492         }
493         catch ( Exception e )
494         {
495             if ( getLog().isDebugEnabled() )
496             {
497                 getLog().error( "Error trying to login into JIRA.", e );
498             }
499             else
500             {
501                 getLog().error( "Error trying to login into JIRA. Cause is: " + e.getLocalizedMessage() );
502             }
503         }
504         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         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         final String loginFailureResponse = "your username and password are incorrect";
529 
530         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         Proxy proxy = null;
542 
543         String proxyHost = null;
544 
545         int proxyPort = 0;
546 
547         String proxyUser = null;
548 
549         String proxyPass = null;
550 
551         if ( project == null )
552         {
553             getLog().error( "No project set. No proxy info available." );
554 
555             return;
556         }
557 
558         if ( settings != null )
559         {
560             proxy = settings.getActiveProxy();
561         }
562 
563         if ( proxy != null )
564         {
565 
566             ProxyInfo proxyInfo = new ProxyInfo();
567             proxyInfo.setNonProxyHosts( proxy.getNonProxyHosts() );
568 
569             // Get the host out of the JIRA URL
570             URL url = null;
571             try
572             {
573                 url = new URL( jiraUrl );
574             }
575             catch( MalformedURLException e )
576             {
577                 getLog().error( "Invalid JIRA URL: " + jiraUrl + ". " + e.getMessage() );
578             }
579             String jiraHost = null;
580             if( url != null )
581             {
582                 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             if ( JiraHelper.validateNonProxyHosts( proxyInfo, jiraHost ) )
590             {
591                 return;
592             }
593 
594             proxyHost = settings.getActiveProxy().getHost();
595 
596             proxyPort = settings.getActiveProxy().getPort();
597 
598             proxyUser = settings.getActiveProxy().getUsername();
599 
600             proxyPass = settings.getActiveProxy().getPassword();
601 
602             getLog().debug( proxyPass );
603         }
604 
605         if ( proxyHost != null )
606         {
607             client.getHostConfiguration().setProxy( proxyHost, proxyPort );
608 
609             getLog().debug( "Using proxy: " + proxyHost + " at port " + proxyPort );
610 
611             if ( proxyUser != null )
612             {
613                 getLog().debug( "Using proxy user: " + proxyUser );
614 
615                 client.getState().setProxyCredentials(
616                                                        new AuthScope( null, AuthScope.ANY_PORT, null,
617                                                                       AuthScope.ANY_SCHEME ),
618                                                        new UsernamePasswordCredentials( proxyUser, proxyPass ) );
619             }
620         }
621     }
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             GetMethod gm = new GetMethod( link );
634 
635             getLog().info( "Downloading from JIRA at: " + link );
636 
637             gm.setFollowRedirects( true );
638 
639             cl.executeMethod( gm );
640 
641             StatusLine sl = gm.getStatusLine();
642 
643             if ( sl == null )
644             {
645                 getLog().error( "Unknown error validating link: " + link );
646 
647                 return;
648             }
649 
650             // if we get a redirect, do so
651             if ( gm.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY )
652             {
653                 Header locationHeader = gm.getResponseHeader( "Location" );
654 
655                 if ( locationHeader == null )
656                 {
657                     getLog().warn( "Site sent redirect, but did not set Location header" );
658                 }
659                 else
660                 {
661                     String newLink = locationHeader.getValue();
662 
663                     getLog().debug( "Following redirect to " + newLink );
664 
665                     download( cl, newLink );
666                 }
667             }
668 
669             if ( gm.getStatusCode() == HttpStatus.SC_OK )
670             {
671                 final InputStream responseBodyStream = gm.getResponseBodyAsStream();
672 
673                 if ( !output.getParentFile().exists() )
674                 {
675                     output.getParentFile().mkdirs();
676                 }
677 
678                 // write the response to file
679                 OutputStream out = null;
680                 try
681                 {
682                     out = new FileOutputStream( output );
683                     IOUtil.copy( responseBodyStream, out );
684                 }
685                 finally
686                 {
687                     IOUtil.close( out );
688                     IOUtil.close( responseBodyStream );
689                 }
690 
691                 getLog().debug( "Downloading from JIRA was successful" );
692             }
693             else
694             {
695                 getLog().warn( "Downloading from JIRA failed. Received: [" + gm.getStatusCode() + "]" );
696             }
697         }
698         catch ( HttpException e )
699         {
700             if ( getLog().isDebugEnabled() )
701             {
702                 getLog().error( "Error downloading issues from JIRA:", e );
703             }
704             else
705             {
706                 getLog().error( "Error downloading issues from JIRA url: " + e.getLocalizedMessage() );
707 
708             }
709         }
710         catch ( IOException e )
711         {
712             if ( getLog().isDebugEnabled() )
713             {
714                 getLog().error( "Error downloading issues from JIRA:", e );
715             }
716             else
717             {
718                 getLog().error( "Error downloading issues from JIRA. Cause is " + e.getLocalizedMessage() );
719             }
720         }
721     }
722 
723     public List<Issue> getIssueList()
724     {
725         if ( output.isFile() )
726         {
727             JiraXML jira = new JiraXML( log, jiraDatePattern );
728             jira.parseXML( output );
729             getLog().info( "The JIRA version is '" + jira.getJiraVersion() + "'" );
730             return jira.getIssueList();
731         }
732         else
733         {
734             getLog().warn( "JIRA file " + output.getPath() + " doesn't exist." );
735             return Collections.emptyList();
736         }
737     }
738 
739     public void setJiraDatePattern( String jiraDatePattern )
740     {
741         this.jiraDatePattern = jiraDatePattern;
742     }
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         this.output = thisOutput;
752     }
753 
754     public File getOutput()
755     {
756         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         this.project = (MavenProject) thisProject;
767     }
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         nbEntriesMax = nbEntries;
777     }
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         statusIds = thisStatusIds;
787     }
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         priorityIds = thisPriorityIds;
797     }
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         resolutionIds = thisResolutionIds;
807     }
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         sortColumnNames = thisSortColumnNames;
817     }
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         this.webPassword = thisWebPassword;
827     }
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         this.webUser = thisWebUser;
837     }
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         this.jiraPassword = thisJiraPassword;
847     }
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         this.jiraUser = thisJiraUser;
857     }
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         this.filter = thisFilter;
867     }
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         this.component = theseComponents;
877     }
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         this.fixVersionIds = theseFixVersionIds;
887     }
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         typeIds = theseTypeIds;
897     }
898 
899     public void setLog( Log log )
900     {
901         this.log = log;
902     }
903 
904     private Log getLog()
905     {
906         return log;
907     }
908 
909     public void setSettings( Settings settings )
910     {
911         this.settings = settings;
912     }
913 }