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