Thu, 10 Nov 2016 18:44:48 +0100
removes span around line number
universe@25 | 1 | /* |
universe@25 | 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
universe@25 | 3 | * |
universe@25 | 4 | * Copyright 2014 Mike Becker. All rights reserved. |
universe@25 | 5 | * |
universe@25 | 6 | * Redistribution and use in source and binary forms, with or without |
universe@25 | 7 | * modification, are permitted provided that the following conditions are met: |
universe@25 | 8 | * |
universe@25 | 9 | * 1. Redistributions of source code must retain the above copyright |
universe@25 | 10 | * notice, this list of conditions and the following disclaimer. |
universe@25 | 11 | * |
universe@25 | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
universe@25 | 13 | * notice, this list of conditions and the following disclaimer in the |
universe@25 | 14 | * documentation and/or other materials provided with the distribution. |
universe@25 | 15 | * |
universe@25 | 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
universe@25 | 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
universe@25 | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
universe@25 | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
universe@25 | 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
universe@25 | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
universe@25 | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
universe@25 | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
universe@25 | 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
universe@25 | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
universe@25 | 26 | * POSSIBILITY OF SUCH DAMAGE. |
universe@25 | 27 | * |
universe@25 | 28 | */ |
universe@25 | 29 | |
universe@25 | 30 | package de.uapcore.sigred.doc.base; |
universe@25 | 31 | |
universe@25 | 32 | import de.uapcore.sigred.doc.Resources; |
universe@25 | 33 | import de.uapcore.sigrapi.impl.Digraph; |
universe@25 | 34 | import de.uapcore.sigrapi.impl.Graph; |
universe@25 | 35 | import de.uapcore.sigrapi.IGraph; |
universe@25 | 36 | import java.io.IOException; |
universe@25 | 37 | import java.io.InputStream; |
universe@25 | 38 | import java.io.OutputStream; |
universe@25 | 39 | import java.util.concurrent.atomic.AtomicBoolean; |
universe@25 | 40 | import java.util.concurrent.atomic.AtomicReference; |
universe@25 | 41 | import org.apache.xerces.impl.Constants; |
universe@25 | 42 | import org.dom4j.Document; |
universe@25 | 43 | import org.dom4j.DocumentException; |
universe@25 | 44 | import org.dom4j.DocumentHelper; |
universe@25 | 45 | import org.dom4j.Element; |
universe@25 | 46 | import org.dom4j.Namespace; |
universe@25 | 47 | import org.dom4j.QName; |
universe@25 | 48 | import org.dom4j.io.OutputFormat; |
universe@25 | 49 | import org.dom4j.io.SAXReader; |
universe@25 | 50 | import org.dom4j.io.XMLWriter; |
universe@25 | 51 | import org.xml.sax.ErrorHandler; |
universe@25 | 52 | import org.xml.sax.SAXException; |
universe@25 | 53 | import org.xml.sax.SAXParseException; |
universe@25 | 54 | |
universe@25 | 55 | public abstract class AbstractGraphDocument<T extends IGraph> |
universe@25 | 56 | extends FileBackedDocument { |
universe@25 | 57 | |
universe@25 | 58 | protected static final Namespace NAMESPACE = Namespace.get("sigred", |
universe@25 | 59 | "http://develop.uap-core.de/sigred/"); |
universe@25 | 60 | |
universe@25 | 61 | private static final |
universe@25 | 62 | QName TAG_GRAPHDOC = QName.get("graph-document", NAMESPACE); |
universe@25 | 63 | private static final |
universe@25 | 64 | QName TAG_GRAPH = QName.get("graph", NAMESPACE); |
universe@25 | 65 | private static final |
universe@25 | 66 | QName TAG_DIGRAPH = QName.get("digraph", NAMESPACE); |
universe@25 | 67 | private static final |
universe@25 | 68 | QName TAG_METADATA = QName.get("metadata", NAMESPACE); |
universe@25 | 69 | |
universe@25 | 70 | protected final T graph; |
universe@25 | 71 | |
universe@25 | 72 | private final GraphDocumentMetadata metadata; |
universe@25 | 73 | |
universe@25 | 74 | public AbstractGraphDocument(Class<T> graphType) { |
universe@25 | 75 | T g; |
universe@25 | 76 | try { |
universe@25 | 77 | g = graphType.newInstance(); |
universe@25 | 78 | } catch (ReflectiveOperationException e) { |
universe@25 | 79 | assert false; |
universe@25 | 80 | g = null; // for the compiler |
universe@25 | 81 | } |
universe@25 | 82 | graph = g; |
universe@25 | 83 | metadata = new GraphDocumentMetadata(); |
universe@25 | 84 | } |
universe@25 | 85 | |
universe@25 | 86 | public T getGraph() { |
universe@25 | 87 | return graph; |
universe@25 | 88 | } |
universe@25 | 89 | |
universe@25 | 90 | public GraphDocumentMetadata getMetadata() { |
universe@25 | 91 | return metadata; |
universe@25 | 92 | } |
universe@25 | 93 | |
universe@25 | 94 | protected abstract void writeGraph(Element rootNode) throws IOException; |
universe@25 | 95 | protected abstract void readGraph(Element rootNode) throws IOException; |
universe@25 | 96 | |
universe@25 | 97 | @Override |
universe@25 | 98 | public void writeTo(OutputStream out) throws IOException { |
universe@25 | 99 | Document doc = DocumentHelper.createDocument(); |
universe@25 | 100 | |
universe@25 | 101 | Element rootNode = doc.addElement(TAG_GRAPHDOC); |
universe@25 | 102 | |
universe@25 | 103 | Element metadataNode = rootNode.addElement(TAG_METADATA); |
universe@25 | 104 | |
universe@25 | 105 | metadata.write(metadataNode); |
universe@25 | 106 | |
universe@25 | 107 | if (graph instanceof Graph) { |
universe@25 | 108 | writeGraph(rootNode.addElement(TAG_GRAPH)); |
universe@25 | 109 | } else if (graph instanceof Digraph) { |
universe@25 | 110 | writeGraph(rootNode.addElement(TAG_DIGRAPH)); |
universe@25 | 111 | } else { |
universe@25 | 112 | throw new IOException("unsupported graph type"); |
universe@25 | 113 | } |
universe@25 | 114 | |
universe@25 | 115 | XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint()); |
universe@25 | 116 | writer.write(doc); |
universe@25 | 117 | writer.flush(); |
universe@25 | 118 | } |
universe@25 | 119 | |
universe@25 | 120 | @Override |
universe@25 | 121 | public void readFrom(InputStream in) throws IOException { |
universe@25 | 122 | try { |
universe@25 | 123 | SAXReader reader = new SAXReader(true); |
universe@25 | 124 | reader.setStripWhitespaceText(true); |
universe@25 | 125 | |
universe@25 | 126 | reader.setFeature(Constants.XERCES_FEATURE_PREFIX+ |
universe@25 | 127 | Constants.SCHEMA_VALIDATION_FEATURE, true); |
universe@25 | 128 | reader.setProperty(Constants.XERCES_PROPERTY_PREFIX + |
universe@25 | 129 | Constants.SCHEMA_LOCATION, String.format("%s %s", |
universe@25 | 130 | NAMESPACE.getURI(), Resources.class.getResource( |
universe@25 | 131 | "graph-document.xsd").toExternalForm())); |
universe@25 | 132 | |
universe@25 | 133 | final AtomicBoolean passed = new AtomicBoolean(true); |
universe@25 | 134 | final AtomicReference<SAXParseException> xmlerror = new AtomicReference<>(); |
universe@25 | 135 | // TODO: we should do more detailed error handling here |
universe@25 | 136 | reader.setErrorHandler(new ErrorHandler() { |
universe@25 | 137 | @Override |
universe@25 | 138 | public void warning(SAXParseException exception) throws SAXException { |
universe@25 | 139 | } |
universe@25 | 140 | |
universe@25 | 141 | @Override |
universe@25 | 142 | public void error(SAXParseException exception) throws SAXException { |
universe@25 | 143 | xmlerror.set(exception); |
universe@25 | 144 | passed.set(false); |
universe@25 | 145 | } |
universe@25 | 146 | |
universe@25 | 147 | @Override |
universe@25 | 148 | public void fatalError(SAXParseException exception) throws SAXException { |
universe@25 | 149 | xmlerror.set(exception); |
universe@25 | 150 | passed.set(false); |
universe@25 | 151 | } |
universe@25 | 152 | |
universe@25 | 153 | }); |
universe@25 | 154 | Document doc = reader.read(in); |
universe@25 | 155 | if (!passed.get()) { |
universe@25 | 156 | // TODO: provide details (maybe via separate error object?) |
universe@25 | 157 | throw xmlerror.get(); |
universe@25 | 158 | } |
universe@25 | 159 | |
universe@25 | 160 | doc.normalize(); |
universe@25 | 161 | |
universe@25 | 162 | Element root = doc.getRootElement(); |
universe@25 | 163 | metadata.read(root.element(TAG_METADATA)); |
universe@25 | 164 | |
universe@25 | 165 | if (graph instanceof Graph) { |
universe@25 | 166 | readGraph(root.element(TAG_GRAPH)); |
universe@25 | 167 | } else if (graph instanceof Digraph) { |
universe@25 | 168 | readGraph(root.element(TAG_DIGRAPH)); |
universe@25 | 169 | } else { |
universe@25 | 170 | throw new IOException("unsupported graph type"); |
universe@25 | 171 | } |
universe@25 | 172 | } catch (DocumentException | SAXException ex) { |
universe@25 | 173 | throw new IOException(ex); |
universe@25 | 174 | } |
universe@25 | 175 | } |
universe@25 | 176 | } |