| /******************************************************************************* |
| * Copyright (c) 2016. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| *******************************************************************************/ |
| package org.eclipse.mylyn.reviews.internal.core; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.Collection; |
| import java.util.Set; |
| |
| import org.eclipse.mylyn.internal.tasks.core.AbstractTask; |
| import org.eclipse.mylyn.internal.tasks.core.ITaskListChangeListener; |
| import org.eclipse.mylyn.internal.tasks.core.TaskContainerDelta; |
| import org.eclipse.mylyn.internal.tasks.core.TaskContainerDelta.Kind; |
| import org.eclipse.mylyn.internal.tasks.core.TaskList; |
| import org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager; |
| import org.eclipse.mylyn.internal.tasks.core.util.TasksCoreUtil; |
| import org.eclipse.mylyn.reviews.core.spi.ReviewsConnector; |
| import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; |
| import org.eclipse.mylyn.tasks.core.IRepositoryElement; |
| import org.eclipse.mylyn.tasks.core.ITask; |
| import org.eclipse.mylyn.tasks.core.data.TaskAttribute; |
| import org.eclipse.mylyn.tasks.core.data.TaskData; |
| |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.LinkedHashMultimap; |
| import com.google.common.collect.Multimaps; |
| import com.google.common.collect.SetMultimap; |
| |
| /** |
| * This class is used by review connectors to provide a mapping from tasks to reviews. These mappings are used by |
| * TaskEditorReviewPart to give a table of the reviews pertaining to a task. The class is limited as it maps one task to |
| * many reviews. It is however possible (albeit strange) to have multiple tasks for one review. This is a limitation by |
| * design. |
| * |
| * @author Blaine Lewis |
| */ |
| |
| @SuppressWarnings("restriction") |
| public class TaskReviewsMappingsStore implements ITaskListChangeListener { |
| static final String ATTR_ASSOCIATED_TASK = "org.eclipse.mylyn.associated.task"; //$NON-NLS-1$ |
| |
| private final SetMultimap<String, String> taskReviewsMap; |
| |
| private final TaskRepositoryManager repositoryManager; |
| |
| private final TaskList taskList; |
| |
| private static TaskReviewsMappingsStore instance; |
| |
| public TaskReviewsMappingsStore(TaskList taskList, TaskRepositoryManager repositoryManager) { |
| this.taskList = taskList; |
| this.repositoryManager = repositoryManager; |
| taskReviewsMap = Multimaps.synchronizedSetMultimap(LinkedHashMultimap.<String, String> create()); |
| } |
| |
| public void readFromTaskList() { |
| for (AbstractTask review : taskList.getAllTasks()) { |
| String task = getTaskUrl(review); |
| if (task != null) { |
| taskReviewsMap.put(task, review.getUrl()); |
| } |
| } |
| } |
| |
| private void updateMapping(ITask review, String newTaskUrl) { |
| String reviewUrl = review.getUrl(); |
| String oldTaskUrl = getTaskUrl(review); |
| |
| if (oldTaskUrl != null && !oldTaskUrl.equals(newTaskUrl)) { |
| taskReviewsMap.remove(oldTaskUrl, reviewUrl); |
| } |
| taskReviewsMap.put(newTaskUrl, reviewUrl); |
| review.setAttribute(ATTR_ASSOCIATED_TASK, newTaskUrl); |
| } |
| |
| /* |
| * This method of extracting URLs is deficient because if we have "(www.helloworld.com)" it will be |
| * a valid URL. This is difficult to format though so we won't handle that case. |
| */ |
| public void addTaskAssocation(ITask review, TaskData taskData) { |
| TaskAttribute attr = taskData.getRoot().getMappedAttribute(TaskAttribute.DESCRIPTION); |
| |
| if (attr == null) { |
| return; |
| } |
| |
| String oldTaskUrl = getTaskUrl(review); |
| String description = attr.getValue(); |
| for (String token : description.split("\\s+")) { //$NON-NLS-1$ |
| if (token.equals(oldTaskUrl)) { |
| return;// don't do expensive getTaskByUrl lookup if nothing changed |
| } else if (token.contains("://")) { //$NON-NLS-1$ |
| try { |
| new URL(token); |
| ITask task = getTaskByUrl(token); |
| |
| if (task != null) { |
| AbstractRepositoryConnector connector = repositoryManager |
| .getRepositoryConnector(task.getConnectorKind()); |
| if (!(connector instanceof ReviewsConnector)) { |
| updateMapping(review, task.getUrl() != null ? task.getUrl() : token); |
| return; |
| } |
| } |
| } catch (MalformedURLException e) { |
| //Do nothing, this is expected behavior when there is no URL |
| } |
| } |
| } |
| |
| deleteMappingsTo(review); |
| } |
| |
| public String getTaskUrl(ITask review) { |
| return review.getAttribute(ATTR_ASSOCIATED_TASK); |
| } |
| |
| public Collection<String> getReviewUrls(String taskUrl) { |
| synchronized (taskReviewsMap) { |
| return ImmutableSet.copyOf(taskReviewsMap.get(taskUrl)); |
| } |
| } |
| |
| ITask getTaskByUrl(String url) { |
| return TasksCoreUtil.getTaskByUrl(taskList, repositoryManager, url); |
| } |
| |
| @Override |
| public void containersChanged(Set<TaskContainerDelta> containers) { |
| for (TaskContainerDelta delta : containers) { |
| if (delta.getKind() == Kind.DELETED) { |
| IRepositoryElement reviewRepoElement = delta.getElement(); |
| |
| if (!(reviewRepoElement instanceof ITask)) { |
| continue; |
| } |
| |
| ITask review = (ITask) reviewRepoElement; |
| |
| //We need to check it in case the mapping was removed from the task |
| AbstractRepositoryConnector connector = repositoryManager |
| .getRepositoryConnector(review.getConnectorKind()); |
| |
| if (connector instanceof ReviewsConnector) { |
| deleteMappingsTo(review); |
| } |
| } |
| } |
| } |
| |
| private void deleteMappingsTo(ITask review) { |
| String taskUrl = getTaskUrl(review); |
| if (taskUrl != null) { |
| taskReviewsMap.remove(taskUrl, review.getUrl()); |
| review.setAttribute(ATTR_ASSOCIATED_TASK, null); |
| } |
| } |
| |
| public static void setInstance(TaskReviewsMappingsStore instance) { |
| TaskReviewsMappingsStore.instance = instance; |
| } |
| |
| public static TaskReviewsMappingsStore getInstance() { |
| return instance; |
| } |
| } |