/*
* Copyright (C) 2012 Jason Gedge <http://www.gedge.ca>
*
* This file is part of the OpGraph project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ca.gedge.opgraph.nodes.xml;
import java.io.IOException;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import ca.gedge.opgraph.InputField;
import ca.gedge.opgraph.OpGraph;
import ca.gedge.opgraph.OpNode;
import ca.gedge.opgraph.OutputField;
import ca.gedge.opgraph.extensions.Extendable;
import ca.gedge.opgraph.extensions.Publishable.PublishedInput;
import ca.gedge.opgraph.extensions.Publishable.PublishedOutput;
import ca.gedge.opgraph.io.xml.XMLSerializer;
import ca.gedge.opgraph.io.xml.XMLSerializerFactory;
import ca.gedge.opgraph.nodes.general.MacroNode;
/**
* A default serializer for reading/writing published {@link InputField}s and
* {@link OutputField}s to/from XML.
*/
public class PublishedFieldXMLSerializer implements XMLSerializer {
static final String NAMESPACE = "http://gedge.ca/ns/opgraph-common-nodes";
static final String PREFIX = "ogcn";
// qualified names
static final QName INPUT_QNAME = new QName(NAMESPACE, "published_input", PREFIX);
static final QName OUTPUT_QNAME = new QName(NAMESPACE, "published_output", PREFIX);
@Override
public void write(XMLSerializerFactory serializerFactory, Document doc, Element parentElem, Object obj)
throws IOException
{
if(obj == null)
throw new IOException("Null object given to serializer");
// setup namespace for document
final Element rootEle = doc.getDocumentElement();
rootEle.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
XMLConstants.XMLNS_ATTRIBUTE + ":" + PREFIX, NAMESPACE);
if(obj instanceof PublishedInput) {
final PublishedInput field = (PublishedInput)obj;
// Only write if field is non-fixed, or fixed but with extensions
final Element fieldElem = doc.createElementNS(NAMESPACE, PREFIX + ":" + INPUT_QNAME.getLocalPart());
fieldElem.setAttribute("name", field.getKey());
fieldElem.setAttribute("ref", field.destinationNode.getId());
fieldElem.setAttribute("field", field.nodeInputField.getKey());
// Extensions
if(field.getExtensionClasses().size() > 0) {
final XMLSerializer serializer = serializerFactory.getHandler(Extendable.class);
if(serializer == null)
throw new IOException("No XML serializer for extensions");
serializer.write(serializerFactory, doc, fieldElem, field);
}
parentElem.appendChild(fieldElem);
} else if(obj instanceof PublishedOutput) {
final PublishedOutput field = (PublishedOutput)obj;
// Only write if field is non-fixed, or fixed but with extensions
final Element fieldElem = doc.createElementNS(NAMESPACE, PREFIX + ":" + INPUT_QNAME.getLocalPart());
fieldElem.setAttribute("name", field.getKey());
fieldElem.setAttribute("ref", field.sourceNode.getId());
fieldElem.setAttribute("field", field.nodeOutputField.getKey());
// Extensions
if(field.getExtensionClasses().size() > 0) {
final XMLSerializer serializer = serializerFactory.getHandler(Extendable.class);
if(serializer == null)
throw new IOException("No XML serializer for extensions");
serializer.write(serializerFactory, doc, fieldElem, field);
}
parentElem.appendChild(fieldElem);
} else {
throw new IOException(PublishedFieldXMLSerializer.class.getName() + " cannot write objects of type " + obj.getClass().getName());
}
}
@Override
public Object read(XMLSerializerFactory serializerFactory, OpGraph graph, Object parent, Document doc, Element elem)
throws IOException
{
if(INPUT_QNAME.equals(XMLSerializerFactory.getQName(elem))) {
if(!(parent instanceof MacroNode))
throw new IOException("Trying to read published field, but parent object is not a macro");
// Find published info
final String key = elem.getAttribute("name");
final String destNodeId = elem.getAttribute("ref");
final String destFieldKey = elem.getAttribute("field");
final MacroNode macro = (MacroNode)parent;
final OpNode destNode = macro.getGraph().getNodeById(destNodeId, true);
final InputField destField = destNode.getInputFieldWithKey(destFieldKey);
// Create
final InputField published = macro.publish(key, destNode, destField);
// Read children
final NodeList children = elem.getChildNodes();
for(int childIndex = 0; childIndex < children.getLength(); ++childIndex) {
final Node node = children.item(childIndex);
if(node instanceof Element) {
final Element childElem = (Element)node;
final QName name = XMLSerializerFactory.getQName(childElem);
// Get a handler for the element
final XMLSerializer serializer = serializerFactory.getHandler(name);
if(serializer == null)
throw new IOException("Could not get handler for element: " + name);
serializer.read(serializerFactory, graph, published, doc, childElem);
}
}
} else if(OUTPUT_QNAME.equals(XMLSerializerFactory.getQName(elem))) {
if(!(parent instanceof MacroNode))
throw new IOException("Trying to read published field, but parent object is not a macro");
// Find published info
final String key = elem.getAttribute("name");
final String sourceNodeId = elem.getAttribute("ref");
final String sourceFieldKey = elem.getAttribute("field");
final MacroNode macro = (MacroNode)parent;
final OpNode sourceNode = macro.getGraph().getNodeById(sourceNodeId, true);
final OutputField sourceField = sourceNode.getOutputFieldWithKey(sourceFieldKey);
// Create
final OutputField published = macro.publish(key, sourceNode, sourceField);
// Read children
final NodeList children = elem.getChildNodes();
for(int childIndex = 0; childIndex < children.getLength(); ++childIndex) {
final Node node = children.item(childIndex);
if(node instanceof Element) {
final Element childElem = (Element)node;
final QName name = XMLSerializerFactory.getQName(childElem);
// Get a handler for the element
final XMLSerializer serializer = serializerFactory.getHandler(name);
if(serializer == null)
throw new IOException("Could not get handler for element: " + name);
serializer.read(serializerFactory, graph, published, doc, childElem);
}
}
}
return null;
}
@Override
public boolean handles(Class<?> cls) {
return ((cls == PublishedInput.class) || (cls == PublishedOutput.class));
}
@Override
public boolean handles(QName name) {
return (INPUT_QNAME.equals(name) || OUTPUT_QNAME.equals(name));
}
}