Jump to: navigation, search

Mylyn/Porting Guide/3.0

< Mylyn‎ | Porting Guide
Revision as of 13:31, 8 December 2008 by Daviemoston.gmail.com (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Migrating from Mylyn 2.x to 3.0

Note: This porting guide is work in progress. Feel free to add contents.

This porting guide is intended to support developers porting connectors from Mylyn 2.x to Mylyn 3.x. In addition to the abbreviated pseudo code examples in this guide it is recommended to refer to the Bugzilla, Trac and JIRA connector implementations that are part of the Mylyn code base.

Migrating Tasks and Queries

In Mylyn 3.0 the data model of the task list has changed. Elements in the task list are now managed by the tasks framework and connectors do not extend AbstractTask or AbstractRepositoryQuery with their own implementation. Task list externalization that previously required connectors to provide an implementation of AbstractTaskListFactory is now encapsulated in the framework.

In order to migrate the Mylyn 2.x tasklist.xml.zip to the new tasks.xml.zip file connectors need to extend AbstractTaskListMigrator. When a Mylyn 2.x task list is read the migrator is invoked for migrating query and tasks elements. The migration is only done once.

The task list migrator is registered through the org.eclipse.mylyn.tasks.ui.repositories extension point. The taskListFactory element is replaced by taskListMigrator:

  name="Generic web-based access (Advanced)"
    <connectorCore ... />
    <connectorUi ... />
  name="Generic web-based access (Advanced)"
    <connectorCore ... />
    <connectorUi ... />

The implementating of AbstractTaskListFactory.createTask() has moved to AbstractTaskListMigrator.migrateTask(). Instead of creating an instance of a custom task class connector set custom state on task classes through the setAttribute() method.

Whether task data is up to date is now managed by the connector. The reference implementations use the last modification time stamp of task data to determine if a task is stale. In Mylyn 2.x the last modification time stamp was not stored in the task list but the last read time stamp which is the connector specific string that was stored in the DATE_MODIFICATION attribute on task data was set on a task when it was opened. The last read time stamp is not used anymore and must be migrated if connectors intend to use this as the last modification time stamp. Please note that the last read time stamp may not be set or not accurately reflect the last modification stamp of the latest downloaded task, e.g. when a task is new or when the latest state has not been read.

Connectors that used to override AbstractTask.getTaskKey() need to explicitly set the task key during migration. It is initialized to the task id by default:

class JiraTaskListMigrator {
	public void migrateTask(ITask task, Element element) {

Connectors that used to override AbstractTask.isLocal() must now implement AbstractRepositoryConnector.hasLocalCompletionState() instead.

Tip: AbstractTaskListFactory contains most of the information necessary to implement AbstractTaskListMigrator. For the migrateTask() and migrateQuery() methods, any data you use to set on your connector specific element must now be set as attributes on either the task or query being migrated. Use the task.setAttribute(String, String) method to set your connector specific key value pairs.

Porting Query Synchronization

In Mylyn 2.x AbstractRepositoryConnector.markStaleTasks() was invoked to indicate the start of a task list or query synchronization. The method has been replaced by preSynchronization() and postSynchronization() which have ISynchronizationSession paramater. The synchronization session is state associated with a particular synchronization. It has getters that specify details about the type synchronization.

Migrating markStaleTasks() to preSynchronization()

Previously AbstractTask.setStale() was used to indicate that a task requires synchronization. This is now done by invoking ISynchronizationSession.markStale(ITask). Connectors that fetch task data in preSynchronization() can store the data by invoking session.putTaskData().

The boolean return value of markStaleTasks() has been replaced by IsynchronizationSession.setNeedsPerformQueries(). The default is to perform queries but connectors may set the flag to false to indicate that the task list is up to date.

Porting performQuery()

The IqueryHitCollector interface has been replaced by TaskDataCollector which only accepts task data. Connectors that used to return AbstractTask may now use the framework class TaskMapper which provides a default schema for task data:

TaskData data = createTaskData(repository, id);
TaskMapper mapper = new TaskMapper(data, true);
mapper.setTaskUrl(taskPrefix + id);
mapper.setValue(KEY_TASK_PREFIX, taskPrefix);

The task framework will invoke AbstractRepositoryConnector.hasTaskChanged() for each returned TaskData object. Connectors may use a task property or a custom attribute to determine if the task data is up to date. TaskMapper has a method that compares attribute values on the task class with the values on task data to determine if a task has changed:

return new TaskMapper(taskData).hasChanges(task);

Migrating getSynchronizationTimestamp() to postSynchronization()

The default implementation of AbstractRepositoryConnector.getSynchronizationTimestamp() used to return the most recent modification time stamp of all tasks synchronized by a query. Connectors must now provide an implementation in postSynchronization() to persist synchronization information.

Please note that postSynchronization() will be called even if query or task synchronization fails. ISynchronizationSession.getStatus() will return a non-null value in case of an error.

Migrating updateTaskFromQueryHit() to updateTaskFromTaskData()

Since the task data collector now only accepts task data connectors must implement updateTaskFromTaskData(). If the default task schema is used TaskMapper.apply() may be sufficient:

TaskMapper mapper = new TaskMapper(taskData);

Porting Task Data Handling

Class names and packages for task data handling have changed. Classes are now located in the org.eclipse.mylyn.tasks.core.data. This table shows the old class names on the left and the new class names on the right:

Classes (old)


Classes (new)

TaskCommentMapper, ITaskComment
TaskAttachmentMapper, ITaskAttachment


Task data is now solely composed of attributes. Default implementations to store comments, attachments and operations in attributes are provied through mapper classes (see below). Each task data object has a root attribute that may have nested child attributes. Task attributes now have a reference to the enclosing task data instance that is set on construction time and is immutable:

RepositoryTaskData (old)

addAttribute("id", attribute)
setAttributeValue("id", "value")
addAttributeValue("id", "value")

TaskData (new)

attribute = getRoot().createAttribute("id)  /* or */  attribute = new TaskAttribute(taskData, "id")


RepositoryTaskAttribute has been renamed to TaskAttribute. The interface is very similar. The most significant change is that attribute properties are now accessed through the TaskAttributeMetaData class which adds an explicit notion of types to attributes. Types supported by the tasks framework are defined in TaskAttribute.TYPE_* constants.

RepositoryTaskAttribute (old)


TaskAttribute (new)


An attribute needs to have valid meta data to become visible in the attribute section of the task editor. Here is an example how to set the meta data (also see JiraTaskDataHandler.createAttribute()):

	.setLabel("My Attribute")

It is important to set a valid type and kind. Framework supported Types are defined in the TaskAttribute.TYPE_* constants. Currently TaskAttribute.KIND_DEFAULT is the only supported kind.

Attribute Mapping

The former TaskAttributeFactory mirrors the new AttributeMapper class. Simply extend this new class and override mapToRepositoryKey() leveraging most of the code from your previous factory class. The purpose of this method is to map from framework attribute ids to the corresponding key used by your repository. Note that the framework attribute id is the String key parameter of mapToRepositoryKey, not the TaskAttribute parameter. When retrieving the priority of a task, the framework will request attribute with id "common.priority". Your connector may refer to its native field that represents priority via a different key i.e "myconnector.priority" for example. In this case, the AttributeMapper.mapToRepositoryKey() method you implement must perform the appropriate conversion, returning "myconnector.priority" when "common.priority" is provided.

In addition to providing attribute mappings the TaskAttributeFactory provides methods for serializing Java types to task attributes which stores lists of Strings. Default implementations are provided for common types used by the framework such as Boolean, Date and Integer objects. Clients may override the methods to specify a custom format.


Attachments are now stored in a connector specific schema as TaskAttributes. TaskAttributeMapper maps attachment attributes to ITaskAttachment objects. The default mapper TaskAttachmentMapper may be used to create attachment attributes.


Comments are now stored in a connector specific schema as TaskAttributes. TaskAttributeMapper maps comment attributes to ITaskComment objects. The default mapper TaskCommentMapper may be used to create comment attributes.


Operations (actions) are now just another attribute stored in the task data. To create an operation:

TaskAttribute myoperation = taskData.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + myoperationId); 
TaskOperation.applyTo(attribute, myoperationId, operationLabel);

Often operations require input, for example, when reassigning a task, you want to select the reassign operation and provide the target users id as input to the operation. To provide the input capability, simply add another attribute to the task data with the TYPE specified (TaskAttribute.TYPE_SHORT_TEXT for example to take text input). Associate the operation with this input attribute using the TaskAttribute.META_ASSOCIATED_ATTRIBUTE on the operation attribute.

TaskAttribute operationInputAttribute = taskData.getTaskData().getRoot().createAttribute(inputAttributeId); 
myoperation.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, inputAttributeId);

Migrating Task Data

If you are seeing fields showing up as blue (incoming) within the editor upon opening an old task with your new connector code) These erroneous incoming are the result of failure to successfully migrate 2.x offline task data to the new 3.0 format. If this is the case, you can help migration along (do additional migration work) by overriding AbstractTaskDataHandler.migrateTaskData().

This example from TracTaskDataHandler removed the reassign operation which is not used by the Trac connector in the latest release. The version field of task data is managed by the client and used to keep track of the format of task data. The version is null unless explicitly set by the connector.

public void migrateTaskData(TaskRepository taskRepository, TaskData taskData) {
	int version = 0;
	if (taskData.getVersion() != null) {
		try {
			version = Integer.parseInt(taskData.getVersion());
		} catch (NumberFormatException e) {
	if (version < 1) {
		TaskAttribute root = taskData.getRoot();
		List<TaskAttribute> attributes = new ArrayList<TaskAttribute>(root.getAttributes().values());
		for (TaskAttribute attribute : attributes) {
			if (TaskAttribute.TYPE_OPERATION.equals(attribute.getMetaData().getType())
					&& "reassign".equals(attribute.getValue())) {

Porting AbstractTaskDataHandler

Some of the methods in AbstractTaskDataHandler have moved. Cloning of tasks is now handled through the ITaskMapping interface. Clients may override AbstractRepositoryConnector.getTaskMapping() to provide a custom implementation for clonging tasks by overridding ITaskMapping.merge(). The getTaskData() and getSubTaskIds() methods have moved to AbstractRepositoryConnector to reflect that all connectors now return task data as query results.

AbstractTaskDataHandler (old)

cloneTaskData(source, target)


new TaskMapper(target).merge(new TaskMapper(source))

Porting Attachment Handling

Attachment handling is now entirely stream based. Methods for handling attachment contents using byte arrays have been removed. When uploading attachments an optional TaskAttribute object is provided that may set additional connector specific properties such as hints for deprecating attachments.

AbstractAttachmentHandler (old)


AbstractTaskAttachmentHandler (new)


Porting Web Access

The API for web-based access through HttpClient with support for password prompting and cancellation is described in Mylyn/Architecture/Web.

Porting Duplicate Detectors

In addition to specifying a duplicate detector through the org.eclipse.mylyn.tasks.ui.duplicateDetectors extension point and extending AbstractDuplicateDetector connectors can implement a search handler that extends AbstractSearchHandler. These search handlers are used by duplicate detectors such as the StackTraceDuplicateDetector to provide a generic duplicate detection without requiring connectors to duplicate the logic for detecting stack traces.

class JiraSearchHandler extends AbstractSearchHandler {
  public boolean queryForText(TaskRepository taskRepository, IRepositoryQuery query, TaskData taskData, String searchString) {
    FilterDefinition filter = new FilterDefinition();
    filter.setContentFilter(new ContentFilter(searchString, false, true, false, true));
    JiraUtil.setQuery(taskRepository, query, filter);
    return true;
// register search handler
TasksUiPlugin.getDefault().addSearchHandler(new JiraSearchHandler());

Porting Query Wizards

Extenders of AbstractRepositoryQueryPage must now override applyTo() instead of getQuery().

The tasks framework now provides a default implementation for query wizards in the RepositoryQueryWizard class. Connectors may instantiate this class and add pages that extends AbstractRepositoryQueryPage:

public IWizard getQueryWizard(TaskRepository repository, IRepositoryQuery query) {
  RepositoryQueryWizard wizard = new RepositoryQueryWizard(repository);
  wizard.addPage(new WebQueryWizardPage(repository, query));
  return wizard;

Porting Task Editors

AbstractTaskEditorFactory has been replaced by AbstractTaskEdiorPageFactory which is registered through the org.eclipse.mylyn.tasks.ui.editors extension point.


Task editors are not decomposed into parts that can be replaced with custom implemenations by overridding AbstractTaskEditorPage.createPartDescriptors(). Controls for editing task attributes are now encapsulated in subclasses of AbstractAttributeEditor which are created through a factory provided by AbstractTaskEditorPage.createAttributeEditorFactory(). Clients may override this method to provide a factory that supports custom attribute types. See TracTaskEditorPage for an example.

API Changes

Plug-in Refactorings

  • org.eclipse.mylyn.web.core is now org.eclipse.mylyn.commons.net
  • Core classes from org.eclipse.mylyn.monitor.core was split in order to make API not coupled to the Monitor component be reusable independently, now in the new org.eclipse.mylyn.commons.core plug-in.
  • org.eclipse.mylyn.commons.ui is a new API for common UI components that are not coupled to the rest of Mylyn.

Changed Extension Points

  • org.eclipse.mylyn.tasks.ui.editors
    • hyperLinkDetector has been removed, use org.eclipse.ui.workbench.texteditor.hyperlinkDetectors instead and set targetId to org.eclipse.mylyn.tasks.ui.TaskEditor
    • editorFactory has been removed, use pageFactory instead
  • repositories
    • taskListFactory has been removed, use taskListMigrator instead
    • connectorCore
      • userManaged has been removed, override isUserManaged() in AbstractRepositoryConnector instead
    • connectorUi
      • customNotifications has been removed, override isCustomNotification() in AbstractRepositoryConnectorUi instead

New Context API

  • AbstractFocusViewAction.updateEnablementWithContextActivation(): override to return false for focus actions that are not related to context activations (e.g. the Task List).
  • AbstractFocusViewAction.setLinkingActionEnabled(boolean): should be overridden if view provides linking

Removed Context API

  • ActivityTimerThread has been removed
  • BrowseFilteredAction has been moved to an internal package
  • ContextCorePlugin has been moved to an internal package and replaced by ContextCore
  • ContextUiPlugin has been moved to an internal package and replaced by ContextUi
  • IActivityTimerListener has been removed
  • IInteractionContextListener has been renamed to AbstractContextListener
  • InteractionContextReader has been moved to an internal package
  • InteractionContextWriter has been moved to an internal package
  • MonitorUiPlugin has been moved to an internal package and replaced by MonitorUi
  • ResourcesUiPlugin has been moved to an internal package and replaced by ResourcesUi
  • The active/auto folding preference has been removed, you can reuse the one from JavaUiBridgePlugin or use your own preference

New Monitor API

  • MonitorUiPlugin.getMonitoredWindows(): use insteand of PlatformUI.getWorkbench().getWorkbenchWindows()
  • MonitorUiPlugin.getLaunchingWorkbenchWindow(): use to get the first active window when the monitor started.

Removed Monitor API

  • IMylarMonitorLifecycleListener has been renamed to IMonitorLifecycleListener
  • ReportGenerator has been moved to an internal package

Changed Team API

  • org.eclipse.mylyn.tasks.core.ILinkedTaskInfo is now org.eclipse.mylyn.team.ui.AbstractTaskReference
    • getComment() has been renamed to getText()

Removed Tasks API

Some deprecated types and methods have been moved to the internal package org.eclipse.mylyn.internal.tasks.core.deprecated. This package is not intended as a backwards compatibility layer and is expected to be removed as part of the 3.1 release.

  • AbstractAttachmentHandler has been removed, use AbstractTaskAttachmentHandler instead
    • MYLAR_CONTEXT_DESCRIPTION has been removed
    • MYLAR_CONTEXT_FILENAME has been removed
    • attachContextAttachments() has been moved to the internal class AttachmentUtil
    • getContextAttachments() has been moved to the internal class AttachmentUtil
    • hasRepositoryContext() has been moved to the internal class AttachmentUtil
    • retrieveContext() has been moved to the internal class AttachmentUtil
  • AbstractAttributeFactory has been removed, use TaskAttributeMapper instead
  • AbstractDuplicateDetector has been moved to tasks.core
  • AbstractEditQueryWizard has been renamed to AbstractRepositoryQueryWizard
  • AbstractNewRepositoryTaskEditor has been removed, use AbstractTaskEditorPage instead
  • AbstractRepositoryConnector
    • init() has been removed
    • getAttachmentHandler() has been renamed to getTaskAttachmentHandler()
    • createTaskFromExistingId() has been removed
    • createTaskFromTaskData() has been removed, use updateTaskFromTaskData() instead
    • createTask() has been removed, use RepositoryModel.createTask() instead
    • getPepositoryPropertyNames() has been removed
    • getTemplate() has been removed, use RepositoryTemplateManager instead
    • hasTaskPropertyChanged() has been removed
    • updateTaskFromRepository() has been removed, use updateTaskFromTaskData() instead
    • updateTaskFromQueryHit() has been removed, use updateTaskFromTaskData() instead
    • markStaleTasks() has been removed, override preSynchronization() instead
    • removeTemplate() has been removed, use RepositoryTemplateManager instead
    • updateAttributes() has been renamed to updateRepositoryConfiguration()
    • setUserManaged() has been removed, override isUserManaged() instead
  • AbstractRepositoryConnectorUi
    • forceSubtaskHierarchy() has been removed, override hasStrictSubtaskHierarchy() instead
    • getLegendItems() has been renamed to getLegendElements()
    • getNewTaskWizard(TaskRepository) has been removed, use getNewTaskWizard(TaskRepository, ITaskMapping) instead
    • getTaskKindLabel(RepositoryTaskData) has been removed
    • getTaskListElementIcon() has been removed, override getImageDescriptor() instead
    • isCustomNotificationHandling() has been removed, override hasCustomNotificationHandling() instead
    • openEditQueryDialog(AbstractRepositoryQuery) has been moved to the internal class TasksUiInternal
    • openRepositoryTask() has been moved to the internal class TasksUiInternal
    • setCustomNotificationHandling() has been removed, override hasCustomNotificationHandling() instead
    • supportsDueDates(AbstractTask) has been removed, override AbstractRepositoryConnector.hasRepositoryDueDate() instead
  • AbstractRepositoryQuery has been removed, use IRepositoryQuery instead
    • getRepositoryKind() has been renamed to getConnectorKind()
  • AbstractRepositoryQueryPage has been moved to org.eclipse.mylyn.tasks.ui.wizards
  • AbstractRepositoryTaskEditor has been removed, use AbstractTaskEditorPage instead
  • AbstractRepositoryQueryWizard has been removed, use RepositoryQueryWizard instead
  • AbstractTask has been removed, use ITask instead
    • hasValidUrl() has been moved to TasksUiInternal.isValidUrl()
    • setCompleted() has been removed, a non-null completion date indicates a task is complete
  • AttributeContainer has been removed, use TaskAttribute instead
  • AuthenticatedProxy has been moved to an internal package
  • DatePicker has been moved to org.eclipse.mylyn.commons.ui
  • DateSelectionDialog has been moved to org.eclipse.mylyn.commons.ui
  • FileAttachment has been removed, use AbstractTaskAttachmentSource instead
  • GzipGetMethod has been moved to an internal package
  • GzipPostMethod has been moved to an internal package
  • IStatusHandler has been removed, use AbstractErrorReporter instead
  • ITaskCollector has been removed, use TaskDataCollector instead
  • ITaskFactory has been removed
  • ITaskRepositoryListener has been renamed to IRepositoryListener
  • ITaskListChangeListener has been moved to an internal package
  • NewTaskEditorInput has been removed, use TaskEditorInput instead
  • QueryHitCollector has been removed, use TaskDataCollector instead
  • RepositoryAttachment has been removed, use TaskAttachmentMapper instead
  • RepositoryOperation has been removed, use TaskOperationMapper instead
  • RepositorySearchResult has been moved to an internal package
  • RepositoryTaskData has been removed, use TaskData instead
  • RepositoryTaskEditorInput has been removed, use TaskEditorInput instead
  • SearchHitCollector has been moved to an internal package
  • SslProtocolSocketFactory has been moved to an internal package
  • StatusHandler
    • addDefaultStatusHandler(IStatusHandler) has been removed
    • addStatusHandler(IStatusHandler) has been removed
    • fail(Throwable,String,boolean) has been removed
    • fail(Throwable,String,boolean,int) has been removed
    • getDefaultStatusHandler() has been removed
    • getStatusHandler() has been removed
    • log(String,Object) has been removed
    • log(Throwable,String) has been removed
    • setDefaultStatusHandler(IStatusHandler) has been removed
    • removeStatusHandler(IStatusHandler) has been removed
  • TaskActivityManager
    • getInstance() has been removed, use TasksUiPlugin.getTaskActivityManager() instead
    • init() has been replaced by a public constructor
  • TaskFormPage
    • actionContributor has been removed
  • TaskFactory has been removed
  • TaskListManager has been moved to an internal package and replaced by ITaskListManager
    • task activity related methods have been removed (see TaskActivityManager)
  • TaskRepositoryManager has been moved to an internal package and replaced by ITaskRepositoryManager
  • TaskEditor
    • configureContextMenuManager(MenuManager,TextViewer) has been removed
    • getAdapterDelegate() has been removed
    • getContributor() has been removed
    • refreshEditorContents() has been renamed to refreshPages()
  • TaskList has been moved to an internal package and replaced by ITaskList
  • TaskSelection has been removed, use ITaskMapping instead
  • TasksUiProxyChangeListener has been removed
  • TasksUiUtil
    • closeEditorInActivePage(ITask,boolean) has been moved to the internal class TasksUiInternal
    • getActiveRepositoryTaskEditor() has been moved to the internal class TasksUiInternal
    • isAnimationsEnabled() has been moved to the internal class TasksUiInternal
    • openEditor(TaskCategory) has been moved to the internal class TasksUiInternal
    • openEditor(AbstractTask, boolean) has been replaced by openTask(ITask)
    • openEditor(AbstractTask, boolean, boolean) has been replaced by openTask(ITask)
    • openEditor(AbstractTask, String) has been replaced by openTask(ITask)
    • openUrl(String, boolean) has been replaced by openTask(String) and openUrl(String)
    • refreshAndOpenTaskListElement() has been moved to the internal class TasksUiInternal
    • showPreferencesPage(String, IPreferencePAge) has been removed
  • TrustAllTrustManager has been moved to an internal package
  • WebClientLog has been removed
  • WebClientUtil has been removed, use WebUtil instead
  • WebCorePlugin has been moved to an internal package
  • WebHyperlink has been moved to an internal package