/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, availible at the root * application directory. */ package org.geoserver.rest; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import org.restlet.data.MediaType; import org.restlet.resource.OutputRepresentation; import org.restlet.resource.Representation; /** * The AutoXMLFormat class automatically converts a map into an XML document * with a pretty direct mapping between XML and in-memory structure. Map keys * are used as tag names, with the contents being either: * <ul> * <li> A single string </li> * <li> Another map </li> * <li> A list represented by objects in <entry> tags </li> * <ul> * * This format can automatically reconstruct the map from the XML. Note that, * since the in-memory structure is deduced from the contents of each tag, strange * things may happen if you try to use "entry" as a map key. * * @author David Winslow <dwinslow@openplans.org> */ public class AutoXMLFormat implements DataFormat { String myRootName; /** * Create an AutoXMLFormat that will wrap the entire document in an element called 'root'. */ public AutoXMLFormat(){ this("root"); } /** * Create an AutoXMLFormat that will wrap the entire document in an element named with the * string given. * * @param s the name of the root element for XML generated by this AutoXMLFormat */ public AutoXMLFormat(String s){ myRootName = s; } public Representation makeRepresentation(Object context) { Element root = new Element(myRootName); final Document doc = new Document(root); insert(root, context); return new OutputRepresentation(MediaType.APPLICATION_XML){ public void write(OutputStream outputStream){ try{ XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat()); outputter.output(doc, outputStream); } catch(IOException ioe){ ioe.printStackTrace(); } } }; } /** * Generate the JDOM element needed to represent an object and insert it into the parent element given. * @todo This method is recursive and could cause stack overflow errors for large input maps. * * @param elem the parent Element into which to insert the created JDOM element * @param o the Object to be converted */ private final void insert(Element elem, Object o){ if (o instanceof Map){ Iterator it = ((Map)o).entrySet().iterator(); while (it.hasNext()){ Map.Entry entry = (Map.Entry)it.next(); Element newElem = new Element(entry.getKey().toString()); insert(newElem, entry.getValue()); elem.addContent(newElem); } } else if (o instanceof Collection) { Iterator it = ((Collection)o).iterator(); while (it.hasNext()){ Element newElem = new Element("entry"); Object entry = it.next(); insert(newElem, entry); elem.addContent(newElem); } } else { elem.addContent(o == null ? "" : o.toString()); } } public Object readRepresentation(Representation rep) { Object result = null; try { SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(rep.getStream()); Element elem = doc.getRootElement(); result = convert(elem); } catch (Exception e){ } return result; } /** * Interpret XML and convert it back to a Java collection. * * @param elem a JDOM element * @return the Object produced by interpreting the XML */ private Object convert(Element elem){ List children = elem.getChildren(); if (children.size() == 0){ if (elem.getContent().size() == 0){ return null; } else { return elem.getText(); } } else if (children.get(0) instanceof Element){ Element child = (Element)children.get(0); if (child.getName().equals("entry")){ List l = new ArrayList(); Iterator it = elem.getChildren("entry").iterator(); while(it.hasNext()){ Element curr = (Element)it.next(); l.add(convert(curr)); } return l; } else { Map m = new HashMap(); Iterator it = children.iterator(); while (it.hasNext()){ Element curr = (Element)it.next(); m.put(curr.getName(), convert(curr)); } return m; } } throw new RuntimeException("Hm, there was a problem parsing XML"); } }