/** * Copyright (c) Codice Foundation * <p/> * This 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, either version 3 of the * License, or any later version. * <p/> * 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 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.catalog.transformer.metacard.geojson; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; import java.util.TimeZone; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.catalog.data.BinaryContent; import ddf.catalog.data.Metacard; import ddf.catalog.data.impl.BasicTypes; import ddf.catalog.data.impl.MetacardImpl; import ddf.catalog.transform.CatalogTransformerException; import ddf.geo.formatter.CompositeGeometry; import ddf.geo.formatter.GeometryCollection; import ddf.geo.formatter.LineString; import ddf.geo.formatter.MultiLineString; import ddf.geo.formatter.MultiPoint; import ddf.geo.formatter.MultiPolygon; import ddf.geo.formatter.Point; import ddf.geo.formatter.Polygon; /** * Tests the {@link GeoJsonMetacardTransformer} * */ public class TestGeoJsonMetacardTransformer { public static final String DEFAULT_TITLE = "myTitle"; public static final String DEFAULT_VERSION = "myVersion"; public static final String DEFAULT_TYPE = "myType"; public static final String DEFAULT_LOCATION = "POINT (1 0)"; public static final String DEFAULT_SOURCE_ID = "ddfChild"; private static final Logger LOGGER = LoggerFactory .getLogger(TestGeoJsonMetacardTransformer.class); private static final JSONParser PARSER = new JSONParser(); private static final String SOURCE_ID_PROPERTY = "source-id"; @Test(expected = CatalogTransformerException.class) public void testNullMetacard() throws CatalogTransformerException { new GeoJsonMetacardTransformer().transform(null, null); } /** * Tests that proper JSON output is received when no {@link Metacard#GEOGRAPHY} is found. * * @throws CatalogTransformerException * @throws IOException * @throws ParseException */ @Test public void testNoGeo() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; assertThat(obj2.get("geometry"), nullValue()); verifyBasicMetacardJson(now, obj2); } /** * Tests that improper WKT throws an exception * * @throws CatalogTransformerException * @throws IOException * @throws ParseException */ @Test(expected = CatalogTransformerException.class) public void testwithBadGeo() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); String badWktMissingComma = "MULTILINESTRING ((10 10, 20 20, 10 40)(40 40, 30 30, 40 20, 30 10))"; metacard.setLocation(badWktMissingComma); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); } /** * Tests that a POINT Geography can be returned in JSON * * @throws CatalogTransformerException * @throws IOException * @throws ParseException */ @Test public void testwithPointGeo() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation(DEFAULT_LOCATION); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(Point.TYPE)); List<Double> coords = (List<Double>) geometryMap.get(CompositeGeometry.COORDINATES_KEY); assertThat(coords.size(), is(2)); assertThat(coords.get(0), equalTo(1.0)); assertThat(coords.get(1), equalTo(0.0)); verifyBasicMetacardJson(now, obj2); } /** * Tests that a LineString Geography can be returned in JSON * * @throws CatalogTransformerException * @throws IOException * @throws ParseException */ @Test public void testwithLineStringGeo() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation("LINESTRING (30 10, 10 30, 40 40)"); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(LineString.TYPE)); List<List<Double>> coordsList = (List<List<Double>>) geometryMap .get(CompositeGeometry.COORDINATES_KEY); assertThat(coordsList.size(), is(3)); for (List list : coordsList) { assertEquals(list.size(), 2); } assertThat(coordsList.get(0).get(0), equalTo(30.0)); assertThat(coordsList.get(0).get(1), equalTo(10.0)); assertThat(coordsList.get(1).get(0), equalTo(10.0)); assertThat(coordsList.get(1).get(1), equalTo(30.0)); assertThat(coordsList.get(2).get(0), equalTo(40.0)); assertThat(coordsList.get(2).get(1), equalTo(40.0)); verifyBasicMetacardJson(now, obj2); } @Test public void testwithMultiPointGeo() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation("MULTIPOINT ((30 10), (10 30), (40 40))"); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(MultiPoint.TYPE)); List<List<Double>> coordsList = (List<List<Double>>) geometryMap .get(CompositeGeometry.COORDINATES_KEY); assertThat(coordsList.size(), is(3)); for (List list : coordsList) { assertEquals(list.size(), 2); } assertThat(coordsList.get(0).get(0), equalTo(30.0)); assertThat(coordsList.get(0).get(1), equalTo(10.0)); assertThat(coordsList.get(1).get(0), equalTo(10.0)); assertThat(coordsList.get(1).get(1), equalTo(30.0)); assertThat(coordsList.get(2).get(0), equalTo(40.0)); assertThat(coordsList.get(2).get(1), equalTo(40.0)); verifyBasicMetacardJson(now, obj2); } @Test public void testwithMultiLineStringGeo() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation( "MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))"); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(MultiLineString.TYPE)); List<List<List<Double>>> coordsList = (List<List<List<Double>>>) geometryMap .get(CompositeGeometry.COORDINATES_KEY); assertThat(coordsList.size(), is(2)); List<List<Double>> list1 = coordsList.get(0); List<List<Double>> list2 = coordsList.get(1); assertThat(list1.get(0).get(0), equalTo(10.0)); assertThat(list1.get(0).get(1), equalTo(10.0)); assertThat(list1.get(1).get(0), equalTo(20.0)); assertThat(list1.get(1).get(1), equalTo(20.0)); assertThat(list1.get(2).get(0), equalTo(10.0)); assertThat(list1.get(2).get(1), equalTo(40.0)); assertThat(list2.get(0).get(0), equalTo(40.0)); assertThat(list2.get(0).get(1), equalTo(40.0)); assertThat(list2.get(1).get(0), equalTo(30.0)); assertThat(list2.get(1).get(1), equalTo(30.0)); assertThat(list2.get(2).get(0), equalTo(40.0)); assertThat(list2.get(2).get(1), equalTo(20.0)); assertThat(list2.get(3).get(0), equalTo(30.0)); assertThat(list2.get(3).get(1), equalTo(10.0)); verifyBasicMetacardJson(now, obj2); } @Test public void testwithPolygonGeoNoHole() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation("POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(Polygon.TYPE)); List<List> listOfRings = (List<List>) geometryMap.get(CompositeGeometry.COORDINATES_KEY); assertThat(listOfRings.size(), is(1)); List<List> exteriorRing = listOfRings.get(0); testPopularPolygon(exteriorRing); verifyBasicMetacardJson(now, obj2); } @Test public void testwithPolygonGeoWithHole() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation( "POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10),(20 30, 35 35, 30 20, 20 30))"); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(Polygon.TYPE)); List<List> listOfRings = (List<List>) geometryMap.get(CompositeGeometry.COORDINATES_KEY); assertThat(listOfRings.size(), is(2)); List<List> exteriorRing = listOfRings.get(0); List<List> interiorRing = listOfRings.get(1); testPopularPolygon(exteriorRing); List<Double> interiorlist1 = interiorRing.get(0); List<Double> interiorlist2 = interiorRing.get(1); List<Double> interiorlist3 = interiorRing.get(2); List<Double> interiorlist4 = interiorRing.get(3); assertThat(interiorlist1.get(0), equalTo(20.0)); assertThat(interiorlist1.get(1), equalTo(30.0)); assertThat(interiorlist2.get(0), equalTo(35.0)); assertThat(interiorlist2.get(1), equalTo(35.0)); assertThat(interiorlist3.get(0), equalTo(30.0)); assertThat(interiorlist3.get(1), equalTo(20.0)); assertThat(interiorlist4.get(0), equalTo(20.0)); assertThat(interiorlist4.get(1), equalTo(30.0)); verifyBasicMetacardJson(now, obj2); } @Test public void testWithMultiPolygonGeo() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation( "MULTIPOLYGON (((30 10, 10 20, 20 40, 40 40, 30 10)),((15 5, 40 10, 10 20, 5 10, 15 5)))"); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(MultiPolygon.TYPE)); List<List> listOfPolygons = (List<List>) geometryMap.get(CompositeGeometry.COORDINATES_KEY); assertThat(listOfPolygons.size(), is(2)); List<List> polygon1 = listOfPolygons.get(0); List<List> polygon2 = listOfPolygons.get(1); List<List> polygon1FirstRing = polygon1.get(0); List<List> polygon2FirstRing = polygon2.get(0); testPopularPolygon(polygon1FirstRing); testSecondPolygon(polygon2FirstRing); verifyBasicMetacardJson(now, obj2); } @Test public void testWithGeometryCollection() throws CatalogTransformerException, IOException, ParseException { Date now = new Date(); MetacardImpl metacard = new MetacardImpl(); metacard.setLocation("GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10))"); setupBasicMetacard(now, metacard); GeoJsonMetacardTransformer transformer = new GeoJsonMetacardTransformer(); BinaryContent content = transformer.transform(metacard, null); assertEquals(content.getMimeTypeValue(), GeoJsonMetacardTransformer.defaultMimeType.getBaseType()); String jsonText = new String(content.getByteArray()); LOGGER.debug(jsonText); Object object = PARSER.parse(jsonText); JSONObject obj2 = (JSONObject) object; Map geometryMap = (Map) obj2.get("geometry"); assertThat(geometryMap.get(CompositeGeometry.TYPE_KEY).toString(), is(GeometryCollection.TYPE)); assertThat(geometryMap.get(CompositeGeometry.GEOMETRIES_KEY), notNullValue()); verifyBasicMetacardJson(now, obj2); } protected void testPopularPolygon(List<List> exteriorRing) { // (30 10, 10 20, 20 40, 40 40, 30 10) List<Double> list1 = exteriorRing.get(0); List<Double> list2 = exteriorRing.get(1); List<Double> list3 = exteriorRing.get(2); List<Double> list4 = exteriorRing.get(3); List<Double> list5 = exteriorRing.get(4); assertThat(list1.get(0), equalTo(30.0)); assertThat(list1.get(1), equalTo(10.0)); assertThat(list2.get(0), equalTo(10.0)); assertThat(list2.get(1), equalTo(20.0)); assertThat(list3.get(0), equalTo(20.0)); assertThat(list3.get(1), equalTo(40.0)); assertThat(list4.get(0), equalTo(40.0)); assertThat(list4.get(1), equalTo(40.0)); assertThat(list5.get(0), equalTo(30.0)); assertThat(list5.get(1), equalTo(10.0)); } protected void testSecondPolygon(List<List> exteriorRing) { // (15 5, 40 10, 10 20, 5 10, 15 5) List<Double> list1 = exteriorRing.get(0); List<Double> list2 = exteriorRing.get(1); List<Double> list3 = exteriorRing.get(2); List<Double> list4 = exteriorRing.get(3); List<Double> list5 = exteriorRing.get(4); assertThat(list1.get(0), equalTo(15.0)); assertThat(list1.get(1), equalTo(5.0)); assertThat(list2.get(0), equalTo(40.0)); assertThat(list2.get(1), equalTo(10.0)); assertThat(list3.get(0), equalTo(10.0)); assertThat(list3.get(1), equalTo(20.0)); assertThat(list4.get(0), equalTo(5.0)); assertThat(list4.get(1), equalTo(10.0)); assertThat(list5.get(0), equalTo(15.0)); assertThat(list5.get(1), equalTo(5.0)); } private void setupBasicMetacard(Date now, MetacardImpl metacard) { metacard.setCreatedDate(now); metacard.setModifiedDate(now); metacard.setMetadata("<xml></xml>"); metacard.setContentTypeName(DEFAULT_TYPE); metacard.setContentTypeVersion(DEFAULT_VERSION); byte[] buffer = {8}; metacard.setThumbnail(buffer); // metacard.setSourceId(DEFAULT_SOURCE_ID) ; metacard.setTitle(DEFAULT_TITLE); metacard.setSourceId(DEFAULT_SOURCE_ID); try { metacard.setResourceURI(new URI("http://example.com")); } catch (URISyntaxException e) { LOGGER.warn("URI Syntax exception setting resource URI", e); } } private void verifyBasicMetacardJson(Date now, JSONObject obj2) { assertThat(obj2.size(), is(3)); // no extra members assertThat(obj2.get("type").toString(), equalTo("Feature")); assertThat(obj2.get("properties"), notNullValue()); Map properties = ((Map) obj2.get("properties")); assertThat(properties.size(), is(10)); // no extra // properties assertThat(toString(properties.get(Metacard.TITLE)), is(DEFAULT_TITLE)); assertThat(toString(properties.get(Metacard.CONTENT_TYPE)), is(DEFAULT_TYPE)); assertThat(toString(properties.get(Metacard.CONTENT_TYPE_VERSION)), is(DEFAULT_VERSION)); SimpleDateFormat dateFormat = new SimpleDateFormat( GeoJsonMetacardTransformer.ISO_8601_DATE_FORMAT); dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); assertThat(toString(properties.get(Metacard.CREATED)), is(dateFormat.format(now))); assertThat(toString(properties.get(Metacard.EXPIRATION)), nullValue()); assertThat(toString(properties.get(Metacard.EFFECTIVE)), nullValue()); assertThat(toString(properties.get(Metacard.MODIFIED)), is(dateFormat.format(now))); assertThat(toString(properties.get(Metacard.THUMBNAIL)), is("CA==")); assertThat(toString(properties.get(Metacard.METADATA)), is("<xml></xml>")); assertThat(toString(properties.get(Metacard.RESOURCE_URI)), is("http://example.com")); assertThat(toString(properties.get(SOURCE_ID_PROPERTY)), is(DEFAULT_SOURCE_ID)); assertThat(toString(properties.get(GeoJsonMetacardTransformer.METACARD_TYPE_PROPERTY_KEY)), is(BasicTypes.BASIC_METACARD.getName())); } private String toString(Object object) { if (object != null) { return object.toString(); } return null; } }