/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.uima.caseditor.core.model.dotcorpus; import java.awt.Color; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.uima.caseditor.CasEditorPlugin; import org.apache.uima.caseditor.editor.AnnotationStyle; import org.apache.uima.internal.util.XMLUtils; import org.apache.uima.util.XMLSerializer; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; /** * This class is responsible to read and write {@link DotCorpus} objects from or to a byte stream. */ public class DotCorpusSerializer { /** The Constant CONFIG_ELEMENT. */ private static final String CONFIG_ELEMENT = "config"; /** The Constant CORPUS_ELEMENT. */ private static final String CORPUS_ELEMENT = "corpus"; /** The Constant CORPUS_FOLDER_ATTRIBUTE. */ private static final String CORPUS_FOLDER_ATTRIBUTE = "folder"; /** The Constant STYLE_ELEMENT. */ private static final String STYLE_ELEMENT = "style"; /** The Constant STYLE_TYPE_ATTRIBUTE. */ private static final String STYLE_TYPE_ATTRIBUTE = "type"; /** The Constant STYLE_STYLE_ATTRIBUTE. */ private static final String STYLE_STYLE_ATTRIBUTE = "style"; /** The Constant STYLE_COLOR_ATTRIBUTE. */ private static final String STYLE_COLOR_ATTRIBUTE = "color"; /** The Constant STYLE_LAYER_ATTRIBUTE. */ private static final String STYLE_LAYER_ATTRIBUTE = "layer"; /** The Constant STYLE_CONFIG_ATTRIBUTE. */ private static final String STYLE_CONFIG_ATTRIBUTE = "config"; /** The Constant TYPESYSTEM_ELEMENT. */ private static final String TYPESYSTEM_ELEMENT = "typesystem"; /** The Constant TYPESYTEM_FILE_ATTRIBUTE. */ private static final String TYPESYTEM_FILE_ATTRIBUTE = "file"; /** The Constant CAS_PROCESSOR_ELEMENT. */ private static final String CAS_PROCESSOR_ELEMENT = "processor"; /** The Constant CAS_PROCESSOR_FOLDER_ATTRIBUTE. */ private static final String CAS_PROCESSOR_FOLDER_ATTRIBUTE = "folder"; /** The Constant EDITOR_ELEMENT. */ private static final String EDITOR_ELEMENT = "editor"; /** The Constant EDITOR_LINE_LENGTH_ATTRIBUTE. */ private static final String EDITOR_LINE_LENGTH_ATTRIBUTE = "line-length-hint"; /** The Constant SHOWN_ELEMENT. */ private static final String SHOWN_ELEMENT = "shown"; /** The Constant SHOWN_TYPE_ATTRIBUTE. */ private static final String SHOWN_TYPE_ATTRIBUTE = "type"; /** The Constant SHOWN_IS_VISISBLE_ATTRIBUTE. */ private static final String SHOWN_IS_VISISBLE_ATTRIBUTE = "visible"; /** * Creates a {@link DotCorpus} object from a given {@link InputStream}. * * @param dotCorpusStream the dot corpus stream * @return the {@link DotCorpus} instance. * @throws CoreException - */ public static DotCorpus parseDotCorpus(InputStream dotCorpusStream) throws CoreException { DocumentBuilderFactory documentBuilderFactory = XMLUtils.createDocumentBuilderFactory(); DocumentBuilder documentBuilder; try { documentBuilder = documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { String message = "This should never happen:" + (e.getMessage() != null ? e.getMessage() : ""); IStatus s = new Status(IStatus.ERROR, CasEditorPlugin.ID, IStatus.OK, message, e); throw new CoreException(s); } org.w3c.dom.Document dotCorpusDOM; try { dotCorpusDOM = documentBuilder.parse(dotCorpusStream); } catch (SAXException | IOException e) { String message = e.getMessage() != null ? e.getMessage() : ""; IStatus s = new Status(IStatus.ERROR, CasEditorPlugin.ID, IStatus.OK, message, e); throw new CoreException(s); } DotCorpus dotCorpus = new DotCorpus(); // get corpora root element Element configElement = dotCorpusDOM.getDocumentElement(); if (CONFIG_ELEMENT.equals(configElement.getNodeName())) { // TODO: // throw exception } NodeList corporaChildNodes = configElement.getChildNodes(); for (int i = 0; i < corporaChildNodes.getLength(); i++) { Node corporaChildNode = corporaChildNodes.item(i); if (!(corporaChildNode instanceof Element)) { continue; } Element corporaChildElement = (Element) corporaChildNode; // TODO: This code will emit NumberFormatExceptions if the values // are incorrect, they should be caught, logged and replaced with default // values if (TYPESYSTEM_ELEMENT.equals(corporaChildElement.getNodeName())) { dotCorpus.setTypeSystemFilename(corporaChildElement.getAttribute(TYPESYTEM_FILE_ATTRIBUTE)); } else if (CORPUS_ELEMENT.equals(corporaChildElement.getNodeName())) { String corpusFolderName = corporaChildElement.getAttribute(CORPUS_FOLDER_ATTRIBUTE); dotCorpus.addCorpusFolder(corpusFolderName); } else if (STYLE_ELEMENT.equals(corporaChildElement.getNodeName())) { String type = corporaChildElement.getAttribute(STYLE_TYPE_ATTRIBUTE); String styleString = corporaChildElement.getAttribute(STYLE_STYLE_ATTRIBUTE); int colorInteger = Integer .parseInt(corporaChildElement.getAttribute(STYLE_COLOR_ATTRIBUTE)); Color color = new Color(colorInteger); String drawingLayerString = corporaChildElement.getAttribute(STYLE_LAYER_ATTRIBUTE); String drawingConfigString = corporaChildElement.getAttribute(STYLE_CONFIG_ATTRIBUTE); if (drawingConfigString.length() == 0) drawingConfigString = null; int drawingLayer; try { drawingLayer = Integer.parseInt(drawingLayerString); } catch (NumberFormatException e) { drawingLayer = 0; } AnnotationStyle style = new AnnotationStyle(type, AnnotationStyle.Style .valueOf(styleString), color, drawingLayer, drawingConfigString); dotCorpus.setStyle(style); } else if (CAS_PROCESSOR_ELEMENT.equals(corporaChildElement.getNodeName())) { dotCorpus.addCasProcessorFolder(corporaChildElement .getAttribute(CAS_PROCESSOR_FOLDER_ATTRIBUTE)); } else if (EDITOR_ELEMENT.equals(corporaChildElement.getNodeName())) { String lineLengthHintString = corporaChildElement .getAttribute(EDITOR_LINE_LENGTH_ATTRIBUTE); int lineLengthHint = Integer.parseInt(lineLengthHintString); dotCorpus.setEditorLineLength(lineLengthHint); } else if (SHOWN_ELEMENT.equals(corporaChildElement.getNodeName())) { String type = corporaChildElement.getAttribute(SHOWN_TYPE_ATTRIBUTE); String isVisisbleString = corporaChildElement.getAttribute(SHOWN_IS_VISISBLE_ATTRIBUTE); boolean isVisible = Boolean.parseBoolean(isVisisbleString); if (isVisible) { dotCorpus.setShownType(type); } } else { String message = "Unexpected element: " + corporaChildElement.getNodeName(); IStatus s = new Status(IStatus.ERROR, CasEditorPlugin.ID, IStatus.OK, message, null); throw new CoreException(s); } } return dotCorpus; } /** * Writes the <code>DotCorpus</code> instance to the given <code>OutputStream</code>. * * @param dotCorpus * the {@link DotCorpus} object to serialize. * @param out * - the stream to write the current <code>DotCorpus</code> instance. * @throws CoreException - */ public static void serialize(DotCorpus dotCorpus, OutputStream out) throws CoreException { XMLSerializer xmlSerializer = new XMLSerializer(out, true); ContentHandler xmlSerHandler = xmlSerializer.getContentHandler(); try { xmlSerHandler.startDocument(); xmlSerHandler.startElement("", CONFIG_ELEMENT, CONFIG_ELEMENT, new AttributesImpl()); for (String corpusFolder : dotCorpus.getCorpusFolderNameList()) { AttributesImpl corpusFolderAttributes = new AttributesImpl(); corpusFolderAttributes.addAttribute("", "", CORPUS_FOLDER_ATTRIBUTE, "", corpusFolder); xmlSerHandler.startElement("", CORPUS_ELEMENT, CORPUS_ELEMENT, corpusFolderAttributes); xmlSerHandler.endElement("", CORPUS_ELEMENT, CORPUS_ELEMENT); } for (AnnotationStyle style : dotCorpus.getAnnotationStyles()) { AttributesImpl styleAttributes = new AttributesImpl(); styleAttributes.addAttribute("", "", STYLE_TYPE_ATTRIBUTE, "", style.getAnnotation()); styleAttributes.addAttribute("", "", STYLE_STYLE_ATTRIBUTE, "", style.getStyle().name()); Color color = style.getColor(); int colorInt = new Color(color.getRed(), color.getGreen(), color.getBlue()).getRGB(); styleAttributes.addAttribute("", "", STYLE_COLOR_ATTRIBUTE, "", Integer.toString(colorInt)); styleAttributes.addAttribute("", "", STYLE_LAYER_ATTRIBUTE, "", Integer.toString(style .getLayer())); if (style.getConfiguration() != null) { styleAttributes.addAttribute("", "", STYLE_CONFIG_ATTRIBUTE, "", style .getConfiguration()); } xmlSerHandler.startElement("", STYLE_ELEMENT, STYLE_ELEMENT, styleAttributes); xmlSerHandler.endElement("", STYLE_ELEMENT, STYLE_ELEMENT); } for (String type : dotCorpus.getShownTypes()) { AttributesImpl shownAttributes = new AttributesImpl(); shownAttributes.addAttribute("", "", SHOWN_TYPE_ATTRIBUTE, "", type); shownAttributes.addAttribute("", "", SHOWN_IS_VISISBLE_ATTRIBUTE, "", "true"); xmlSerHandler.startElement("", SHOWN_ELEMENT, SHOWN_ELEMENT, shownAttributes); xmlSerHandler.endElement("", SHOWN_ELEMENT, SHOWN_ELEMENT); } if (dotCorpus.getTypeSystemFileName() != null) { AttributesImpl typeSystemFileAttributes = new AttributesImpl(); typeSystemFileAttributes.addAttribute("", "", TYPESYTEM_FILE_ATTRIBUTE, "", dotCorpus .getTypeSystemFileName()); xmlSerHandler.startElement("", TYPESYSTEM_ELEMENT, TYPESYSTEM_ELEMENT, typeSystemFileAttributes); xmlSerHandler.endElement("", TYPESYSTEM_ELEMENT, TYPESYSTEM_ELEMENT); } for (String folder : dotCorpus.getCasProcessorFolderNames()) { AttributesImpl taggerConfigAttributes = new AttributesImpl(); taggerConfigAttributes.addAttribute("", "", CAS_PROCESSOR_FOLDER_ATTRIBUTE, "", folder); xmlSerHandler.startElement("", CAS_PROCESSOR_ELEMENT, CAS_PROCESSOR_ELEMENT, taggerConfigAttributes); xmlSerHandler.endElement("", CAS_PROCESSOR_ELEMENT, CAS_PROCESSOR_ELEMENT); } if (dotCorpus.getEditorLineLengthHint() != DotCorpus.EDITOR_LINE_LENGTH_HINT_DEFAULT) { AttributesImpl editorLineLengthHintAttributes = new AttributesImpl(); editorLineLengthHintAttributes.addAttribute("", "", EDITOR_LINE_LENGTH_ATTRIBUTE, "", Integer.toString(dotCorpus.getEditorLineLengthHint())); xmlSerHandler.startElement("", EDITOR_ELEMENT, EDITOR_ELEMENT, editorLineLengthHintAttributes); xmlSerHandler.endElement("", EDITOR_ELEMENT, EDITOR_ELEMENT); } xmlSerHandler.endElement("", CONFIG_ELEMENT, CONFIG_ELEMENT); xmlSerHandler.endDocument(); } catch (SAXException e) { String message = e.getMessage() != null ? e.getMessage() : ""; IStatus s = new Status(IStatus.ERROR, CasEditorPlugin.ID, IStatus.OK, message, e); throw new CoreException(s); } } }