/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2015, 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.data.geojson; import static org.junit.Assert.*; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.geotools.data.DataStore; import org.geotools.data.DataStoreFinder; import org.geotools.data.DataUtilities; import org.geotools.data.DefaultTransaction; import org.geotools.data.FeatureReader; import org.geotools.data.FeatureWriter; import org.geotools.data.Query; import org.geotools.data.Transaction; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.factory.CommonFactoryFinder; import org.geotools.factory.FactoryFinder; import org.geotools.feature.DefaultFeatureCollection; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.geometry.jts.JTSFactoryFinder; import org.geotools.test.TestData; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; /** * Informal test used to document expected functionality for workshop. * <p> * This test has a setup method used to copy locations.csv to a temporary file. * */ public class GeoJSONWriteTest { File tmp; File file; URL url; @Before public void createTemporaryLocations() throws IOException { // Setting the system-wide default at startup time System.setProperty("org.geotools.referencing.forceXY", "true"); tmp = File.createTempFile("example", ""); boolean exists = tmp.exists(); if (exists) { System.err.println("Removing tempfile " + tmp); tmp.delete(); } boolean created = tmp.mkdirs(); if (!created) { System.err.println("Could not create " + tmp); System.exit(1); } file = new File(tmp, "locations.json"); URL resource = TestData.getResource(GeoJSONWriteTest.class, "locations.json"); url = resource; if (url == null) throw new RuntimeException("Input datafile not found"); System.out.println("copying " + resource.toExternalForm() + " to " + file); Files.copy(resource.openStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); url = DataUtilities.fileToURL(file); } private String checkFileContents(File modified) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); Files.copy(modified.toPath(), baos); String contents = new String(baos.toByteArray(), StandardCharsets.UTF_8); return contents; } @After public void removeTemporaryLocations() throws IOException { File list[] = tmp.listFiles(); for (int i = 0; i < list.length; i++) { list[i].delete(); } tmp.delete(); } @Test public void featureStoreExample() throws Exception { Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", url); DataStore store = DataStoreFinder.getDataStore(params); SimpleFeatureSource featureSource = store.getFeatureSource("locations"); assertTrue("Modification not supported", (featureSource instanceof SimpleFeatureStore)); } @Test public void transactionExample() throws Exception { Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", url); DataStore store = DataStoreFinder.getDataStore(params); Transaction t1 = new DefaultTransaction("transaction 1"); Transaction t2 = new DefaultTransaction("transactoin 2"); SimpleFeatureType type = store.getSchema("locations"); SimpleFeatureStore auto = (SimpleFeatureStore) store.getFeatureSource("locations"); SimpleFeatureStore featureStore1 = (SimpleFeatureStore) store.getFeatureSource("locations"); SimpleFeatureStore featureStore2 = (SimpleFeatureStore) store.getFeatureSource("locations"); featureStore1.setTransaction(t1); featureStore2.setTransaction(t2); // Before we edit everything should be the same assertEquals("featureStore1 before", 9, featureStore1.getFeatures().size()); assertEquals("featureStore2 before", 9, featureStore2.getFeatures().size()); SimpleFeature first = DataUtilities.first(featureStore1.getFeatures()); System.out.println(first); // select feature to remove FilterFactory ff = CommonFactoryFinder.getFilterFactory(null); // Filter filter1 = ff.id(Collections.singleton(ff.featureId(first.getID()))); Filter filter1 = ff.equal(ff.property("CITY"), ff.literal("Trento"), false); featureStore1.removeFeatures(filter1); // removes "Trento" from fs1 // Tests after removal assertEquals("auto after featureStore1 removes fid1", 9, auto.getFeatures().size()); assertEquals("featureStore1 after featureStore1 removes fid1", 8, featureStore1.getFeatures().size()); assertEquals("featureStore2 after featureStore1 removes fid1", 9, featureStore2.getFeatures().size()); // new feature to add! // 45.52, -122.681944, Portland, 800, 2014 GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); Point point = geometryFactory.createPoint(new Coordinate(-122.681944, 45.52)); SimpleFeature feature = SimpleFeatureBuilder.build(type, new Object[] { 45.52, -122.681944, "Portland", 800, 2014, point }, "feature-10"); System.out.println(feature); SimpleFeatureCollection collection = DataUtilities.collection(feature); featureStore2.addFeatures(collection); // Tests after adding the feature assertEquals("auto after featureStore1 removes Trento and featureStore2 adds Portland", 9, auto.getFeatures().size()); assertEquals("featureStore1 after featureStore1 removes fid1 and featureStore2 adds fid5", 8, featureStore1.getFeatures().size()); assertEquals("featureStore2 after featureStore1 removes fid1 and featureStore2 adds fid5", 10, featureStore2.getFeatures().size()); // commit transaction one t1.commit(); // Tests after first commit assertEquals( "auto after featureStore1 commits removal of fid1 (featureStore2 has added fid5)", 8, auto.getFeatures().size()); assertEquals("featureStore1 after commiting removal of fid1 (featureStore2 has added fid5)", 8, featureStore1.getFeatures().size()); assertEquals( "featureStore2 after featureStore1 commits removal of fid1 (featureStore2 has added fid5)", 9, featureStore2.getFeatures().size()); // commit transaction two t2.commit(); // Tests after 2nd commit assertEquals("auto after featureStore2 commits addition of fid5 (fid1 previously removed)", 9, auto.getFeatures().size()); assertEquals( "featureStore1 after featureStore2 commits addition of fid5 (fid1 previously removed)", 9, featureStore1.getFeatures().size()); assertEquals("featureStore2 after commiting addition of fid5 (fid1 previously removed)", 9, featureStore2.getFeatures().size()); t1.close(); t2.close(); store.dispose(); // clear out any listeners } @Test public void removeAllExample() throws Exception { Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", url); DataStore store = DataStoreFinder.getDataStore(params); Transaction t = new DefaultTransaction("locations"); try { FeatureWriter<SimpleFeatureType, SimpleFeature> writer = store .getFeatureWriter("locations", Filter.INCLUDE, t); try { while (writer.hasNext()) { writer.next(); writer.remove(); // marking contents for removal } } finally { writer.close(); } // Test the contents have been removed SimpleFeatureStore featureStore = (SimpleFeatureStore) store .getFeatureSource("locations"); assertEquals("featureStore should be empty", 0, featureStore.getFeatures().size()); // Make sure the file is empty assertEquals("file should have no content", "", checkFileContents(file)); t.commit(); } catch (Throwable eek) { t.rollback(); } finally { t.close(); store.dispose(); } } @Test public void replaceAll() throws Exception { Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", url); System.out.println("fetching store from " + url); DataStore store = DataStoreFinder.getDataStore(params); final SimpleFeatureType type = store.getSchema("locations"); assertNotNull(type); final FeatureWriter<SimpleFeatureType, SimpleFeature> writer; SimpleFeature f; DefaultFeatureCollection collection = new DefaultFeatureCollection(); // 45.52, -122.681944, Portland, 800, 2014 GeometryFactory gf = JTSFactoryFinder.getGeometryFactory(); Point portland = gf.createPoint(new Coordinate(45.52, -122.681944)); f = SimpleFeatureBuilder.build(type, new Object[] { 45.52, -122.681944, "Portland", 800, 2014, portland }, "locations.1"); collection.add(f); writer = store.getFeatureWriter("locations", Transaction.AUTO_COMMIT); try { // remove all features while (writer.hasNext()) { writer.next(); writer.remove(); } // copy new features in SimpleFeatureIterator iterator = collection.features(); while (iterator.hasNext()) { SimpleFeature feature = iterator.next(); SimpleFeature newFeature = writer.next(); // new blank feature newFeature.setAttributes(feature.getAttributes()); writer.write(); } } finally { writer.close(); } // Test everything was replaced by the one feature we added SimpleFeatureStore featureStore = (SimpleFeatureStore) store.getFeatureSource("locations"); assertEquals("featureStore should only have the one feature we created", 1, featureStore.getFeatures().size()); final String newline = System.lineSeparator(); String contents = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[45.52,-122.6819]},\"properties\":{\"LAT\":45.52,\"LON\":-122.681944,\"CITY\":\"Portland\",\"NUMBER\":800,\"YEAR\":2014},\"id\":\"locations.0\"}]}"; assertEquals("Ensure the file has only the one feature we created", contents.trim(), checkFileContents(file).trim()); } @Test public void copyContent() throws Exception { File directory = tmp; Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", url); DataStore store = DataStoreFinder.getDataStore(params); SimpleFeatureType featureType = store.getSchema("locations"); File file2 = new File(directory, "duplicate.json"); Map<String, Serializable> params2 = new HashMap<String, Serializable>(); params2.put("url", DataUtilities.fileToURL(file2)); GeoJSONDataStoreFactory factory = new GeoJSONDataStoreFactory(); DataStore duplicate = factory.createNewDataStore(params2); duplicate.createSchema(featureType); FeatureReader<SimpleFeatureType, SimpleFeature> reader; FeatureWriter<SimpleFeatureType, SimpleFeature> writer; SimpleFeature feature, newFeature; Query query = new Query(featureType.getTypeName(), Filter.INCLUDE); reader = store.getFeatureReader(query, Transaction.AUTO_COMMIT); writer = duplicate.getFeatureWriterAppend("duplicate", Transaction.AUTO_COMMIT); try { while (reader.hasNext()) { feature = reader.next(); newFeature = writer.next(); newFeature.setAttributes(feature.getAttributes()); writer.write(); } } finally { reader.close(); writer.close(); } // test the new store is the same as the original SimpleFeatureStore featureStore = (SimpleFeatureStore) store.getFeatureSource("locations"); assertEquals(9, featureStore.getFeatures().size()); SimpleFeatureStore featureStored = (SimpleFeatureStore) duplicate .getFeatureSource("duplicate"); assertEquals(9, featureStored.getFeatures().size()); SimpleFeatureIterator original = featureStore.getFeatures().features(); SimpleFeatureIterator dups = featureStored.getFeatures().features(); try { while (original.hasNext() && dups.hasNext()) { SimpleFeature o = original.next(); SimpleFeature d = dups.next(); for (int i = 0; i < o.getAttributeCount(); i++) { assertTrue(DataUtilities.attributesEqual(o.getAttribute(i), d.getAttribute(i))); } } } finally { original.close(); dups.close(); } } public static void assertEqualsIgnoreWhitespace(String message, String expected, String actual) { expected = removeWhitespace(expected); actual = removeWhitespace(actual); assertEquals(message, expected, actual); } private static String removeWhitespace(String actual) { if (actual == null) return ""; StringBuffer crush = new StringBuffer(actual); int ch = 0; while (ch < crush.length()) { char chracter = crush.charAt(ch); if (Character.isWhitespace(chracter)) { crush.deleteCharAt(ch); continue; } ch++; } return crush.toString(); } }