1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package de.smartics.maven.issues.repository;
18
19 import java.util.ArrayList;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.TreeSet;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.maven.reporting.MavenReportException;
29 import org.codehaus.plexus.util.StringUtils;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IProgressMonitor;
32 import org.eclipse.core.runtime.IStatus;
33 import org.eclipse.core.runtime.NullProgressMonitor;
34 import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
35 import org.eclipse.mylyn.commons.net.AuthenticationType;
36 import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
37 import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
38 import org.eclipse.mylyn.tasks.core.TaskRepository;
39 import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
40 import org.eclipse.mylyn.tasks.core.data.TaskData;
41 import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
42 import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession;
43
44 import de.smartics.maven.issues.IssueManagementConfig;
45 import de.smartics.maven.issues.QueryData;
46 import de.smartics.maven.issues.RepositoryFacade;
47 import de.smartics.maven.issues.ResourceLocator;
48 import de.smartics.maven.issues.cache.TaskDataCache;
49
50
51
52
53
54
55
56 public abstract class AbstractRepositoryFacade implements RepositoryFacade
57 {
58
59
60
61
62
63
64
65
66
67 private final Log log = LogFactory.getLog(AbstractRepositoryFacade.class);
68
69
70
71
72 protected final IssueManagementConfig config;
73
74
75
76
77 protected final AbstractRepositoryConnector connector;
78
79
80
81
82 protected TaskRepository repository;
83
84
85
86
87
88
89
90
91
92
93
94
95 protected AbstractRepositoryFacade(final IssueManagementConfig config,
96 final AbstractRepositoryConnector connector)
97 {
98 this.config = config;
99 this.connector = connector;
100 this.repository = createRepository();
101 }
102
103
104
105
106
107
108
109 private static final class SimpleTaskDataCollector extends TaskDataCollector
110 {
111
112
113
114 private final List<TaskData> tasks = new ArrayList<TaskData>();
115
116
117
118
119
120
121 public List<TaskData> getTasks()
122 {
123 return tasks;
124 }
125
126
127
128
129
130
131
132
133
134 @Override
135 public void accept(final TaskData taskData)
136 {
137 tasks.add(taskData);
138 }
139
140 }
141
142
143
144
145
146
147
148
149
150
151 private TaskRepository createRepository()
152 {
153 final TaskRepository newRepository =
154 new TaskRepository(config.getIssueManagementId(),
155 config.getConnectionUrl());
156 newRepository.setProperty(TaskRepository.PROXY_USEDEFAULT, "false");
157
158 final String repositoryVersion = config.getRepositoryVersion();
159 if (StringUtils.isNotBlank(repositoryVersion))
160 {
161 newRepository.setVersion(repositoryVersion);
162 }
163
164 setAuthenicationInformation(newRepository);
165 return newRepository;
166 }
167
168
169
170
171
172
173
174 private void setAuthenicationInformation(final TaskRepository repository)
175 {
176 final String webUser = config.getWebUser();
177 final String webPassword = config.getWebPassword();
178
179 if (StringUtils.isNotBlank(webUser) && StringUtils.isNotBlank(webPassword))
180 {
181 if (log.isTraceEnabled())
182 {
183 log.trace("Setting web credentials '" + webUser + "' with password '"
184 + StringUtils.repeat("*", webPassword.length()) + "'.");
185 }
186 final AuthenticationCredentials credentials =
187 new AuthenticationCredentials(webUser, webPassword);
188 repository.setCredentials(AuthenticationType.HTTP, credentials, false);
189 }
190
191 final String issueManagementUser = config.getIssueManagementUser();
192 final String issueManagementPassword = config.getIssueManagementPassword();
193 if (StringUtils.isNotBlank(issueManagementUser)
194 && StringUtils.isNotBlank(issueManagementPassword))
195 {
196 if (log.isTraceEnabled())
197 {
198 log.trace("Setting repository credentials '" + issueManagementUser
199 + "' with password '"
200 + StringUtils.repeat("*", issueManagementPassword.length())
201 + "'.");
202 }
203 final AuthenticationCredentials credentials =
204 new AuthenticationCredentials(issueManagementUser,
205 issueManagementPassword);
206
207 repository.setCredentials(AuthenticationType.REPOSITORY, credentials,
208 false);
209 }
210 }
211
212
213
214
215
216 private void sleep()
217 {
218 try
219 {
220 Thread.sleep(config.getTimeout());
221 }
222 catch (final InterruptedException e)
223 {
224
225 }
226 }
227
228
229
230
231
232
233 public AbstractRepositoryConnector getConnector()
234 {
235 return connector;
236 }
237
238
239
240
241
242
243
244
245 public List<TaskData> queryTasks(final QueryData queryData)
246 throws MavenReportException
247 {
248 final SimpleTaskDataCollector collector = new SimpleTaskDataCollector();
249 runQuery(queryData, collector);
250 return fetchTaskData(collector);
251 }
252
253
254
255
256
257
258
259
260
261
262
263 private void runQuery(final QueryData queryData,
264 final SimpleTaskDataCollector collector) throws MavenReportException
265 {
266 if (log.isDebugEnabled())
267 {
268 log.debug("Searching for matching bugs...");
269 }
270
271 final int maxRetries = config.getMaxRetries();
272 final boolean ignoreLogoutProblem = config.isIgnoreLogoutProblem();
273 final IRepositoryQuery query = constructQuery(queryData);
274
275 if (log.isDebugEnabled())
276 {
277 log.debug("Connecting to " + query.getUrl() + " (max retries "
278 + maxRetries + ")...");
279 }
280 final IProgressMonitor monitor = new NullProgressMonitor();
281 for (int tryNumber = 0; tryNumber <= maxRetries; tryNumber++)
282 {
283 final IStatus status =
284 connector.performQuery(repository, query, collector, createSession(),
285 monitor);
286
287 if (log.isTraceEnabled())
288 {
289 log.trace("Query performed with status '" + status + "'.");
290 }
291
292 if (shouldBreak(status, ignoreLogoutProblem, maxRetries, tryNumber))
293 {
294 checkException(query, status);
295 break;
296 }
297 }
298
299 if (log.isTraceEnabled())
300 {
301 log.trace("Collected " + collector.getTasks().size() + " issues.");
302 }
303
304 }
305
306
307
308
309
310
311
312
313
314 private void checkException(final IRepositoryQuery query, final IStatus status)
315 throws MavenReportException
316 {
317 if (status.getSeverity() == IStatus.ERROR)
318 {
319 final MavenReportException e =
320 new MavenReportException("Problem connecting to '" + query.getUrl()
321 + "': " + status.getMessage());
322 e.initCause(status.getException());
323 throw e;
324 }
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 private boolean shouldBreak(final IStatus status,
348 final boolean ignoreLogoutProblem, final int maxRetries,
349 final int tryNumber) throws MavenReportException
350 {
351 if (status.getSeverity() == IStatus.ERROR)
352 {
353 final boolean logoutProblem = isLogoutProblem(status);
354 if (!logoutProblem || !ignoreLogoutProblem)
355 {
356 retry(status, maxRetries, tryNumber);
357 return false;
358 }
359 }
360 return true;
361 }
362
363
364
365
366
367
368
369
370
371
372 protected abstract boolean isLogoutProblem(IStatus status);
373
374
375
376
377
378
379
380
381
382
383
384 private void retry(final IStatus status, final int maxRetries,
385 final int tryNumber) throws MavenReportException
386 {
387 final String statusMessage = status.getMessage();
388 if (tryNumber == maxRetries)
389 {
390 throw new MavenReportException(statusMessage,
391 (Exception) status.getException());
392 }
393 else
394 {
395 if (log.isWarnEnabled())
396 {
397 log.warn("Connection (retry # " + tryNumber + "): " + statusMessage);
398 }
399 sleep();
400 }
401 }
402
403
404
405
406
407
408
409 protected ISynchronizationSession createSession()
410 {
411 return null;
412 }
413
414
415
416
417
418
419
420
421
422
423 private List<TaskData> fetchTaskData(
424 final SimpleTaskDataCollector hitCollector) throws MavenReportException
425 {
426 final TaskDataCache taskDataCache =
427 ResourceLocator.getInstance().getTaskDataCache();
428
429 final boolean logColumns = config.isLogColumns();
430 final Set<String> columnIds = logColumns ? new HashSet<String>() : null;
431 final int maxEntries = config.getMaxEntries();
432 final int maxRetries = config.getMaxRetries();
433 final List<TaskData> issues = new ArrayList<TaskData>(128);
434 try
435 {
436 int taskCounter = 0;
437 for (TaskData minimallyFilledTask : hitCollector.getTasks())
438 {
439 if (isQuit(maxEntries, taskCounter))
440 {
441 logQuitting(maxEntries);
442 break;
443 }
444
445 final String taskId = minimallyFilledTask.getTaskId();
446 logIssueId(taskId);
447
448 final TaskData completeTaskData =
449 fetchTaskData(taskDataCache, minimallyFilledTask, maxRetries);
450 if (completeTaskData != null)
451 {
452 addLogColumns(columnIds, completeTaskData);
453 issues.add(completeTaskData);
454 taskCounter++;
455 }
456 }
457 }
458 catch (CoreException e)
459 {
460 throw new MavenReportException(e.getMessage(), e);
461 }
462
463 if (logColumns)
464 {
465 log.info("Attribute IDs: " + new TreeSet<String>(columnIds));
466 }
467
468 return issues;
469 }
470
471
472
473
474
475
476 private void logIssueId(final String taskId)
477 {
478 if (log.isTraceEnabled())
479 {
480 log.trace("Retrieving issue: " + taskId);
481 }
482 }
483
484
485
486
487
488
489 private void logQuitting(final int maxEntries)
490 {
491 if (log.isDebugEnabled())
492 {
493 log.debug("Quitting fetching tasks after task " + maxEntries + '.');
494 }
495 }
496
497
498
499
500
501
502
503
504
505 private void addLogColumns(final Set<String> columnIds,
506 final TaskData taskData)
507 {
508 if (columnIds != null)
509 {
510 final TaskAttribute root = taskData.getRoot();
511 final Map<String, TaskAttribute> attributes = root.getAttributes();
512 final Set<String> attributeIds = attributes.keySet();
513 columnIds.addAll(attributeIds);
514 }
515 }
516
517
518
519
520
521
522
523
524
525 private static boolean isQuit(final int maxEntries, final int taskCounter)
526 {
527 return maxEntries != -1 && taskCounter >= maxEntries;
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541 private TaskData fetchTaskData(final TaskDataCache taskDataCache,
542 final TaskData minimallyFilledTask, final int maxRetries)
543 throws CoreException
544 {
545 for (int tryNumber = 0; tryNumber <= maxRetries; tryNumber++)
546 {
547 try
548 {
549 final TaskData completeTaskData =
550 readAndCacheTaskData(taskDataCache, minimallyFilledTask);
551 return completeTaskData;
552 }
553 catch (final CoreException e)
554 {
555 if (tryNumber == maxRetries)
556 {
557 throw e;
558 }
559 else
560 {
561 if (log.isWarnEnabled())
562 {
563 log.warn("Connection (retry # " + tryNumber + "): "
564 + e.getMessage());
565 }
566 sleep();
567 }
568 }
569 }
570 if (log.isWarnEnabled())
571 {
572 log.warn("No information for task " + minimallyFilledTask.getTaskId()
573 + "' can be retrieved. Omitting this bug from the report.");
574 }
575 return null;
576 }
577
578
579
580
581
582
583
584
585
586
587 private TaskData readAndCacheTaskData(final TaskDataCache taskDataCache,
588 final TaskData task) throws CoreException
589 {
590 final String id = task.getTaskId();
591 TaskData taskData = taskDataCache.getTask(id);
592 if (taskData == null)
593 {
594 taskData =
595 connector.getTaskData(repository, id, new NullProgressMonitor());
596 taskDataCache.addTask(taskData);
597 if (log.isTraceEnabled())
598 {
599 log.trace(" Cache miss for bug " + id + '.');
600 }
601 }
602 return taskData;
603 }
604
605
606
607
608
609
610
611
612
613
614
615
616 protected abstract IRepositoryQuery constructQuery(QueryData queryData)
617 throws MavenReportException;
618
619
620
621 }