package org.simantics.xml.sax.base; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.layer0.Layer0; import org.simantics.message.ILogger; import org.simantics.xml.sax.ontology.XMLResource; public class XMLWriter { private ReadGraph graph; private Map subWriters = new HashMap(); private Map, XMLElementWriter> namedWriters = new HashMap, XMLElementWriter>(); private Map writers = new HashMap<>(); private String schemaURI; private String ontologyURI; private Resource ontology; private ILogger logger; public ReadGraph getGraph() { return graph; } public void setGraph(ReadGraph graph) throws DatabaseException { this.graph = graph; for (XMLWriter p : subWriters.values()) p.setGraph(graph); if (ontologyURI != null) this.ontology = graph.getResource(ontologyURI); } public String getSchemaURI() { return schemaURI; } public void setSchemaURI(String schemaURI) { this.schemaURI = schemaURI; } public String getOntologyURI() { return ontologyURI; } public void setOntologyURI(String ontologyURI) { this.ontologyURI = ontologyURI; } public Resource getOntology() { return ontology; } public void add(XMLElementWriter writer) throws DatabaseException { Resource type = writer.getType(graph); if (type != null) writers.put(type, writer); namedWriters.put(writer.getClass(), writer); } public void add(XMLWriter writer) { subWriters.put(writer.getOntology(), writer); } public void write(Resource root, XMLStreamWriter writer) throws DatabaseException, XMLStreamException { WriterElement element = new WriterElement(root); loadElement(element); write(element, writer); } protected void write(WriterElement instance, XMLStreamWriter writer) throws DatabaseException, XMLStreamException { XMLResource XML = XMLResource.getInstance(graph); XMLElementWriter elementWriter = instance.writer; elementWriter.start(graph, instance, writer); if (instance.parent == null) { if(getSchemaURI() != null) { writer.writeDefaultNamespace(getSchemaURI()); } } elementWriter.attributes(graph, instance, graph.getStatements(instance.instance, XML.hasAttribute), writer); if (graph.hasValue(instance.instance)) elementWriter.characters(graph, instance, writer); // get all child elements Set childElements = new HashSet<>(); childElements.addAll(graph.getStatements(instance.instance, XML.hasElement)); childElements.addAll(graph.getStatements(instance.instance, XML.hasComplexType)); // load elements, assign writers Map elementMap = new HashMap<>(); for (Statement s : childElements) { WriterElement c = new WriterElement(instance,s); loadElement(c); elementMap.put(s.getObject(), c); } LinkedHashSet sorted = new LinkedHashSet<>(); if (graph.hasStatement(instance.instance, XML.hasOriginalElementList)) { Resource originalList = graph.getSingleObject(instance.instance, XML.hasOriginalElementList); List l = ListUtils.toList(graph, originalList); sorted.addAll(l); } elementWriter.children(graph, instance, sorted); Set processed = new HashSet<>(); for (Resource r : sorted) { if (processed.contains(r)) // badly generated writer could report elements several times. continue; WriterElement child = elementMap.get(r); if (child == null) throw new DatabaseException("Trying to export unregonized resource " +NameUtils.getSafeName(graph, r) + " " + r); write(child, writer); processed.add(r); } //write the rest of the elements (in random order) for (Statement stm : childElements) { if (processed.contains(stm.getObject())) continue; WriterElement child = elementMap.get(stm.getObject()); if (child == null) throw new DatabaseException("Trying to export unregonized resource " +NameUtils.getSafeName(graph, stm.getObject()) + " " + stm.getObject()); write(child, writer); } elementWriter.end(graph, instance, writer); } private void loadElement(WriterElement child) throws DatabaseException { XMLElementWriter childWriter = null; if (child.parent != null && child.parent.writer instanceof XMLElementNamedChildWriter) { XMLElementNamedChildWriter namedParentWriter = (XMLElementNamedChildWriter)child.parent.writer; Class childWriterClass = namedParentWriter.getWriter(graph, writers, child); if (childWriterClass != null) { childWriter = this.writers.get(childWriterClass); if (childWriter == null) { try { Constructor c = null; try { c = childWriterClass.getConstructor(ReadGraph.class); childWriter = c.newInstance(graph); } catch (NoSuchMethodException e) { c = childWriterClass.getConstructor(); childWriter = c.newInstance(); } //childWriter = childWriterClass.newInstance(); namedWriters.put(childWriterClass, childWriter); } catch (IllegalAccessException|InstantiationException|NoSuchMethodException|SecurityException|InvocationTargetException e) { String err = "Error processing " + childWriterClass.getName() + " : element writers must have accessible constructor with ReadGraph parameter"; logger.log(new Status(IStatus.ERROR, XMLParser.PLUGIN_ID, err, e)); } } } } else { Resource type = graph.getSingleType(child.instance); childWriter = writers.get(type); } if (childWriter == null) { Resource type = graph.getSingleType(child.instance); Resource ontology = getOntology(type); if (ontology != null) { XMLWriter xmlWriter = subWriters.get(ontology); if (xmlWriter != null) { childWriter = xmlWriter.writers.get(type); } } if (childWriter == null) throw new DatabaseException("Cannot locate writer for " + NameUtils.getSafeName(graph, child.instance) + ", " + child.instance); } child.writer = childWriter; } private Resource getOntology(Resource type) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Resource r = type; while (true) { r = graph.getPossibleObject(r, L0.PartOf); if (r != null && graph.isInstanceOf(r, L0.Ontology)) break; } return r; } }