From 7f3f9dc21e4b3ff6afd680c835277f08da7c124d Mon Sep 17 00:00:00 2001 From: Jaxsun McCarthy Huggan Date: Mon, 16 May 2016 16:44:26 -0700 Subject: 493037: write task list using SAX instead of DOM Change-Id: Ie0e4c7ff38dbe78951849f0cc880cfa21b7a32eb Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=493037 Signed-off-by: Jaxsun McCarthy Huggan --- .../core/externalization/AttributesWrapper.java | 34 ++++ .../externalization/ContentHandlerWrapper.java | 42 +++++ .../core/externalization/SaxCategoryWriter.java | 43 +++++ .../core/externalization/SaxOrphanWriter.java | 55 ++++++ .../tasks/core/externalization/SaxQueryWriter.java | 58 ++++++ .../externalization/SaxTaskListElementWriter.java | 84 +++++++++ .../core/externalization/SaxTaskListWriter.java | 194 +++++++++++++++++++++ .../tasks/core/externalization/SaxTaskWriter.java | 127 ++++++++++++++ .../core/externalization/TaskListExternalizer.java | 115 +----------- 9 files changed, 642 insertions(+), 110 deletions(-) create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/AttributesWrapper.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/ContentHandlerWrapper.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxCategoryWriter.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxOrphanWriter.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxQueryWriter.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListElementWriter.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListWriter.java create mode 100644 org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskWriter.java diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/AttributesWrapper.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/AttributesWrapper.java new file mode 100644 index 000000000..082974ad0 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/AttributesWrapper.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import org.xml.sax.helpers.AttributesImpl; + +public class AttributesWrapper { + + private final AttributesImpl attributes; + + public AttributesWrapper() { + this.attributes = new AttributesImpl(); + } + + public void addAttribute(String key, String value) { + if (key != null && value != null) { + attributes.addAttribute("", key, key, "", value); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + public AttributesImpl getAttributes() { + return attributes; + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/ContentHandlerWrapper.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/ContentHandlerWrapper.java new file mode 100644 index 000000000..5b35c0b66 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/ContentHandlerWrapper.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +public class ContentHandlerWrapper { + + private final ContentHandler handler; + + public ContentHandlerWrapper(ContentHandler handler) { + this.handler = handler; + } + + public void startElement(String elementName, AttributesWrapper attributes) throws SAXException { + handler.startElement("", elementName, elementName, attributes.getAttributes()); //$NON-NLS-1$ + } + + public void endElement(String elementName) throws SAXException { + handler.endElement("", elementName, elementName);//$NON-NLS-1$ + } + + public void characters(String value) throws SAXException { + char[] chars = value.toCharArray(); + handler.characters(chars, 0, chars.length); + } + + public ContentHandler getHandler() { + return handler; + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxCategoryWriter.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxCategoryWriter.java new file mode 100644 index 000000000..322971b05 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxCategoryWriter.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import org.eclipse.mylyn.internal.tasks.core.AbstractTaskCategory; +import org.eclipse.mylyn.tasks.core.ITask; +import org.xml.sax.SAXException; + +public class SaxCategoryWriter extends SaxTaskListElementWriter { + + public SaxCategoryWriter(ContentHandlerWrapper handler) { + super(handler); + } + + @Override + public void writeElement(AbstractTaskCategory category) throws SAXException { + AttributesWrapper attributes = new AttributesWrapper(); + attributes.addAttribute(TaskListExternalizationConstants.KEY_HANDLE, category.getHandleIdentifier()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_NAME, category.getSummary()); + handler.startElement(TaskListExternalizationConstants.NODE_CATEGORY, attributes); + for (ITask task : category.getChildren()) { + createTaskReference(task); + } + handler.endElement(TaskListExternalizationConstants.NODE_CATEGORY); + } + + private void createTaskReference(ITask task) throws SAXException { + AttributesWrapper attributes = new AttributesWrapper(); + attributes.addAttribute(TaskListExternalizationConstants.KEY_HANDLE, task.getHandleIdentifier()); + handler.startElement(TaskListExternalizationConstants.NODE_TASK_REFERENCE, attributes); + handler.endElement(TaskListExternalizationConstants.NODE_TASK_REFERENCE); + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxOrphanWriter.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxOrphanWriter.java new file mode 100644 index 000000000..d3ba93d81 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxOrphanWriter.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.SAXException; + +public class SaxOrphanWriter { + + private final ContentHandlerWrapper handler; + + public SaxOrphanWriter(ContentHandlerWrapper handler) { + this.handler = handler; + } + + public void writeOrphans(NodeList orphanNodes) throws SAXException { + for (int i = 0; i < orphanNodes.getLength(); i++) { + Node orphanNode = orphanNodes.item(i); + if (orphanNode instanceof Element) { + Element orphanElement = (Element) orphanNode; + AttributesWrapper saxAttributes = getAttributes(orphanElement); + handler.startElement(orphanElement.getNodeName(), saxAttributes); + writeOrphans(orphanElement.getChildNodes()); + handler.endElement(orphanElement.getNodeName()); + } else if (orphanNode instanceof Text) { + Text orphanText = (Text) orphanNode; + handler.characters(orphanText.getData()); + } + } + } + + private AttributesWrapper getAttributes(Element orphanElement) { + AttributesWrapper saxAttributes = new AttributesWrapper(); + NamedNodeMap domAttributes = orphanElement.getAttributes(); + for (int i = 0; i < domAttributes.getLength(); i++) { + Node attribute = domAttributes.item(i); + saxAttributes.addAttribute(attribute.getNodeName(), attribute.getNodeValue()); + } + return saxAttributes; + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxQueryWriter.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxQueryWriter.java new file mode 100644 index 000000000..edbf068c2 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxQueryWriter.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; +import org.eclipse.mylyn.internal.tasks.core.RepositoryQuery; +import org.eclipse.mylyn.tasks.core.ITask; +import org.xml.sax.SAXException; + +public class SaxQueryWriter extends SaxTaskListElementWriter { + + public SaxQueryWriter(ContentHandlerWrapper handler) { + super(handler); + } + + @Override + public void writeElement(RepositoryQuery query) throws SAXException { + if (query.getClass() == RepositoryQuery.class) { + AttributesWrapper attributes = new AttributesWrapper(); + attributes.addAttribute(TaskListExternalizationConstants.KEY_HANDLE, query.getHandleIdentifier()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_CONNECTOR_KIND, query.getConnectorKind()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_NAME, query.getSummary()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_QUERY_STRING, query.getUrl()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_REPOSITORY_URL, query.getRepositoryUrl()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_LAST_REFRESH, + query.getLastSynchronizedTimeStamp()); + handler.startElement(TaskListExternalizationConstants.NODE_QUERY, attributes); + writeAttributes(query); + for (ITask task : query.getChildren()) { + writeQueryHit(task); + } + handler.endElement(TaskListExternalizationConstants.NODE_QUERY); + } else { + addError(new Status(IStatus.WARNING, ITasksCoreConstants.ID_PLUGIN, + String.format("Unable to externalize query \"%s\" as it is of an unsupported type %s", //$NON-NLS-1$ + query.getHandleIdentifier(), query.getClass()))); + } + } + + private void writeQueryHit(ITask task) throws SAXException { + AttributesWrapper attributes = new AttributesWrapper(); + attributes.addAttribute(TaskListExternalizationConstants.KEY_HANDLE, task.getHandleIdentifier()); + handler.startElement(TaskListExternalizationConstants.NODE_QUERY_HIT, attributes); + handler.endElement(TaskListExternalizationConstants.NODE_QUERY_HIT); + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListElementWriter.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListElementWriter.java new file mode 100644 index 000000000..9845358aa --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListElementWriter.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; +import org.eclipse.mylyn.tasks.core.IAttributeContainer; +import org.eclipse.mylyn.tasks.core.IRepositoryElement; +import org.xml.sax.SAXException; + +public abstract class SaxTaskListElementWriter { + + protected final ContentHandlerWrapper handler; + + private final MultiStatus errors; + + public SaxTaskListElementWriter(ContentHandlerWrapper handler) { + this.handler = handler; + this.errors = new MultiStatus(ITasksCoreConstants.ID_PLUGIN, IStatus.OK, null, null); + } + + public abstract void writeElement(T element) throws SAXException; + + protected void writeAttributes(IAttributeContainer container) throws SAXException { + Map attributes = container.getAttributes(); + for (Map.Entry entry : attributes.entrySet()) { + AttributesWrapper xmlAttributes = new AttributesWrapper(); + xmlAttributes.addAttribute(TaskListExternalizationConstants.KEY_KEY, entry.getKey()); + + handler.startElement(TaskListExternalizationConstants.NODE_ATTRIBUTE, xmlAttributes); + handler.characters(entry.getValue()); + handler.endElement(TaskListExternalizationConstants.NODE_ATTRIBUTE); + } + } + + @SuppressWarnings({ "restriction" }) + protected String stripControlCharacters(String text) { + if (text == null) { + return ""; //$NON-NLS-1$ + } + return org.eclipse.mylyn.internal.commons.core.XmlStringConverter.cleanXmlString(text); + } + + protected String formatExternDate(Date date) { + if (date == null) { + return ""; //$NON-NLS-1$ + } + SimpleDateFormat format = new SimpleDateFormat(TaskListExternalizationConstants.OUT_DATE_FORMAT, + Locale.ENGLISH); + return format.format(date); + } + + protected String formatExternCalendar(Calendar date) { + if (date == null) { + return ""; //$NON-NLS-1$ + } + return formatExternDate(date.getTime()); + } + + protected void addError(IStatus status) { + errors.add(status); + } + + public IStatus getErrors() { + return errors; + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListWriter.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListWriter.java new file mode 100644 index 000000000..439f6fe2d --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskListWriter.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.commons.core.StatusHandler; +import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; +import org.eclipse.mylyn.internal.tasks.core.ITransferList; +import org.eclipse.mylyn.internal.tasks.core.SaxRepositoriesWriter; +import org.eclipse.mylyn.tasks.core.IRepositoryElement; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +/** + * Adapted from {@link SaxRepositoriesWriter} + */ +public class SaxTaskListWriter { + + private static final String ATTRIBUTE_VERSION = "Version"; //$NON-NLS-1$ + + // Mylyn 3.0 + private static final String VALUE_VERSION = "2.0"; //$NON-NLS-1$ + + private OutputStream outputStream; + + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public void writeTaskListToStream(ITransferList taskList, Document orphans) throws IOException { + if (outputStream == null) { + throw new IOException("OutputStream not set"); //$NON-NLS-1$ + } + + try { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.transform(new SAXSource(new TaskListWriter(), new TaskListInputSource(taskList, orphans)), + new StreamResult(outputStream)); + } catch (TransformerException e) { + StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Could not write task list", e)); //$NON-NLS-1$ + throw new IOException(e.getMessage(), e); + } + + } + + private static class TaskListInputSource extends InputSource { + private final ITransferList taskList; + + private final Document orphans; + + public TaskListInputSource(ITransferList taskList, Document orphans) { + this.taskList = taskList; + this.orphans = orphans; + } + + public ITransferList getTaskList() { + return this.taskList; + } + + public Document getOrphans() { + return orphans; + } + + } + + private static class TaskListWriter implements XMLReader { + + private ContentHandlerWrapper handler; + + private ErrorHandler errorHandler; + + public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + return false; + } + + public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { + } + + public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + return null; + } + + public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { + } + + public void setEntityResolver(EntityResolver resolver) { + } + + public EntityResolver getEntityResolver() { + return null; + } + + public void setDTDHandler(DTDHandler handler) { + } + + public DTDHandler getDTDHandler() { + return null; + } + + public void setContentHandler(ContentHandler handler) { + this.handler = new ContentHandlerWrapper(handler); + } + + public ContentHandler getContentHandler() { + return handler.getHandler(); + } + + public void setErrorHandler(ErrorHandler handler) { + this.errorHandler = handler; + } + + public ErrorHandler getErrorHandler() { + return errorHandler; + } + + public void parse(InputSource input) throws IOException, SAXException { + if (!(input instanceof TaskListInputSource)) { + throw new SAXException("Can only parse writable input sources"); //$NON-NLS-1$ + } + TaskListInputSource taskListInputSource = (TaskListInputSource) input; + + handler.getHandler().startDocument(); + writeTaskList(taskListInputSource.getTaskList(), taskListInputSource.getOrphans()); + handler.getHandler().endDocument(); + } + + private void writeTaskList(ITransferList taskList, Document orphanDocument) throws IOException, SAXException { + AttributesWrapper attributes = new AttributesWrapper(); + attributes.addAttribute(ATTRIBUTE_VERSION, VALUE_VERSION); + handler.startElement(TaskListExternalizationConstants.NODE_TASK_LIST, attributes); + + writeTaskListElements(new SaxTaskWriter(handler), taskList.getAllTasks()); + writeTaskListElements(new SaxCategoryWriter(handler), taskList.getCategories()); + writeTaskListElements(new SaxQueryWriter(handler), taskList.getQueries()); + + writeOrphans(orphanDocument); + + handler.endElement(TaskListExternalizationConstants.NODE_TASK_LIST); + } + + private void writeTaskListElements(SaxTaskListElementWriter writer, + Collection elements) throws SAXException { + for (T element : elements) { + writer.writeElement(element); + } + if (!writer.getErrors().isOK()) { + StatusHandler.log(writer.getErrors()); + } + } + + private void writeOrphans(Document orphanDocument) throws SAXException { + if (orphanDocument != null) { + SaxOrphanWriter writer = new SaxOrphanWriter(handler); + NodeList orphanNodes = orphanDocument.getChildNodes(); + if (orphanNodes.getLength() == 1) { + writer.writeOrphans(orphanNodes.item(0).getChildNodes()); + } + } + } + + public void parse(String systemId) throws IOException, SAXException { + throw new SAXException("Can only parse writable input sources"); //$NON-NLS-1$ + } + } +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskWriter.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskWriter.java new file mode 100644 index 000000000..299891987 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/SaxTaskWriter.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2016 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.externalization; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.internal.tasks.core.AbstractTask; +import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; +import org.eclipse.mylyn.internal.tasks.core.LocalTask; +import org.eclipse.mylyn.internal.tasks.core.TaskTask; +import org.eclipse.mylyn.tasks.core.ITask; +import org.eclipse.mylyn.tasks.core.ITask.SynchronizationState; +import org.xml.sax.SAXException; + +public class SaxTaskWriter extends SaxTaskListElementWriter { + + public SaxTaskWriter(ContentHandlerWrapper handler) { + super(handler); + } + + @Override + public void writeElement(AbstractTask task) throws SAXException { + if (task.getClass() == TaskTask.class || task instanceof LocalTask) { + handler.startElement(TaskListExternalizationConstants.NODE_TASK, createTaskElementAttributes(task)); + writeAttributes(task); + for (ITask subTask : task.getChildren()) { + createTaskReference(subTask); + } + handler.endElement(TaskListExternalizationConstants.NODE_TASK); + } else { + addError(new Status(IStatus.WARNING, ITasksCoreConstants.ID_PLUGIN, + String.format("Unable to externalize task \"%s\" as it is of an unsupported type %s", //$NON-NLS-1$ + task.getTaskId(), task.getClass()))); + } + } + + private AttributesWrapper createTaskElementAttributes(AbstractTask task) { + AttributesWrapper attributes = new AttributesWrapper(); + + attributes.addAttribute(TaskListExternalizationConstants.KEY_CONNECTOR_KIND, task.getConnectorKind()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_REPOSITORY_URL, task.getRepositoryUrl()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_TASK_ID, task.getTaskId()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_KEY, task.getTaskKey()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_HANDLE, task.getHandleIdentifier()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_LABEL, stripControlCharacters(task.getSummary())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_PRIORITY, task.getPriority()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_KIND, task.getTaskKind()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_ISSUEURL, task.getUrl()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_NOTES, stripControlCharacters(task.getNotes())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_TIME_ESTIMATED, + Integer.toString(task.getEstimatedTimeHours())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_DATE_END, + formatExternDate(task.getCompletionDate())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_DATE_CREATION, + formatExternDate(task.getCreationDate())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_DATE_MODIFICATION, + formatExternDate(task.getModificationDate())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_DATE_DUE, formatExternDate(task.getDueDate())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_OWNER, task.getOwner()); + attributes.addAttribute(TaskListExternalizationConstants.KEY_OWNER_ID, task.getOwnerId()); + + if (task.isActive()) { + attributes.addAttribute(TaskListExternalizationConstants.KEY_ACTIVE, + TaskListExternalizationConstants.VAL_TRUE); + } else { + attributes.addAttribute(TaskListExternalizationConstants.KEY_ACTIVE, + TaskListExternalizationConstants.VAL_FALSE); + } + + if (task.getScheduledForDate() != null) { + attributes.addAttribute(TaskListExternalizationConstants.KEY_DATE_SCHEDULED_START, + formatExternCalendar(task.getScheduledForDate().getStartDate())); + attributes.addAttribute(TaskListExternalizationConstants.KEY_DATE_SCHEDULED_END, + formatExternCalendar(task.getScheduledForDate().getEndDate())); + } + + if (task.isReminded()) { + attributes.addAttribute(TaskListExternalizationConstants.KEY_REMINDED, + TaskListExternalizationConstants.VAL_TRUE); + } else { + attributes.addAttribute(TaskListExternalizationConstants.KEY_REMINDED, + TaskListExternalizationConstants.VAL_FALSE); + } + + if (task.isMarkReadPending()) { + attributes.addAttribute(TaskListExternalizationConstants.KEY_MARK_READ_PENDING, + TaskListExternalizationConstants.VAL_TRUE); + } else { + attributes.addAttribute(TaskListExternalizationConstants.KEY_MARK_READ_PENDING, + TaskListExternalizationConstants.VAL_FALSE); + } + + if (task.isNotified()) { + attributes.addAttribute(TaskListExternalizationConstants.KEY_NOTIFIED_INCOMING, + TaskListExternalizationConstants.VAL_TRUE); + } else { + attributes.addAttribute(TaskListExternalizationConstants.KEY_NOTIFIED_INCOMING, + TaskListExternalizationConstants.VAL_FALSE); + } + + if (task.getSynchronizationState() != null) { + attributes.addAttribute(TaskListExternalizationConstants.KEY_SYNC_STATE, + task.getSynchronizationState().name()); + } else { + attributes.addAttribute(TaskListExternalizationConstants.KEY_SYNC_STATE, + SynchronizationState.SYNCHRONIZED.name()); + } + + return attributes; + } + + public void createTaskReference(ITask task) throws SAXException { + AttributesWrapper attributes = new AttributesWrapper(); + attributes.addAttribute(TaskListExternalizationConstants.KEY_HANDLE, task.getHandleIdentifier()); + handler.startElement(TaskListExternalizationConstants.NODE_SUB_TASK, attributes); + handler.endElement(TaskListExternalizationConstants.NODE_SUB_TASK); + } +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/TaskListExternalizer.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/TaskListExternalizer.java index 3ef523cf7..536c432d8 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/TaskListExternalizer.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/externalization/TaskListExternalizer.java @@ -18,40 +18,21 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.mylyn.commons.core.StatusHandler; -import org.eclipse.mylyn.internal.tasks.core.AbstractTask; -import org.eclipse.mylyn.internal.tasks.core.AbstractTaskCategory; import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; import org.eclipse.mylyn.internal.tasks.core.ITransferList; import org.eclipse.mylyn.internal.tasks.core.RepositoryModel; -import org.eclipse.mylyn.internal.tasks.core.RepositoryQuery; import org.eclipse.mylyn.internal.tasks.core.XmlReaderUtil; import org.eclipse.mylyn.tasks.core.AbstractTaskListMigrator; import org.eclipse.mylyn.tasks.core.IRepositoryManager; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -64,19 +45,6 @@ public class TaskListExternalizer { private static final String ERROR_TASKLIST_READ = "Failed to load Task List"; //$NON-NLS-1$ - private static final String TRANSFORM_PROPERTY_VERSION = "version"; //$NON-NLS-1$ - - // May 2007: There was a bug when reading in 1.1 - // Result was an infinite loop within the parser - private static final String XML_VERSION = "1.0"; //$NON-NLS-1$ - - public static final String ATTRIBUTE_VERSION = "Version"; //$NON-NLS-1$ - - public static final String ELEMENT_TASK_LIST = "TaskList"; //$NON-NLS-1$ - - // Mylyn 3.0 - private static final String VALUE_VERSION = "2.0"; //$NON-NLS-1$ - private final DelegatingTaskExternalizer delegatingExternalizer; private final RepositoryModel repositoryModel; @@ -96,24 +64,19 @@ public class TaskListExternalizer { } public void writeTaskList(ITransferList taskList, File outFile) throws CoreException { - try { - FileOutputStream outStream = new FileOutputStream(outFile); - try { - Document doc = createTaskListDocument(taskList); - - ZipOutputStream zipOutStream = new ZipOutputStream(outStream); - + try (FileOutputStream outStream = new FileOutputStream(outFile)) { + try (ZipOutputStream zipOutStream = new ZipOutputStream(outStream)) { ZipEntry zipEntry = new ZipEntry(ITasksCoreConstants.OLD_TASK_LIST_FILE); zipOutStream.putNextEntry(zipEntry); zipOutStream.setMethod(ZipOutputStream.DEFLATED); - writeDocument(doc, zipOutStream); + SaxTaskListWriter writer = new SaxTaskListWriter(); + writer.setOutputStream(zipOutStream); + writer.writeTaskListToStream(taskList, orphanDocument); zipOutStream.flush(); zipOutStream.closeEntry(); zipOutStream.finish(); - } finally { - outStream.close(); } } catch (IOException e) { throw new CoreException(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Saving Task List failed", //$NON-NLS-1$ @@ -121,74 +84,6 @@ public class TaskListExternalizer { } } - private Document createTaskListDocument(ITransferList taskList) throws CoreException { - Document doc = createDocument(); - - delegatingExternalizer.clearErrorStatus(); - - Element root = doc.createElement(ELEMENT_TASK_LIST); - root.setAttribute(ATTRIBUTE_VERSION, VALUE_VERSION); - doc.appendChild(root); - - // create task nodes... - for (AbstractTask task : taskList.getAllTasks()) { - delegatingExternalizer.createTaskElement(task, doc, root); - } - - // create the category nodes... - for (AbstractTaskCategory category : taskList.getCategories()) { - delegatingExternalizer.createCategoryElement(category, doc, root); - } - - // create query nodes... - for (RepositoryQuery query : taskList.getQueries()) { - delegatingExternalizer.createQueryElement(query, doc, root); - } - - // Persist orphaned tasks... - if (orphanDocument != null) { - NodeList orphans = orphanDocument.getDocumentElement().getChildNodes(); - for (int i = 0; i < orphans.getLength(); i++) { - Node node = orphans.item(i); - Node tempNode = doc.importNode(node, true); - if (tempNode != null) { - root.appendChild(tempNode); - } - } - } - - if (delegatingExternalizer.getErrorStatus() != null) { - StatusHandler.log(delegatingExternalizer.getErrorStatus()); - } - - return doc; - } - - private void writeDocument(Document doc, OutputStream outputStream) throws CoreException { - Source source = new DOMSource(doc); - Result result = new StreamResult(outputStream); - try { - Transformer xformer = TransformerFactory.newInstance().newTransformer(); - xformer.setOutputProperty(TRANSFORM_PROPERTY_VERSION, XML_VERSION); - xformer.transform(source, result); - } catch (TransformerException e) { - throw new CoreException(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Failed write task list", //$NON-NLS-1$ - e)); - } - } - - private Document createDocument() throws CoreException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db; - try { - db = dbf.newDocumentBuilder(); - return db.newDocument(); - } catch (ParserConfigurationException e) { - throw new CoreException( - new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Failed to create document", e)); //$NON-NLS-1$ - } - } - public void readTaskList(ITransferList taskList, File inFile) throws CoreException { if (!inFile.exists()) { throw new CoreException(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, -- cgit v1.2.3