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