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