package com.lateensoft.pathfinder.toolkit.serialize; import com.google.common.collect.Lists; import org.dom4j.Element; import org.dom4j.tree.DefaultElement; import java.io.InvalidObjectException; import java.util.List; /** * @author trevsiemens */ public abstract class XMLObjectAdapter<E> { public abstract String getElementName(); protected abstract E createObjectForElement(Element element) throws InvalidObjectException; protected abstract void setElementContentForObject(Element element, E object); public Element toXML(E object) { Element element = new DefaultElement(getElementName()); setElementContentForObject(element, object); return element; } public E toObject(Element element) throws InvalidObjectException { if (element.getName().equals(getElementName())) { return createObjectForElement(element); } else { throw new IllegalArgumentException("Element type " + element.getName() + " does not match " + getElementName()); } } public static int getIntAttribute(Element element, String attrName) throws InvalidObjectException { return getBoundedIntAttribute(element, attrName, Integer.MIN_VALUE, Integer.MAX_VALUE); } public static int getBoundedIntAttribute(Element element, String attrName, int lowestVal, int highestVal) throws InvalidObjectException { try { String intString = element.attributeValue(attrName); if (intString == null) { throw new InvalidObjectException(String.format("Missing integer attribute '%s' in '%s'", attrName, element.getName())); } int val = Integer.parseInt(intString); if (val < lowestVal || val > highestVal) { throw new InvalidObjectException(String.format("'%s' in '%s' must be between %d and %d", attrName, element.getName(), lowestVal, highestVal)); } else { return val; } } catch (NumberFormatException e) { throw new InvalidObjectException(String.format("Malformed integer attribute '%s' in '%s'", attrName, element.getName())); } } public static double getDoubleAttribute(Element element, String attrName) throws InvalidObjectException { return getBoundedDoubleAttribute(element, attrName, Double.MIN_VALUE, Double.MAX_VALUE); } public static double getBoundedDoubleAttribute(Element element, String attrName, double lowestVal, double highestVal) throws InvalidObjectException { try { String doubleString = element.attributeValue(attrName); if (doubleString == null) { throw new InvalidObjectException(String.format("Missing decimal attribute '%s' in '%s'", attrName, element.getName())); } double val = Double.parseDouble(doubleString); if (val < lowestVal || val > highestVal) { throw new InvalidObjectException(String.format("'%s' in '%s' must be between %f and %f", attrName, element.getName(), lowestVal, highestVal)); } else { return val; } } catch (NumberFormatException e) { throw new InvalidObjectException(String.format("Malformed decimal attribute '%s' in '%s'", attrName, element.getName())); } } public static long getLongAttribute(Element element, String attrName) throws InvalidObjectException { try { String longString = element.attributeValue(attrName); if (longString == null) { throw new InvalidObjectException(String.format("Missing large integer attribute '%s' in '%s'", attrName, element.getName())); } return Long.parseLong(longString); } catch (NumberFormatException e) { throw new InvalidObjectException(String.format("Malformed large integer attribute '%s' in '%s'", attrName, element.getName())); } } public static String getStringAttribute(Element element, String attrName) throws InvalidObjectException { String val = element.attributeValue(attrName); if (val == null) { throw new InvalidObjectException(String.format("Missing text attribute '%s' in '%s'", attrName, element.getName())); } else { return val; } } public static boolean getBooleanAttribute(Element element, String attrName) throws InvalidObjectException { String boolString = element.attributeValue(attrName); if (boolString == null) { throw new InvalidObjectException(String.format("Missing boolean attribute '%s' in '%s'", attrName, element.getName())); } if ("true".equalsIgnoreCase(boolString)) return true; else if ("false".equalsIgnoreCase(boolString)) return false; else throw new InvalidObjectException(String.format("Attribute '%s' in '%s' must contain 'true' or 'false'", attrName, element.getName())); } public static String getSubElementText(Element element, String subElementName) throws InvalidObjectException { Element subElement = element.element(subElementName); if (subElement == null) { throw new InvalidObjectException(String.format("Required element '%s' not found in '%s'", subElementName, element.getName())); } return (subElement.getText() != null) ? subElement.getText() : ""; } public static void addSubElementText(Element element, String subElementName, String text) { element.addElement(subElementName).addCDATA(text); } public static <T> List<T> getSubObjects(Element element, XMLObjectAdapter<T> adapter) throws InvalidObjectException { @SuppressWarnings("unchecked") List<Element> subElements = element.elements(adapter.getElementName()); List<T> subObjects = Lists.newArrayListWithCapacity(subElements.size()); for (Element subElement : subElements) { subObjects.add(adapter.toObject(subElement)); } return subObjects; } public static <T> T getSubObject(Element element, XMLObjectAdapter<T> adapter) throws InvalidObjectException { @SuppressWarnings("unchecked") Element subElement = element.element(adapter.getElementName()); if (subElement == null) { throw new InvalidObjectException("Required element " + adapter.getElementName() + " not found in " + element.getName()); } return adapter.toObject(subElement); } }