/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.geometry.xml; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.text.ParseException; import java.util.logging.Level; import java.util.logging.Logger; import org.opengis.geometry.Geometry; import org.opengis.geometry.PrecisionType; import org.opengis.geometry.coordinate.GeometryFactory; import org.opengis.geometry.primitive.PrimitiveFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.xml.sax.SAXException; import org.xml.sax.InputSource; import org.geotools.geometry.GeometryBuilder; import org.geotools.geometry.text.WKTParser; import org.geotools.geometry.iso.PrecisionModel; import org.geotools.referencing.crs.DefaultGeographicCRS; /** * @author <a href="mailto:joel@lggi.com">Joel Skelton</a> * * * * @source $URL$ */ public class GeometryTestParser { private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.geometry"); private DocumentBuilderFactory documentBuilderFactory; private DocumentBuilder documentBuilder; private WKTParser wktFactory; /** * Constructor */ public GeometryTestParser() { documentBuilderFactory = DocumentBuilderFactory.newInstance(); try { documentBuilder = documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new RuntimeException("", e); } GeometryBuilder builder = new GeometryBuilder(DefaultGeographicCRS.WGS84); GeometryFactory geomFact = builder.getGeometryFactory(); PrimitiveFactory primFact = builder.getPrimitiveFactory(); wktFactory = new WKTParser( geomFact, primFact, null, builder.getAggregateFactory() ); } /** * @param inputSource * @return GeometryTestContainer */ public GeometryTestContainer parseTestDefinition(InputSource inputSource) { Document doc = null; try { doc = documentBuilder.parse(inputSource); } catch (SAXException e) { LOGGER.log( Level.FINE, e.getMessage(), e); throw new RuntimeException("", e); } catch (IOException e) { LOGGER.log( Level.FINE, e.getMessage(), e); throw new RuntimeException("", e); } Element element = doc.getDocumentElement(); GeometryTestContainer test = null; try { test = processRootNode(element); } catch (ParseException e) { LOGGER.log( Level.FINE, e.getMessage(), e); throw new RuntimeException("", e); } return test; } /** * Processes the root "run" node * @param node * @return GeometryTestContainer * @throws ParseException */ public GeometryTestContainer processRootNode(Node node) throws ParseException { if (!node.getNodeName().equalsIgnoreCase("run")) { throw new ParseException("Expected run tag, found " + node.getNodeName(), 0); } GeometryTestContainer test = new GeometryTestContainer(); Node child = node.getFirstChild(); // default precision type is float PrecisionType precisionType = PrecisionType.FLOAT; while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { String name = child.getNodeName(); if (name.equalsIgnoreCase("case")) { GeometryTestCase testCase = readTestCase(child); test.addTestCase(testCase); } else if (name.equalsIgnoreCase("precisionmodel")) { precisionType = getPrecisionModel(child); } else { throw new ParseException("Unexpected: " + name, 0); } } child = child.getNextSibling(); } test.setPrecisionModel(new PrecisionModel(precisionType)); return test; } /** * parse a single test case * * From looking at various JTS test cases and seeing how their * testbuilder program works, I think its safe to assume that * there will always be just one or two objects, named a and * b. * * @param testCaseNode * @return GeometryTestCase */ private GeometryTestCase readTestCase(Node testCaseNode) throws ParseException { Node child = testCaseNode.getFirstChild(); GeometryTestCase testCase = new GeometryTestCase(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { String name = child.getNodeName(); if (name.equalsIgnoreCase("test")) { GeometryTestOperation op = loadTestOperation(child); testCase.addTestOperation(op); } else if (name.equalsIgnoreCase("a")) { testCase.setGeometryA(loadTestGeometry(child)); } else if (name.equalsIgnoreCase("b")) { testCase.setGeometryB(loadTestGeometry(child)); } else if (name.equalsIgnoreCase("desc")) { testCase.setDescription(getNodeText(child)); } else { throw new ParseException("Unexpected: " + name, 0); } } child = child.getNextSibling(); } return testCase; } /** * Loads a test operation. Assumes that there _must_ be a name attribute, * and looks for arg1, arg2, and arg3. The value of the text subnode is * the value of the expected result * @param testNode a test node from the xml file * @return GeometryTestOperation */ private GeometryTestOperation loadTestOperation(Node testNode) { Node node = getNamedChild(testNode, "op"); if (node == null) { throw new RuntimeException("<test> element must have <op> subelement"); } String operation = getNodeAttribute(node, "name"); String arg1 = getNodeAttribute(node, "arg1"); String arg2 = getNodeAttribute(node, "arg2"); String arg3 = getNodeAttribute(node, "arg3"); Object expectedResult; String expectedString = getNodeText(node); if (expectedString.trim().equalsIgnoreCase("true")) { expectedResult = Boolean.TRUE; } else if (expectedString.trim().equalsIgnoreCase("false")) { expectedResult = Boolean.FALSE; } else { try { expectedResult = wktFactory.parse(expectedString); } catch (ParseException e) { LOGGER.log( Level.FINE, "Couldn't parse [" + expectedString + "]", e); throw new RuntimeException("Couldn't parse [" + expectedString + "]", e); } } return new GeometryTestOperation(operation, arg1, arg2, arg3, expectedResult); } private Geometry loadTestGeometry(Node node) { String wktString = getNodeText(node); Geometry geom = null; try { geom = wktFactory.parse(wktString); } catch (ParseException e) { LOGGER.log( Level.FINE, "Can't parse [" + wktString + "]", e); throw new RuntimeException("Can't parse [" + wktString + "]", e); } return geom; } private PrecisionType getPrecisionModel(Node child) { String val = getNodeAttribute(child, "type"); if (val == "") { // if scale is 1.0 then set the precision to type FIXED String scale = getNodeAttribute(child, "scale"); if (scale.equalsIgnoreCase("1.0")) return PrecisionType.FIXED; } else if (val.equalsIgnoreCase("DOUBLE")) { return PrecisionType.DOUBLE; } // default return PrecisionType.FLOAT; } private String getNodeAttribute(Node node, String attrName) { String emptyString = ""; NamedNodeMap attrs = node.getAttributes(); if (attrs == null) { return emptyString; } Node attrNode = attrs.getNamedItem(attrName); if (attrNode == null) { return emptyString; } return attrNode.getNodeValue(); } private String getNodeText(Node node) { Node child = node.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.TEXT_NODE) { return child.getNodeValue(); } } return ""; } private Node getNamedChild(Node node, String name) { Node child = node.getFirstChild(); while (child != null) { if (name.equalsIgnoreCase(child.getNodeName())) { return child; } child = child.getNextSibling(); } return null; } }