blob: c76aa89f864dc61ba488a3692fabea74c6cc1db4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 Tasktop Technologies and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* 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);
}
}
}