/*******************************************************************************
* Copyright (c) 2004, 2010 Tasktop Technologies and others.
* 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
*
* Contributors:
* Tasktop Technologies - initial API and implementation
* Atlassian - improvements for bug 319397
*******************************************************************************/
package org.eclipse.mylyn.tasks.core;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentHandler;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
import org.eclipse.mylyn.tasks.core.data.TaskHistory;
import org.eclipse.mylyn.tasks.core.data.TaskMapper;
import org.eclipse.mylyn.tasks.core.data.TaskRelation;
import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession;
/**
* Encapsulates common operations that can be performed on a task repository. Extend to connect with a Java API or WS
* API for accessing the repository. Only methods that take a progress monitor can do network I/O.
*
* @author Mik Kersten
* @author Rob Elves
* @author Shawn Minto
* @since 2.0
*/
public abstract class AbstractRepositoryConnector {
private static final long REPOSITORY_CONFIGURATION_UPDATE_INTERVAL = 24 * 60 * 60 * 1000;
/**
* Returns true, if the connector provides a wizard for creating new tasks.
*
* @since 2.0
*/
// TODO move this to ConnectorUi.hasNewTaskWizard()
public abstract boolean canCreateNewTask(TaskRepository repository);
/**
* Returns true, if the connector supports retrieval of tasks based on String keys.
*
* @since 2.0
*/
public abstract boolean canCreateTaskFromKey(TaskRepository repository);
/**
* Returns true, if the connector supports retrieval of task history for <code>task</code>.
*
* @see #getHistory(TaskRepository, ITask, IProgressMonitor)
* @since 3.6
*/
public boolean canGetTaskHistory(TaskRepository repository, ITask task) {
return false;
}
/**
* @since 3.0
*/
public boolean canQuery(TaskRepository repository) {
return true;
}
/**
* @since 3.0
*/
public boolean canSynchronizeTask(TaskRepository taskRepository, ITask task) {
return true;
}
/**
* Returns true, if the connector supports deletion of <code>task</code> which is part of <code>repository</code>.
*
* @since 3.3
*/
public boolean canDeleteTask(TaskRepository repository, ITask task) {
return false;
}
/**
* Return true, if the connector supports creation of task repositories. The default default implementation returns
* true.
*
* @since 3.4
*/
public boolean canCreateRepository() {
return true;
}
/**
* Returns the unique kind of the repository, e.g. "bugzilla".
*
* @since 2.0
*/
public abstract String getConnectorKind();
/**
* The connector's summary i.e. "JIRA (supports 3.3.1 and later)"
*
* @since 2.0
*/
public abstract String getLabel();
/**
* Can return null if URLs are not used to identify tasks.
*/
public abstract String getRepositoryUrlFromTaskUrl(String taskFullUrl);
/**
* Returns a short label for the connector, e.g. Bugzilla.
*
* @since 2.3
*/
public String getShortLabel() {
String label = getLabel();
if (label == null) {
return null;
}
int i = label.indexOf("("); //$NON-NLS-1$
if (i != -1) {
return label.substring(0, i).trim();
}
i = label.indexOf(" "); //$NON-NLS-1$
if (i != -1) {
return label.substring(0, i).trim();
}
return label;
}
/**
* @since 3.0
*/
public AbstractTaskAttachmentHandler getTaskAttachmentHandler() {
return null;
}
/**
* @since 3.0
*/
public abstract TaskData getTaskData(TaskRepository taskRepository, String taskId, IProgressMonitor monitor)
throws CoreException;
/**
* @since 3.0
*/
public AbstractTaskDataHandler getTaskDataHandler() {
return null;
}
/**
* @since 2.0
*/
public abstract String getTaskIdFromTaskUrl(String taskFullUrl);
/**
* Used for referring to the task in the UI.
*/
public String getTaskIdPrefix() {
return "task"; //$NON-NLS-1$
}
/**
* @since 2.0
*/
public String[] getTaskIdsFromComment(TaskRepository repository, String comment) {
return null;
}
/**
* @since 3.0
*/
public ITaskMapping getTaskMapping(TaskData taskData) {
return new TaskMapper(taskData);
}
/**
* Connectors can override to return other tasks associated with this task.
*
* @since 3.0
*/
public Collection<TaskRelation> getTaskRelations(TaskData taskData) {
return null;
}
/**
* @since 2.0
*/
public abstract String getTaskUrl(String repositoryUrl, String taskId);
/**
* Returns a URL for <code>element</code> that contains authentication information such as a session ID.
* <p>
* Returns <code>null</code> by default. Clients may override.
*
* @param repository
* the repository for <code>element</code>
* @param element
* the element to return the authenticated url for
* @return null, if no corresponding authenticated URL is available for <code>element</code>; the URL, otherwise
* @see IRepositoryElement#getUrl()
* @since 3.4
*/
public URL getAuthenticatedUrl(TaskRepository repository, IRepositoryElement element) {
return null;
}
/**
* @since 3.0
*/
public abstract boolean hasTaskChanged(TaskRepository taskRepository, ITask task, TaskData taskData);
/**
* @since 3.0
*/
public boolean hasLocalCompletionState(TaskRepository taskRepository, ITask task) {
return false;
}
/**
* @since 3.0
*/
public boolean hasRepositoryDueDate(TaskRepository taskRepository, ITask task, TaskData taskData) {
return false;
}
/**
* Default implementation returns true every 24hrs.
*
* @return true to indicate that the repository configuration is stale and requires update
* @since 3.0
*/
public boolean isRepositoryConfigurationStale(TaskRepository repository, IProgressMonitor monitor)
throws CoreException {
Date configDate = repository.getConfigurationDate();
if (configDate != null) {
return (new Date().getTime() - configDate.getTime()) > REPOSITORY_CONFIGURATION_UPDATE_INTERVAL;
}
return true;
}
/**
* @since 2.0
*/
public boolean isUserManaged() {
return true;
}
/**
* Runs <code>query</code> on <code>repository</code>, results are passed to <code>collector</code>. If a repository
* does not return the full task data for a result, {@link TaskData#isPartial()} will return true.
* <p>
* Implementors must complete executing <code>query</code> before returning from this method.
*
* @param repository
* task repository to run query against
* @param query
* query to run
* @param collector
* callback for returning results
* @param session
* provides additional information for running the query, may be <code>null</code>
* @param monitor
* for reporting progress
* @return {@link Status#OK_STATUS} in case of success, an error status otherwise
* @throws OperationCanceledException
* if the query was canceled
* @since 3.0
*/
public abstract IStatus performQuery(TaskRepository repository, IRepositoryQuery query,
TaskDataCollector collector, ISynchronizationSession session, IProgressMonitor monitor);
/**
* Delete the task from the server
*
* @throws UnsupportedOperationException
* if this is not implemented by the connector
* @since 3.3
*/
public IStatus deleteTask(TaskRepository repository, ITask task, IProgressMonitor monitor) throws CoreException {
throw new UnsupportedOperationException();
}
/**
* Hook into the synchronization process.
*
* @since 3.0
*/
public void postSynchronization(ISynchronizationSession event, IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask("", 1); //$NON-NLS-1$
} finally {
monitor.done();
}
}
/**
* Hook into the synchronization process.
*
* @since 3.0
*/
public void preSynchronization(ISynchronizationSession event, IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask("", 1); //$NON-NLS-1$
} finally {
monitor.done();
}
}
/**
* Updates the local repository configuration cache (e.g. products and components). Connectors are encouraged to
* implement {@link #updateRepositoryConfiguration(TaskRepository, ITask, IProgressMonitor)} in addition this
* method.
*
* @param repository
* the repository to update configuration for
* @since 3.0
* @see #isRepositoryConfigurationStale(TaskRepository, IProgressMonitor)
*/
public abstract void updateRepositoryConfiguration(TaskRepository taskRepository, IProgressMonitor monitor)
throws CoreException;
/**
* Updates the local repository configuration cache (e.g. products and components). The default implementation
* invokes {@link #updateRepositoryConfiguration(TaskRepository, IProgressMonitor)}.
*
* @param repository
* the repository to update configuration for
* @param task
* if not null, limit the update to the details relevant to task
* @see #updateRepositoryConfiguration(TaskRepository, IProgressMonitor)
* @since 3.3
*/
public void updateRepositoryConfiguration(TaskRepository taskRepository, ITask task, IProgressMonitor monitor)
throws CoreException {
updateRepositoryConfiguration(taskRepository, monitor);
}
/**
* @since 3.0
*/
public abstract void updateTaskFromTaskData(TaskRepository taskRepository, ITask task, TaskData taskData);
/**
* Called when a new task is created, before it is opened in a task editor. Connectors should override this method
* if they need information from the {@link TaskData} to determine kind labels or other information that should be
* displayed in a new task editor.
*
* @since 3.5
*/
public void updateNewTaskFromTaskData(TaskRepository taskRepository, ITask task, TaskData taskData) {
}
/**
* Invoked when a task associated with this connector is migrated. This typically happens when an unsubmitted task
* is submitted to the repository. Implementers may override to implement custom migration rules.
* <p>
* Does nothing by default.
*
* @param event
* provides additional details
* @since 3.4
*/
public void migrateTask(TaskMigrationEvent event) {
}
/**
* Returns if the user using the repository is the owner of the task. Subclasses may override.
*
* @param repository
* repository task is associated with
* @param task
* task to determined ownership of
* @return true if user using the repository is owner of the task
* @since 3.5
*/
public boolean isOwnedByUser(TaskRepository repository, ITask task) {
if (task.getOwner() != null) {
return task.getOwner().equals(repository.getUserName());
}
return false;
}
/**
* Retrieves the history for <code>task</code>. Throws {@link UnsupportedOperationException} by default.
*
* @param repository
* the repository
* @param task
* the task to retrieve history for
* @param monitor
* a progress monitor
* @return the history for <code>task</code>
* @throws CoreException
* thrown in case retrieval fails
* @see #canGetHistory(TaskRepository, ITask)
* @since 3.6
*/
public TaskHistory getTaskHistory(TaskRepository repository, ITask task, IProgressMonitor monitor)
throws CoreException {
throw new UnsupportedOperationException();
}
// /**
// * Returns a specific revision of a task. Sub-classes may override.
// *
// * @return null, if the revision is not found
// * @since 3.6
// * @see TaskHistory
// * @see #getTaskHistory(TaskRepository, ITask, IProgressMonitor)
// */
// public TaskData getTaskData(TaskRepository repository, ITask task, String revisionId, IProgressMonitor monitor)
// throws CoreException {
// Assert.isNotNull(repository);
// Assert.isNotNull(task);
// Assert.isNotNull(revisionId);
// return null;
// }
}