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