1 package org.apache.maven.plugin.jira;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
50
51
52
53
54
55
56
57 public abstract class AbstractJiraDownloader
58 {
59
60 private Log log;
61
62 private File output;
63
64 private int nbEntriesMax;
65
66 private String filter;
67
68 private String fixVersionIds;
69
70 private String statusIds;
71
72 private String resolutionIds;
73
74 private String priorityIds;
75
76 private String component;
77
78 private String typeIds;
79
80 private String sortColumnNames;
81
82 private String jiraUser;
83
84 private String jiraPassword;
85
86 private String webUser;
87
88 private String webPassword;
89
90 private MavenProject project;
91
92 private Settings settings;
93
94 protected Map statusMap = new HashMap();
95
96 protected Map resolutionMap = new HashMap();
97
98 protected Map priorityMap = new HashMap();
99
100 protected Map typeMap = new HashMap();
101
102
103
104
105
106
107 private String createFilter()
108 {
109
110 if ( ( this.filter != null ) && ( this.filter.length() > 0 ) )
111 {
112 return this.filter;
113 }
114
115 StringBuffer localFilter = new StringBuffer();
116
117
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
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
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
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
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
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
210 int validSortColumnNames = 0;
211 if ( sortColumnNames != null )
212 {
213 String[] sortColumnNamesArray = sortColumnNames.split( "," );
214
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
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
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
313
314
315
316 public void doExecute()
317 throws Exception
318 {
319 try
320 {
321 HttpClient client = new HttpClient();
322
323
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
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
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
403
404
405
406 protected String getFixFor()
407 {
408 return null;
409 }
410
411
412
413
414
415
416
417 private Map getJiraUrlAndIssueId()
418 {
419 HashMap urlMap = new HashMap();
420
421 String url = project.getIssueManagement().getUrl();
422
423
424 int pos = url.indexOf( "?" );
425
426
427 String id = "";
428
429 if ( pos >= 0 )
430 {
431
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
452
453
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
472
473
474
475
476
477
478
479 private boolean doJiraAuthentication( HttpClient client, final String jiraUrl )
480 {
481
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
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
534
535
536
537 private boolean isJiraAuthenticationConfigured()
538 {
539 return ( jiraUser != null ) && ( jiraUser.length() > 0 ) && ( jiraPassword != null );
540 }
541
542
543
544
545
546
547
548
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
560
561
562
563 private void determineProxy( HttpClient client )
564 {
565
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
621
622
623
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
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
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
715
716
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
730
731
732
733 public void setMavenProject( Object thisProject )
734 {
735 this.project = (MavenProject) thisProject;
736 }
737
738
739
740
741
742
743 public void setNbEntries( final int nbEntries )
744 {
745 nbEntriesMax = nbEntries;
746 }
747
748
749
750
751
752
753 public void setStatusIds( String thisStatusIds )
754 {
755 statusIds = thisStatusIds;
756 }
757
758
759
760
761
762
763 public void setPriorityIds( String thisPriorityIds )
764 {
765 priorityIds = thisPriorityIds;
766 }
767
768
769
770
771
772
773 public void setResolutionIds( String thisResolutionIds )
774 {
775 resolutionIds = thisResolutionIds;
776 }
777
778
779
780
781
782
783 public void setSortColumnNames( String thisSortColumnNames )
784 {
785 sortColumnNames = thisSortColumnNames;
786 }
787
788
789
790
791
792
793 public void setWebPassword( String thisWebPassword )
794 {
795 this.webPassword = thisWebPassword;
796 }
797
798
799
800
801
802
803 public void setWebUser( String thisWebUser )
804 {
805 this.webUser = thisWebUser;
806 }
807
808
809
810
811
812
813 public void setJiraPassword( final String thisJiraPassword )
814 {
815 this.jiraPassword = thisJiraPassword;
816 }
817
818
819
820
821
822
823 public void setJiraUser( String thisJiraUser )
824 {
825 this.jiraUser = thisJiraUser;
826 }
827
828
829
830
831
832
833 public void setFilter( String thisFilter )
834 {
835 this.filter = thisFilter;
836 }
837
838
839
840
841
842
843 public void setComponent( String theseComponents )
844 {
845 this.component = theseComponents;
846 }
847
848
849
850
851
852
853 public void setFixVersionIds( String theseFixVersionIds )
854 {
855 this.fixVersionIds = theseFixVersionIds;
856 }
857
858
859
860
861
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 }