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 String jqlQuery = new JqlQueryBuilder( log )
153 .project( jiraProject )
154 .fixVersion( getFixFor() )
155 .fixVersionIds( fixVersionIds )
156 .statusIds( statusIds )
157 .priorityIds( priorityIds )
158 .resolutionIds( resolutionIds )
159 .components( component )
160 .typeIds( typeIds )
161 .sortColumnNames( sortColumnNames )
162 .build();
163
164 String url = new UrlBuilder( jiraUrl, "sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml" )
165 .addParameter( "tempMax", nbEntriesMax )
166 .addParameter( "reset", "true" )
167 .addParameter( "jqlQuery", jqlQuery )
168 .build();
169
170 return url;
171 }
172 }
173
174 private String getParameterBasedQueryURL( HttpClient client )
175 {
176 Map<String, String> urlMap = JiraHelper.getJiraUrlAndProjectId( project.getIssueManagement().getUrl() );
177 String jiraUrl = urlMap.get( "url" );
178 String jiraId = urlMap.get( "id" );
179
180 if ( jiraId == null || jiraId.length() == 0 )
181 {
182 log.debug( "The JIRA URL " + project.getIssueManagement().getUrl()
183 + " doesn't include a pid, trying to extract it from JIRA." );
184 jiraId = JiraHelper.getPidFromJira( log, project.getIssueManagement().getUrl(), client );
185 }
186
187 if ( jiraId == null )
188 {
189 throw new RuntimeException( "The issue management URL in the POM does not include a pid,"
190 + " and it was not possible to extract it from the page at that URL." );
191 }
192 else
193 {
194
195 String fullURL = jiraUrl + "/secure/IssueNavigator.jspa?view=rss&pid=" + jiraId;
196
197 if ( getFixFor() != null )
198 {
199 fullURL += "&fixfor=" + getFixFor();
200 }
201
202 String createdFilter = new ParameterQueryBuilder( log )
203 .fixVersionIds( fixVersionIds )
204 .statusIds( statusIds )
205 .priorityIds( priorityIds )
206 .resolutionIds( resolutionIds )
207 .components( component )
208 .typeIds( typeIds )
209 .sortColumnNames( sortColumnNames )
210 .filter( filter )
211 .build();
212
213 if ( createdFilter.charAt( 0 ) != '&' )
214 {
215 fullURL += "&";
216 }
217 fullURL += createdFilter;
218
219 fullURL += ( "&tempMax=" + nbEntriesMax + "&reset=true&decorator=none" );
220
221 return fullURL;
222 }
223 }
224
225
226
227
228
229
230 private void prepareBasicAuthentication( HttpClient client )
231 {
232 if ( ( webUser != null ) && ( webUser.length() > 0 ) )
233 {
234 client.getParams().setAuthenticationPreemptive( true );
235
236 Credentials defaultcreds = new UsernamePasswordCredentials( webUser, webPassword );
237
238 getLog().debug( "Using username: " + webUser + " for Basic Authentication." );
239
240 client.getState().setCredentials( new AuthScope( null, AuthScope.ANY_PORT, null, AuthScope.ANY_SCHEME ),
241 defaultcreds );
242 }
243 }
244
245
246
247
248
249
250
251
252
253
254 private boolean doJiraAuthentication( HttpClient client, final String jiraUrl )
255 {
256
257 String loginUrl;
258
259 StringBuilder loginLink = new StringBuilder( jiraUrl );
260
261 loginLink.append( "/login.jsp?os_destination=/secure/" );
262
263 try
264 {
265 loginLink.append( "&os_username=" ).append( URLEncoder.encode( jiraUser, UTF_8 ) );
266
267 String password = null;
268 if ( jiraPassword != null )
269 {
270 password = StringUtils.repeat( "*", jiraPassword.length() );
271 }
272 getLog().debug( "Login URL: " + loginLink + "&os_password=" + password );
273
274 loginLink.append( "&os_password=" ).append( URLEncoder.encode( jiraPassword, UTF_8 ) );
275
276 loginUrl = loginLink.toString();
277
278
279 GetMethod loginGet = new GetMethod( loginUrl );
280
281 client.executeMethod( loginGet );
282
283 if ( loginSucceeded( loginGet ) )
284 {
285 getLog().debug( "Successfully logged in into JIRA." );
286 return true;
287 }
288 else
289 {
290 getLog().warn( "Was unable to login into JIRA: wrong username and/or password." );
291 }
292 }
293 catch ( Exception e )
294 {
295 if ( getLog().isDebugEnabled() )
296 {
297 getLog().error( "Error trying to login into JIRA.", e );
298 }
299 else
300 {
301 getLog().error( "Error trying to login into JIRA. Cause is: " + e.getLocalizedMessage() );
302 }
303 }
304 return false;
305 }
306
307
308
309
310
311
312
313
314
315 private boolean loginSucceeded( GetMethod loginGet )
316 throws IOException
317 {
318 final String loginFailureResponse = "your username and password are incorrect";
319
320 return !loginGet.getResponseBodyAsString().contains( loginFailureResponse );
321 }
322
323
324
325
326
327
328 private void determineProxy( String jiraUrl, HttpClient client )
329 {
330
331
332 getProxyInfo( jiraUrl );
333
334 if ( proxyHost != null )
335 {
336 client.getHostConfiguration().setProxy( proxyHost, proxyPort );
337
338 getLog().debug( "Using proxy: " + proxyHost + " at port " + proxyPort );
339
340 if ( proxyUser != null )
341 {
342 getLog().debug( "Using proxy user: " + proxyUser );
343
344 client.getState().setProxyCredentials(
345 new AuthScope( null, AuthScope.ANY_PORT, null,
346 AuthScope.ANY_SCHEME ),
347 new UsernamePasswordCredentials( proxyUser, proxyPass ) );
348 }
349 }
350 }
351
352
353
354
355
356
357
358 private void download( final HttpClient cl, final String link )
359 {
360 try
361 {
362 GetMethod gm = new GetMethod( link );
363
364 getLog().info( "Downloading from JIRA at: " + link );
365
366 gm.setFollowRedirects( true );
367
368 cl.executeMethod( gm );
369
370 StatusLine sl = gm.getStatusLine();
371
372 if ( sl == null )
373 {
374 getLog().error( "Unknown error validating link: " + link );
375
376 return;
377 }
378
379
380 if ( gm.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY )
381 {
382 Header locationHeader = gm.getResponseHeader( "Location" );
383
384 if ( locationHeader == null )
385 {
386 getLog().warn( "Site sent redirect, but did not set Location header" );
387 }
388 else
389 {
390 String newLink = locationHeader.getValue();
391
392 getLog().debug( "Following redirect to " + newLink );
393
394 download( cl, newLink );
395 }
396 }
397
398 if ( gm.getStatusCode() == HttpStatus.SC_OK )
399 {
400 final InputStream responseBodyStream = gm.getResponseBodyAsStream();
401
402 if ( !output.getParentFile().exists() )
403 {
404 output.getParentFile().mkdirs();
405 }
406
407
408 OutputStream out = null;
409 try
410 {
411 out = new FileOutputStream( output );
412 IOUtil.copy( responseBodyStream, out );
413 }
414 finally
415 {
416 IOUtil.close( out );
417 IOUtil.close( responseBodyStream );
418 }
419
420 getLog().debug( "Downloading from JIRA was successful" );
421 }
422 else
423 {
424 getLog().warn( "Downloading from JIRA failed. Received: [" + gm.getStatusCode() + "]" );
425 }
426 }
427 catch ( HttpException e )
428 {
429 if ( getLog().isDebugEnabled() )
430 {
431 getLog().error( "Error downloading issues from JIRA:", e );
432 }
433 else
434 {
435 getLog().error( "Error downloading issues from JIRA url: " + e.getLocalizedMessage() );
436
437 }
438 }
439 catch ( IOException e )
440 {
441 if ( getLog().isDebugEnabled() )
442 {
443 getLog().error( "Error downloading issues from JIRA:", e );
444 }
445 else
446 {
447 getLog().error( "Error downloading issues from JIRA. Cause is " + e.getLocalizedMessage() );
448 }
449 }
450 }
451
452 public List<Issue> getIssueList()
453 throws MojoExecutionException
454 {
455 if ( output.isFile() )
456 {
457 JiraXML jira = new JiraXML( log, jiraDatePattern );
458 jira.parseXML( output );
459 getLog().info( "The JIRA version is '" + jira.getJiraVersion() + "'" );
460 return jira.getIssueList();
461 }
462 else
463 {
464 getLog().warn( "JIRA file " + output.getPath() + " doesn't exist." );
465 return Collections.emptyList();
466 }
467 }
468
469 }