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
386 download( client, fullURL );
387 }
388 }
389 }
390 catch ( Exception e )
391 {
392 getLog().error( "Error accessing " + project.getIssueManagement().getUrl(), e );
393 }
394 }
395
396
397
398
399
400
401 protected String getFixFor()
402 {
403 return null;
404 }
405
406
407
408
409
410
411
412 private Map getJiraUrlAndIssueId()
413 {
414 HashMap urlMap = new HashMap();
415
416 String url = project.getIssueManagement().getUrl();
417
418
419 int pos = url.indexOf( "?" );
420
421
422 String id = "";
423
424 if ( pos >= 0 )
425 {
426
427 id = url.substring( url.lastIndexOf( "=" ) + 1 );
428 }
429
430 String jiraUrl = url.substring( 0, url.lastIndexOf( "/" ) );
431
432 if ( jiraUrl.endsWith( "secure" ) || jiraUrl.endsWith( "browse" ) )
433 {
434 jiraUrl = jiraUrl.substring( 0, jiraUrl.lastIndexOf( "/" ) );
435 }
436 getLog().debug( "JIRA lives at: " + jiraUrl );
437
438 urlMap.put( "url", jiraUrl );
439
440 urlMap.put( "id", id );
441
442 return urlMap;
443 }
444
445
446
447
448
449
450 private void prepareBasicAuthentication( HttpClient client )
451 {
452 if ( ( webUser != null ) && ( webUser.length() > 0 ) )
453 {
454 client.getParams().setAuthenticationPreemptive( true );
455
456 Credentials defaultcreds = new UsernamePasswordCredentials( webUser, webPassword );
457
458 getLog().debug( "Using username: " + webUser + " for Basic Authentication." );
459
460 client.getState().setCredentials( new AuthScope( null, AuthScope.ANY_PORT, null, AuthScope.ANY_SCHEME ),
461 defaultcreds );
462 }
463 }
464
465
466
467
468
469
470
471
472
473
474 private boolean doJiraAuthentication( HttpClient client, final String jiraUrl )
475 {
476
477 String loginUrl = null;
478
479 StringBuffer loginLink = new StringBuffer( jiraUrl );
480
481 loginLink.append( "/login.jsp?os_destination=/secure/" );
482
483 loginLink.append( "&os_username=" ).append( jiraUser );
484
485 String password = null;
486 if ( jiraPassword != null )
487 {
488 password = StringUtils.repeat( "*", jiraPassword.length() );
489 }
490 getLog().debug( "Login URL: " + loginLink + "&os_password=" + password );
491
492 loginLink.append( "&os_password=" ).append( jiraPassword );
493
494 loginUrl = loginLink.toString();
495
496
497 GetMethod loginGet = new GetMethod( loginUrl );
498
499 try
500 {
501 client.executeMethod( loginGet );
502
503 if ( loginSucceeded( loginGet ) )
504 {
505 getLog().debug( "Successfully logged in into JIRA." );
506 return true;
507 }
508 else
509 {
510 getLog().warn( "Was unable to login into JIRA: wrong username and/or password." );
511 }
512 }
513 catch ( Exception e )
514 {
515 if ( getLog().isDebugEnabled() )
516 {
517 getLog().error( "Error trying to login into JIRA.", e );
518 }
519 else
520 {
521 getLog().error( "Error trying to login into JIRA. Cause is: " + e.getLocalizedMessage() );
522 }
523 }
524 return false;
525 }
526
527
528
529
530
531
532 private boolean isJiraAuthenticationConfigured()
533 {
534 return ( jiraUser != null ) && ( jiraUser.length() > 0 ) && ( jiraPassword != null );
535 }
536
537
538
539
540
541
542
543
544
545 private boolean loginSucceeded( GetMethod loginGet )
546 throws IOException
547 {
548 final String loginFailureResponse = "your username and password are incorrect";
549
550 return loginGet.getResponseBodyAsString().indexOf( loginFailureResponse ) == -1;
551 }
552
553
554
555
556
557
558 private void determineProxy( HttpClient client )
559 {
560
561 Proxy proxy = null;
562
563 String proxyHost = null;
564
565 int proxyPort = 0;
566
567 String proxyUser = null;
568
569 String proxyPass = null;
570
571 if ( project == null )
572 {
573 getLog().error( "No project set. No proxy info available." );
574
575 return;
576 }
577
578 if ( settings != null )
579 {
580 proxy = settings.getActiveProxy();
581 }
582
583 if ( proxy != null )
584 {
585 proxyHost = settings.getActiveProxy().getHost();
586
587 proxyPort = settings.getActiveProxy().getPort();
588
589 proxyUser = settings.getActiveProxy().getUsername();
590
591 proxyPass = settings.getActiveProxy().getPassword();
592
593 getLog().debug( proxyPass );
594 }
595
596 if ( proxyHost != null )
597 {
598 client.getHostConfiguration().setProxy( proxyHost, proxyPort );
599
600 getLog().debug( "Using proxy: " + proxyHost + " at port " + proxyPort );
601
602 if ( proxyUser != null )
603 {
604 getLog().debug( "Using proxy user: " + proxyUser );
605
606 client.getState().setProxyCredentials(
607 new AuthScope( null, AuthScope.ANY_PORT, null,
608 AuthScope.ANY_SCHEME ),
609 new UsernamePasswordCredentials( proxyUser, proxyPass ) );
610 }
611 }
612 }
613
614
615
616
617
618
619
620 private void download( final HttpClient cl, final String link )
621 {
622 try
623 {
624 GetMethod gm = new GetMethod( link );
625
626 getLog().info( "Downloading from JIRA at: " + link );
627
628 gm.setFollowRedirects( true );
629
630 cl.executeMethod( gm );
631
632 StatusLine sl = gm.getStatusLine();
633
634 if ( sl == null )
635 {
636 getLog().error( "Unknown error validating link: " + link );
637
638 return;
639 }
640
641
642 if ( gm.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY )
643 {
644 Header locationHeader = gm.getResponseHeader( "Location" );
645
646 if ( locationHeader == null )
647 {
648 getLog().warn( "Site sent redirect, but did not set Location header" );
649 }
650 else
651 {
652 String newLink = locationHeader.getValue();
653
654 getLog().debug( "Following redirect to " + newLink );
655
656 download( cl, newLink );
657 }
658 }
659
660 if ( gm.getStatusCode() == HttpStatus.SC_OK )
661 {
662 final String strGetResponseBody = gm.getResponseBodyAsString();
663
664 if ( !output.getParentFile().exists() )
665 {
666 output.getParentFile().mkdirs();
667 }
668
669
670 PrintWriter pw = new PrintWriter( new FileWriter( output ) );
671
672 pw.print( strGetResponseBody );
673
674 pw.close();
675
676 getLog().debug( "Downloading from JIRA was successful" );
677 }
678 else
679 {
680 getLog().warn( "Downloading from JIRA failed. Received: [" + gm.getStatusCode() + "]" );
681 }
682 }
683 catch ( HttpException e )
684 {
685 if ( getLog().isDebugEnabled() )
686 {
687 getLog().error( "Error downloading issues from JIRA:", e );
688 }
689 else
690 {
691 getLog().error( "Error downloading issues from JIRA url: " + e.getLocalizedMessage() );
692
693 }
694 }
695 catch ( IOException e )
696 {
697 if ( getLog().isDebugEnabled() )
698 {
699 getLog().error( "Error downloading issues from JIRA:", e );
700 }
701 else
702 {
703 getLog().error( "Error downloading issues from JIRA. Cause is " + e.getLocalizedMessage() );
704 }
705 }
706 }
707
708
709
710
711
712
713 public void setOutput( File thisOutput )
714 {
715 this.output = thisOutput;
716 }
717
718 public File getOutput()
719 {
720 return this.output;
721 }
722
723
724
725
726
727
728 public void setMavenProject( Object thisProject )
729 {
730 this.project = (MavenProject) thisProject;
731 }
732
733
734
735
736
737
738 public void setNbEntries( final int nbEntries )
739 {
740 nbEntriesMax = nbEntries;
741 }
742
743
744
745
746
747
748 public void setStatusIds( String thisStatusIds )
749 {
750 statusIds = thisStatusIds;
751 }
752
753
754
755
756
757
758 public void setPriorityIds( String thisPriorityIds )
759 {
760 priorityIds = thisPriorityIds;
761 }
762
763
764
765
766
767
768 public void setResolutionIds( String thisResolutionIds )
769 {
770 resolutionIds = thisResolutionIds;
771 }
772
773
774
775
776
777
778 public void setSortColumnNames( String thisSortColumnNames )
779 {
780 sortColumnNames = thisSortColumnNames;
781 }
782
783
784
785
786
787
788 public void setWebPassword( String thisWebPassword )
789 {
790 this.webPassword = thisWebPassword;
791 }
792
793
794
795
796
797
798 public void setWebUser( String thisWebUser )
799 {
800 this.webUser = thisWebUser;
801 }
802
803
804
805
806
807
808 public void setJiraPassword( final String thisJiraPassword )
809 {
810 this.jiraPassword = thisJiraPassword;
811 }
812
813
814
815
816
817
818 public void setJiraUser( String thisJiraUser )
819 {
820 this.jiraUser = thisJiraUser;
821 }
822
823
824
825
826
827
828 public void setFilter( String thisFilter )
829 {
830 this.filter = thisFilter;
831 }
832
833
834
835
836
837
838 public void setComponent( String theseComponents )
839 {
840 this.component = theseComponents;
841 }
842
843
844
845
846
847
848 public void setFixVersionIds( String theseFixVersionIds )
849 {
850 this.fixVersionIds = theseFixVersionIds;
851 }
852
853
854
855
856
857
858 public void setTypeIds( String theseTypeIds )
859 {
860 typeIds = theseTypeIds;
861 }
862
863 public void setLog( Log log )
864 {
865 this.log = log;
866 }
867
868 private Log getLog()
869 {
870 return log;
871 }
872
873 public void setSettings( Settings settings )
874 {
875 this.settings = settings;
876 }
877 }