/* * 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.io.xml; import static ca.gedge.opgraph.io.xml.XMLSerializerFactory.*; import java.io.IOException; import java.util.logging.Logger; 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.OpGraph; import ca.gedge.opgraph.extensions.Extendable; /** * A default serializer for reading/writing {@link Extendable}s to/from XML. */ public class DefaultExtendableXMLSerializer implements XMLSerializer { /** Logger */ private static final Logger LOGGER = Logger.getLogger(DefaultExtendableXMLSerializer.class.getName()); // qualified names static final QName EXTENDABLE_QNAME = new QName(DEFAULT_NAMESPACE, "extensions", XMLConstants.DEFAULT_NS_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"); if(!(obj instanceof Extendable)) throw new IOException(DefaultExtendableXMLSerializer.class.getName() + " cannot write objects of type " + obj.getClass().getName()); // Create extensions element final Extendable ext = (Extendable)obj; final Element extensionsElem = doc.createElementNS(EXTENDABLE_QNAME.getNamespaceURI(), EXTENDABLE_QNAME.getLocalPart()); for(Class<?> extension : ext.getExtensionClasses()) { final XMLSerializer serializer = serializerFactory.getHandler(extension); if(serializer == null) { LOGGER.warning("Extendable contains a serializable extension with no handler: " + extension.getName()); } else { serializer.write(serializerFactory, doc, extensionsElem, ext.getExtension(extension)); } } // Only add extensions element if necessary if(extensionsElem.getChildNodes().getLength() > 0) parentElem.appendChild(extensionsElem); } @Override public Object read(XMLSerializerFactory serializerFactory, OpGraph graph, Object parent, Document doc, Element elem) throws IOException { if(EXTENDABLE_QNAME.equals(XMLSerializerFactory.getQName(elem))) { if(!(parent instanceof Extendable)) throw new IOException("Reading extensions from a parent that is not Extendable"); final Extendable ext = (Extendable)parent; final NodeList children = elem.getChildNodes(); for(int childIndex = 0; childIndex < children.getLength(); ++childIndex) { final Node childNode = children.item(childIndex); if(childNode instanceof Element) { // Find serializer for extension final Element childElem = (Element)childNode; final QName qname = XMLSerializerFactory.getQName(childElem); final XMLSerializer serializer = serializerFactory.getHandler(qname); // If no serializer, we'll just issue a warning if(serializer == null) { // TODO perhaps allow errors to be added to the serializer factory // so that the outside world knows an extension couldn't be // read. Another option is to have an extension that holds // all of the extensions that couldn't be read so that if we // write this Extendable back to XML, those extensions won't // be lost. // LOGGER.warning("Extension element has no handler: " + qname); } else { serializer.read(serializerFactory, graph, ext, doc, childElem); } } } } return null; } @Override public boolean handles(Class<?> cls) { return (cls == Extendable.class); } @Override public boolean handles(QName name) { return EXTENDABLE_QNAME.equals(name); } }