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.auth.AuthScope;
32 import org.apache.commons.httpclient.cookie.CookiePolicy;
33 import org.apache.commons.httpclient.methods.GetMethod;
34 import org.apache.commons.httpclient.params.HttpClientParams;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.issues.Issue;
37 import org.apache.maven.settings.Proxy;
38 import org.codehaus.plexus.util.IOUtil;
39 import org.codehaus.plexus.util.StringUtils;
40
41 import java.io.FileOutputStream;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.io.OutputStream;
45 import java.net.URLEncoder;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.Map;
49
50
51
52
53
54
55
56
57 public final class ClassicJiraDownloader
58 extends AbstractJiraDownloader
59 {
60 public ClassicJiraDownloader()
61 {
62 }
63
64
65
66
67
68
69 public void doExecute()
70 throws Exception
71 {
72 try
73 {
74 HttpClient client = new HttpClient();
75
76
77 HttpClientParams clientParams = client.getParams();
78 clientParams.setBooleanParameter( HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true );
79 clientParams.setCookiePolicy( CookiePolicy.BROWSER_COMPATIBILITY );
80
81 HttpState state = new HttpState();
82
83 HostConfiguration hc = new HostConfiguration();
84
85 client.setHostConfiguration( hc );
86
87 client.setState( state );
88
89 String baseUrl = JiraHelper.getBaseUrl( project.getIssueManagement().getUrl() );
90
91 getLog().debug( "JIRA lives at: " + baseUrl );
92
93 determineProxy( baseUrl, client );
94
95 prepareBasicAuthentication( client );
96
97 boolean jiraAuthenticationSuccessful = false;
98 if ( isJiraAuthenticationConfigured() )
99 {
100
101 jiraAuthenticationSuccessful = doJiraAuthentication( client, baseUrl );
102 }
103
104 if ( ( isJiraAuthenticationConfigured() && jiraAuthenticationSuccessful )
105 || !isJiraAuthenticationConfigured() )
106 {
107 String fullUrl = null;
108
109 if ( useJql )
110 {
111 fullUrl = getJqlQueryURL();
112 }
113 else
114 {
115 fullUrl = getParameterBasedQueryURL( client );
116 }
117 if ( log.isDebugEnabled() )
118 {
119 log.debug( "download jira issues from url " + fullUrl );
120 }
121
122
123 download( client, fullUrl );
124 }
125 }
126 catch ( Exception e )
127 {
128 if ( project.getIssueManagement() != null )
129 {
130 getLog().error( "Error accessing " + project.getIssueManagement().getUrl(), e );
131 }
132 else
133 {
134 getLog().error( "Error accessing mock project issues", e );
135 }
136 }
137 }
138
139 private String getJqlQueryURL()
140 {
141
142 Map<String, String> urlMap = JiraHelper.getJiraUrlAndProjectName( project.getIssueManagement().getUrl() );
143 String jiraUrl = urlMap.get( "url" );
144 String jiraProject = urlMap.get( "project" );
145
146 if ( jiraProject == null )
147 {
148 throw new RuntimeException( "The issue management URL in the POM does not include a JIRA project name" );
149 }
150 else
151 {
152
153 String jqlQuery = new JqlQueryBuilder( log )
154 .project( jiraProject )
155 .fixVersion( getFixFor() )
156 .fixVersionIds( fixVersionIds )
157 .statusIds( statusIds )
158 .priorityIds( priorityIds )
159 .resolutionIds( resolutionIds )
160 .components( component )
161 .typeIds( typeIds )
162 .sortColumnNames( sortColumnNames )
163 .build();
164
165 String url = new UrlBuilder( jiraUrl, "sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml" )
166 .addParameter( "tempMax", nbEntriesMax )
167 .addParameter( "reset", "true" )
168 .addParameter( "jqlQuery", jqlQuery )
169 .build();
170
171 return url;
172 }
173 }
174
175 private String getParameterBasedQueryURL( HttpClient client )
176 {
177 Map<String, String> urlMap = JiraHelper.getJiraUrlAndProjectId( project.getIssueManagement().getUrl() );
178 String jiraUrl = urlMap.get( "url" );
179 String jiraId = urlMap.get( "id" );
180
181 if ( jiraId == null || jiraId.length() == 0 )
182 {
183 log.debug( "The JIRA URL " + project.getIssueManagement().getUrl()
184 + " doesn't include a pid, trying to extract it from JIRA." );
185 jiraId = JiraHelper.getPidFromJira( log, project.getIssueManagement().getUrl(), client );
186 }
187
188 if ( jiraId == null )
189 {
190 throw new RuntimeException( "The issue management URL in the POM does not include a pid,"
191 + " and it was not possible to extract it from the page at that URL." );
192 }
193 else
194 {
195
196 String fullURL = jiraUrl + "/secure/IssueNavigator.jspa?view=rss&pid=" + jiraId;
197
198 if ( getFixFor() != null )
199 {
200 fullURL += "&fixfor=" + getFixFor();
201 }
202
203 String createdFilter = new ParameterQueryBuilder( log )
204 .fixVersionIds( fixVersionIds )
205 .statusIds( statusIds )
206 .priorityIds( priorityIds )
207 .resolutionIds( resolutionIds )
208 .components( component )
209 .typeIds( typeIds )
210 .sortColumnNames( sortColumnNames )
211 .filter( filter )
212 .build();
213
214 if ( createdFilter.charAt( 0 ) != '&' )
215 {
216 fullURL += "&";
217 }
218 fullURL += createdFilter;
219
220 fullURL += ( "&tempMax=" + nbEntriesMax + "&reset=true&decorator=none" );
221
222 return fullURL;
223 }
224 }
225
226
227
228
229
230
231 private void prepareBasicAuthentication( HttpClient client )
232 {
233 if ( ( webUser != null ) && ( webUser.length() > 0 ) )
234 {
235 client.getParams().setAuthenticationPreemptive( true );
236
237 Credentials defaultcreds = new UsernamePasswordCredentials( webUser, webPassword );
238
239 getLog().debug( "Using username: " + webUser + " for Basic Authentication." );
240
241 client.getState().setCredentials( new AuthScope( null, AuthScope.ANY_PORT, null, AuthScope.ANY_SCHEME ),
242 defaultcreds );
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255 private boolean doJiraAuthentication( HttpClient client, final String jiraUrl )
256 {
257
258 String loginUrl = null;
259
260 StringBuilder loginLink = new StringBuilder( jiraUrl );
261
262 loginLink.append( "/login.jsp?os_destination=/secure/" );
263
264 try
265 {
266 loginLink.append( "&os_username=" ).append( URLEncoder.encode( jiraUser, UTF_8 ) );
267
268 String password = null;
269 if ( jiraPassword != null )
270 {
271 password = StringUtils.repeat( "*", jiraPassword.length() );
272 }
273 getLog().debug( "Login URL: " + loginLink + "&os_password=" + password );
274
275 loginLink.append( "&os_password=" ).append( URLEncoder.encode( jiraPassword, UTF_8 ) );
276
277 loginUrl = loginLink.toString();
278
279
280 GetMethod loginGet = new GetMethod( loginUrl );
281
282 client.executeMethod( loginGet );
283
284 if ( loginSucceeded( loginGet ) )
285 {
286 getLog().debug( "Successfully logged in into JIRA." );
287 return true;
288 }
289 else
290 {
291 getLog().warn( "Was unable to login into JIRA: wrong username and/or password." );
292 }
293 }
294 catch ( Exception e )
295 {
296 if ( getLog().isDebugEnabled() )
297 {
298 getLog().error( "Error trying to login into JIRA.", e );
299 }
300 else
301 {
302 getLog().error( "Error trying to login into JIRA. Cause is: " + e.getLocalizedMessage() );
303 }
304 }
305 return false;
306 }
307
308
309
310
311
312
313
314
315
316 private boolean loginSucceeded( GetMethod loginGet )
317 throws IOException
318 {
319 final String loginFailureResponse = "your username and password are incorrect";
320
321 return loginGet.getResponseBodyAsString().indexOf( loginFailureResponse ) == -1;
322 }
323
324
325
326
327
328
329 private void determineProxy( String jiraUrl, HttpClient client )
330 {
331
332 Proxy proxy = null;
333
334 getProxyInfo( jiraUrl );
335
336 if ( proxyHost != null )
337 {
338 client.getHostConfiguration().setProxy( proxyHost, proxyPort );
339
340 getLog().debug( "Using proxy: " + proxyHost + " at port " + proxyPort );
341
342 if ( proxyUser != null )
343 {
344 getLog().debug( "Using proxy user: " + proxyUser );
345
346 client.getState().setProxyCredentials(
347 new AuthScope( null, AuthScope.ANY_PORT, null,
348 AuthScope.ANY_SCHEME ),
349 new UsernamePasswordCredentials( proxyUser, proxyPass ) );
350 }
351 }
352 }
353
354
355
356
357
358
359
360 private void download( final HttpClient cl, final String link )
361 {
362 try
363 {
364 GetMethod gm = new GetMethod( link );
365
366 getLog().info( "Downloading from JIRA at: " + link );
367
368 gm.setFollowRedirects( true );
369
370 cl.executeMethod( gm );
371
372 StatusLine sl = gm.getStatusLine();
373
374 if ( sl == null )
375 {
376 getLog().error( "Unknown error validating link: " + link );
377
378 return;
379 }
380
381
382 if ( gm.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY )
383 {
384 Header locationHeader = gm.getResponseHeader( "Location" );
385
386 if ( locationHeader == null )
387 {
388 getLog().warn( "Site sent redirect, but did not set Location header" );
389 }
390 else
391 {
392 String newLink = locationHeader.getValue();
393
394 getLog().debug( "Following redirect to " + newLink );
395
396 download( cl, newLink );
397 }
398 }
399
400 if ( gm.getStatusCode() == HttpStatus.SC_OK )
401 {
402 final InputStream responseBodyStream = gm.getResponseBodyAsStream();
403
404 if ( !output.getParentFile().exists() )
405 {
406 output.getParentFile().mkdirs();
407 }
408
409
410 OutputStream out = null;
411 try
412 {
413 out = new FileOutputStream( output );
414 IOUtil.copy( responseBodyStream, out );
415 }
416 finally
417 {
418 IOUtil.close( out );
419 IOUtil.close( responseBodyStream );
420 }
421
422 getLog().debug( "Downloading from JIRA was successful" );
423 }
424 else
425 {
426 getLog().warn( "Downloading from JIRA failed. Received: [" + gm.getStatusCode() + "]" );
427 }
428 }
429 catch ( HttpException e )
430 {
431 if ( getLog().isDebugEnabled() )
432 {
433 getLog().error( "Error downloading issues from JIRA:", e );
434 }
435 else
436 {
437 getLog().error( "Error downloading issues from JIRA url: " + e.getLocalizedMessage() );
438
439 }
440 }
441 catch ( IOException e )
442 {
443 if ( getLog().isDebugEnabled() )
444 {
445 getLog().error( "Error downloading issues from JIRA:", e );
446 }
447 else
448 {
449 getLog().error( "Error downloading issues from JIRA. Cause is " + e.getLocalizedMessage() );
450 }
451 }
452 }
453
454 public List<Issue> getIssueList()
455 throws MojoExecutionException
456 {
457 if ( output.isFile() )
458 {
459 JiraXML jira = new JiraXML( log, jiraDatePattern );
460 jira.parseXML( output );
461 getLog().info( "The JIRA version is '" + jira.getJiraVersion() + "'" );
462 return jira.getIssueList();
463 }
464 else
465 {
466 getLog().warn( "JIRA file " + output.getPath() + " doesn't exist." );
467 return Collections.emptyList();
468 }
469 }
470
471 }