/******************************************************************************* * Copyright (c) 2004, 2008 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 *******************************************************************************/ package org.eclipse.mylyn.internal.tasks.core.data; import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; import org.eclipse.mylyn.tasks.core.IRepositoryManager; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper; import org.eclipse.mylyn.tasks.core.data.TaskData; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * @author Steffen Pingel */ public class TaskDataStateReader extends DefaultHandler { private class AttachmentHandler10 extends ElementHandler { private int id; private TaskAttribute attribute; private final TaskAttribute parentAttribute; public AttachmentHandler10(ElementHandler parent, TaskAttribute parentAttribute) { super(parent, ITaskDataConstants.ELEMENT_ATTACHMENT); this.parentAttribute = parentAttribute; } @Override protected void end(String uri, String localName, String name) { TaskAttribute child = attribute.getAttribute(TaskAttribute.ATTACHMENT_ID); if (child != null) { attribute.setValue(child.getValue()); } } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { // create a unique id for each attachment since the actual id is in a child attribute attribute = createAttribute(parentAttribute, TaskAttribute.PREFIX_ATTACHMENT + ++id); attribute.getMetaData().defaults().setReadOnly(true).setType(TaskAttribute.TYPE_ATTACHMENT); // the actual attachment id is stored in a child node an correctly set in end() attribute.setValue(id + ""); //$NON-NLS-1$ TaskAttribute child = createAttribute(attribute, TaskAttribute.ATTACHMENT_AUTHOR); child.setValue(getValue(attributes, ITaskDataConstants.ATTRIBUTE_CREATOR)); child.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_PERSON); child = createAttribute(attribute, TaskAttribute.ATTACHMENT_IS_DEPRECATED); child.setValue(getValue(attributes, ITaskDataConstants.ATTRIBUTE_IS_OBSOLETE)); child.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_BOOLEAN); child = createAttribute(attribute, TaskAttribute.ATTACHMENT_IS_PATCH); child.setValue(getValue(attributes, ITaskDataConstants.ATTRIBUTE_IS_PATCH)); child.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_BOOLEAN); addElementHandler(new AttributeHandler10(this, attribute) { @Override protected String mapId(String value) { // migrate key for description if (TaskAttribute.DESCRIPTION.equals(value)) { return TaskAttribute.ATTACHMENT_DESCRIPTION; } return super.mapId(value); } }); } } private class AttributeHandler10 extends ElementHandler { private TaskAttribute attribute; private final TaskAttribute parentAttribute; public AttributeHandler10(ElementHandler parent, TaskAttribute parentAttribute) { super(parent, ITaskDataConstants.ELEMENT_ATTRIBUTE); this.parentAttribute = parentAttribute; } @Override protected void end(String uri, String localName, String name) { // detect type if (attribute.getOptions().size() > 0) { if (attribute.getValues().size() > 1) { attribute.getMetaData() .putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_MULTI_SELECT); } else { attribute.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_SINGLE_SELECT); } } } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { String id = mapId(getValue(attributes, ITaskDataConstants.ATTRIBUTE_ID)); String label = getValue(attributes, ITaskDataConstants.ATTRIBUTE_NAME); boolean hidden = Boolean.parseBoolean(getValue(attributes, ITaskDataConstants.ATTRIBUTE_HIDDEN)); boolean readOnly = Boolean.parseBoolean(getValue(attributes, ITaskDataConstants.ATTRIBUTE_READONLY)); attribute = parentAttribute.createAttribute(id); String kind = (hidden) ? null : TaskAttribute.KIND_DEFAULT; attribute.getMetaData().defaults().setLabel(label).setReadOnly(readOnly).setKind(kind); addElementHandler(new OptionHandler10(this, attribute)); addElementHandler(new ValueHandler10(this, attribute)); addElementHandler(new MetaDataHandler10(this, attribute)); } protected String mapId(String value) { return value; } } private class AttributeHandler20 extends ElementHandler { private TaskAttribute attribute; private final TaskAttribute parentAttribute; public AttributeHandler20(ElementHandler parent, TaskAttribute parentAttribute) { super(parent, ITaskDataConstants.ELEMENT_ATTRIBUTE); this.parentAttribute = parentAttribute; } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { String id = getValue(attributes, ITaskDataConstants.ATTRIBUTE_ID); attribute = parentAttribute.createAttribute(id); addElementHandler(new ValueHandler20(this, attribute)); addElementHandler(new MapHandler20(this, attribute, ITaskDataConstants.ELEMENT_OPTION)); addElementHandler(new MapHandler20(this, attribute, ITaskDataConstants.ELEMENT_META)); addElementHandler(new AttributeHandler20(this, attribute)); } } private class CommentHandler10 extends ElementHandler { private int id; private TaskAttribute attribute; private final TaskAttribute parentAttribute; public CommentHandler10(ElementHandler parent, TaskAttribute parentAttribute) { super(parent, ITaskDataConstants.ELEMENT_COMMENT); this.parentAttribute = parentAttribute; } @Override protected void end(String uri, String localName, String name) { TaskAttribute child = attribute.getMappedAttribute(TaskAttribute.COMMENT_TEXT); if (child != null) { child.getMetaData().putValue(TaskAttribute.META_READ_ONLY, Boolean.toString(true)); child.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_LONG_RICH_TEXT); } } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { attribute = createAttribute(parentAttribute, TaskAttribute.PREFIX_COMMENT + ++id); attribute.getMetaData().defaults().setReadOnly(true).setType(TaskAttribute.TYPE_COMMENT); attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, TaskAttribute.COMMENT_TEXT); attribute.setValue(getValue(attributes, ITaskDataConstants.ATTRIBUTE_NUMBER)); TaskAttribute child = createAttribute(attribute, TaskAttribute.COMMENT_ATTACHMENT_ID); child.setValue(getValue(attributes, ITaskDataConstants.ATTRIBUTE_ATTACHMENT_ID)); child = createAttribute(attribute, TaskAttribute.COMMENT_HAS_ATTACHMENT); child.setValue(getValue(attributes, ITaskDataConstants.ATTRIBUTE_HAS_ATTACHMENT)); child.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_BOOLEAN); child = createAttribute(attribute, TaskAttribute.COMMENT_NUMBER); child.setValue(getValue(attributes, ITaskDataConstants.ATTRIBUTE_NUMBER)); child.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_INTEGER); addElementHandler(new AttributeHandler10(this, attribute)); } } private class MetaDataHandler10 extends ElementHandler { private final TaskAttribute attribute; private String key; public MetaDataHandler10(ElementHandler parent, TaskAttribute attribute) { super(parent, ITaskDataConstants.ELEMENT_META); this.attribute = attribute; } @Override public void end(String uri, String localName, String name) { attribute.getMetaData().putValue(key, getCurrentElementText()); } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { key = getValue(attributes, ITaskDataConstants.ATTRIBUTE_KEY); clearCurrentElementText(); } } private class NameHandler extends ElementHandler { private final TaskAttribute attribute; private String value; public NameHandler(ElementHandler parent, TaskAttribute attribute) { super(parent, ITaskDataConstants.ELEMENT_NAME); this.attribute = attribute; } @Override public void end(String uri, String localName, String name) { attribute.putOption(value, getCurrentElementText()); } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { value = getValue(attributes, ITaskDataConstants.ATTRIBUTE_VALUE); clearCurrentElementText(); } } private class OperationHandler10 extends ElementHandler { private TaskAttribute attribute; private final TaskAttribute operationAttribute; private final TaskAttribute parentAttribute; private int id; public OperationHandler10(ElementHandler parent, TaskAttribute parentAttribute) { super(parent, ITaskDataConstants.ELEMENT_OPERATION); this.parentAttribute = parentAttribute; this.operationAttribute = createAttribute(parentAttribute, TaskAttribute.OPERATION); } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { attribute = createAttribute(parentAttribute, TaskAttribute.PREFIX_OPERATION + ++id); attribute.getMetaData().putValue(TaskAttribute.META_ATTRIBUTE_TYPE, TaskAttribute.TYPE_OPERATION); attribute.getMetaData().putValue(TaskAttribute.META_LABEL, getValue(attributes, ITaskDataConstants.ATTRIBUTE_OPERATION_NAME)); String operationId = getValue(attributes, ITaskDataConstants.ATTRIBUTE_KNOB_NAME); attribute.setValue(operationId); if (Boolean.parseBoolean(getValue(attributes, ITaskDataConstants.ATTRIBUTE_IS_CHECKED))) { operationAttribute.setValue(operationId); } String value = getOptionalValue(attributes, ITaskDataConstants.ATTRIBUTE_OPTION_NAME); TaskAttribute child; if (value.length() > 0) { attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, value); child = createAttribute(attribute, value); child.setValue(getOptionalValue(attributes, ITaskDataConstants.ATTRIBUTE_OPTION_SELECTION)); child.getMetaData().defaults().setReadOnly(false).setType(TaskAttribute.TYPE_SINGLE_SELECT); addElementHandler(new NameHandler(this, child)); } else { value = getOptionalValue(attributes, ITaskDataConstants.ATTRIBUTE_INPUT_NAME); if (value.length() > 0) { attribute.getMetaData().putValue(TaskAttribute.META_ASSOCIATED_ATTRIBUTE_ID, value); child = createAttribute(attribute, value); child.setValue(getOptionalValue(attributes, ITaskDataConstants.ATTRIBUTE_INPUT_VALUE)); child.getMetaData().defaults().setReadOnly(false).setType(TaskAttribute.TYPE_SHORT_TEXT); } } } } private class OptionHandler10 extends ElementHandler { private final TaskAttribute attribute; private String parameter; public OptionHandler10(ElementHandler parent, TaskAttribute attribute) { super(parent, ITaskDataConstants.ELEMENT_OPTION); this.attribute = attribute; } @Override public void end(String uri, String localName, String name) { attribute.putOption(parameter, getCurrentElementText()); } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { parameter = getValue(attributes, ITaskDataConstants.ATTRIBUTE_PARAMETER); clearCurrentElementText(); } } private class TaskDataHandler10 extends ElementHandler { private TaskData taskData; public TaskDataHandler10(TaskStateHandler parent, String elementName) { super(parent, elementName); } public TaskData getTaskData() { return taskData; } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { taskData = ((TaskStateHandler) getParent()).createTaskData(attributes); String taskKind = getOptionalValue(attributes, ITaskDataConstants.ATTRIBUTE_TASK_KIND); if (taskKind != null) { createAttribute(taskData.getRoot(), TaskAttribute.TASK_KIND).setValue(taskKind); } addElementHandler(new AttributeHandler10(this, taskData.getRoot())); addElementHandler(new CommentHandler10(this, taskData.getRoot())); addElementHandler(new AttachmentHandler10(this, taskData.getRoot())); addElementHandler(new OperationHandler10(this, taskData.getRoot())); // the selected operation was never serialized, no need to read it } } private class TaskDataHandler20 extends ElementHandler { private TaskData taskData; public TaskDataHandler20(TaskStateHandler parent, String elementName) { super(parent, elementName); } public TaskData getTaskData() { return taskData; } @Override public void start(String uri, String localName, String name, Attributes attributes) throws SAXException { taskData = ((TaskStateHandler) getParent()).createTaskData(attributes); // skip the root node ElementHandler handler = new ElementHandler(this, ITaskDataConstants.ELEMENT_ATTRIBUTE); handler.addElementHandler(new AttributeHandler20(handler, taskData.getRoot())); addElementHandler(handler); } } private class TaskStateHandler extends ElementHandler { private TaskAttributeMapper attributeMapper; private TaskDataState state; private final String version; public TaskStateHandler(String version) { super(null, ITaskDataConstants.ELEMENT_TASK_STATE); this.version = version; if ("1.0".equals(version)) { //$NON-NLS-1$ addElementHandler(new TaskDataHandler10(this, ITaskDataConstants.ELEMENT_NEW_DATA)); addElementHandler(new TaskDataHandler10(this, ITaskDataConstants.ELEMENT_OLD_DATA)); addElementHandler(new TaskDataHandler10(this, ITaskDataConstants.ELEMENT_EDITS_DATA)); } else if ("2.0".equals(version)) { //$NON-NLS-1$ addElementHandler(new TaskDataHandler20(this, ITaskDataConstants.ELEMENT_NEW_DATA)); addElementHandler(new TaskDataHandler20(this, ITaskDataConstants.ELEMENT_OLD_DATA)); addElementHandler(new TaskDataHandler20(this, ITaskDataConstants.ELEMENT_EDITS_DATA)); } } public TaskData createTaskData(Attributes attributes) throws SAXException { TaskData taskData; if (state == null) { String connectorKind = getValue(attributes, ITaskDataConstants.ATTRIBUTE_REPOSITORY_KIND); String repositoryUrl = getValue(attributes, ITaskDataConstants.ATTRIBUTE_REPOSITORY_URL); String taskId = getValue(attributes, ITaskDataConstants.ATTRIBUTE_ID); attributeMapper = getAttributeMapper(connectorKind, repositoryUrl); taskData = new TaskData(attributeMapper, connectorKind, repositoryUrl, taskId); } else { taskData = new TaskData(attributeMapper, state.getConnectorKind(), state.getRepositoryUrl(), state.getTaskId()); } String taskDataVersion = getOptionalValue(attributes, ITaskDataConstants.ATTRIBUTE_VERSION); if (taskDataVersion.length() > 0) { taskData.setVersion(taskDataVersion); } return taskData; } @Override public void done(ElementHandler elementHandler) { TaskData taskData; if (elementHandler instanceof TaskDataHandler10) { TaskDataHandler10 taskDataHandler = (TaskDataHandler10) elementHandler; TaskData data = taskDataHandler.getTaskData(); if (state == null) { state = new TaskDataState(data.getConnectorKind(), data.getRepositoryUrl(), data.getTaskId()); } taskData = taskDataHandler.getTaskData(); } else { TaskDataHandler20 taskDataHandler = (TaskDataHandler20) elementHandler; taskData = taskDataHandler.getTaskData(); } if (ITaskDataConstants.ELEMENT_NEW_DATA.equals(elementHandler.getElementName())) { state.setRepositoryData(taskData); } else if (ITaskDataConstants.ELEMENT_OLD_DATA.equals(elementHandler.getElementName())) { state.setLastReadData(taskData); } else if (ITaskDataConstants.ELEMENT_EDITS_DATA.equals(elementHandler.getElementName())) { state.setEditsData(taskData); } super.done(elementHandler); } public TaskDataState getState() { return state; } @Override protected void start(String uri, String localName, String name, Attributes attributes) throws SAXException { if ("2.0".equals(version)) { //$NON-NLS-1$ String connectorKind = getValue(attributes, ITaskDataConstants.ATTRIBUTE_CONNECTOR_KIND); String repositoryUrl = getValue(attributes, ITaskDataConstants.ATTRIBUTE_REPOSITORY_URL); String taskId = getValue(attributes, ITaskDataConstants.ATTRIBUTE_TASK_ID); attributeMapper = getAttributeMapper(connectorKind, repositoryUrl); state = new TaskDataState(connectorKind, repositoryUrl, taskId); } } } private class ValueHandler10 extends ElementHandler { private final TaskAttribute attribute; public ValueHandler10(ElementHandler parent, TaskAttribute attribute) { super(parent, ITaskDataConstants.ELEMENT_VALUE); this.attribute = attribute; } @Override public void end(String uri, String localName, String name) { attribute.addValue(getCurrentElementText()); } @Override protected void start(String uri, String localName, String name, Attributes attributes) throws SAXException { clearCurrentElementText(); } } private class ValueHandler20 extends ElementHandler { private final TaskAttribute attribute; public ValueHandler20(ElementHandler parent, TaskAttribute attribute) { super(parent, ITaskDataConstants.ELEMENT_VALUE); this.attribute = attribute; } @Override public void end(String uri, String localName, String name) { attribute.addValue(getCurrentElementText()); } @Override protected void start(String uri, String localName, String name, Attributes attributes) throws SAXException { clearCurrentElementText(); } } private class MapHandler20 extends ElementHandler { private final TaskAttribute attribute; private String key = ""; //$NON-NLS-1$ private String value = ""; //$NON-NLS-1$ public MapHandler20(ElementHandler parent, TaskAttribute attribute, String elementName) { super(parent, elementName); this.attribute = attribute; } @Override public void end(String uri, String localName, String name) { if (ITaskDataConstants.ELEMENT_OPTION.equals(getElementName())) { attribute.putOption(key, value); } else if (ITaskDataConstants.ELEMENT_META.equals(getElementName())) { attribute.getMetaData().putValue(key, value); } key = ""; //$NON-NLS-1$ value = ""; //$NON-NLS-1$ } @Override protected void start(String uri, String localName, String name, Attributes attributes) throws SAXException { addElementHandler(new TextHandler20(this, ITaskDataConstants.ELEMENT_KEY)); addElementHandler(new TextHandler20(this, ITaskDataConstants.ELEMENT_VALUE)); } @Override protected void done(ElementHandler handler) { if (ITaskDataConstants.ELEMENT_KEY.equals(handler.getElementName())) { key = handler.getCurrentElementText(); } else if (ITaskDataConstants.ELEMENT_VALUE.equals(handler.getElementName())) { value = handler.getCurrentElementText(); } super.done(handler); } } private class TextHandler20 extends ElementHandler { public TextHandler20(ElementHandler parent, String elementName) { super(parent, elementName); } @Override protected void start(String uri, String localName, String name, Attributes attributes) throws SAXException { clearCurrentElementText(); } } private TaskStateHandler handler; private final IRepositoryManager repositoryManager; private TaskDataState result; public TaskDataStateReader(IRepositoryManager repositoryManager) { this.repositoryManager = repositoryManager; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (handler != null) { handler.characters(ch, start, length); } } private TaskAttribute createAttribute(TaskAttribute parent, String id) { TaskAttribute attribute = parent.createAttribute(id); attribute.getMetaData().defaults(); return attribute; } @Override public void endElement(String uri, String localName, String name) throws SAXException { if (handler != null) { handler.endElement(uri, localName, name); if (ITaskDataConstants.ELEMENT_TASK_STATE.equals(name)) { result = handler.getState(); handler = null; } } } private TaskAttributeMapper getAttributeMapper(String connectorKind, String repositoryUrl) throws SAXException { AbstractRepositoryConnector connector = repositoryManager.getRepositoryConnector(connectorKind); if (connector == null) { throw new SAXException("No repository connector for kind \"" + connectorKind + "\" found"); //$NON-NLS-1$ //$NON-NLS-2$ } TaskRepository taskRepository = repositoryManager.getRepository(connectorKind, repositoryUrl); if (taskRepository == null) { throw new SAXException("Repository \"" + repositoryUrl + "\" not found for kind \"" + connectorKind + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } final TaskAttributeMapper attributeMapper; AbstractTaskDataHandler taskDataHandler = connector.getTaskDataHandler(); if (taskDataHandler != null) { attributeMapper = taskDataHandler.getAttributeMapper(taskRepository); } else { attributeMapper = new TaskAttributeMapper(taskRepository); } return attributeMapper; } public TaskDataState getTaskDataState() { return result; } @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { if (handler != null) { handler.startElement(uri, localName, name, attributes); } if (ITaskDataConstants.ELEMENT_TASK_STATE.equals(name)) { String version = attributes.getValue(ITaskDataConstants.ATTRIBUTE_VERSION); handler = new TaskStateHandler(version); handler.start(uri, localName, name, attributes); } } }