package mil.nga.giat.geowave.adapter.vector; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.commons.lang3.tuple.Pair; import org.geotools.data.DataUtilities; import org.geotools.feature.SchemaException; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.filter.text.cql2.CQLException; import org.geotools.geometry.jts.JTSFactoryFinder; import org.junit.Before; import org.junit.Test; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.PrecisionModel; import mil.nga.giat.geowave.adapter.vector.plugin.GeoWaveGTDataStore; import mil.nga.giat.geowave.adapter.vector.util.FeatureDataUtils; import mil.nga.giat.geowave.adapter.vector.utils.DateUtilities; import mil.nga.giat.geowave.core.geotime.ingest.SpatialDimensionalityTypeProvider.SpatialIndexBuilder; import mil.nga.giat.geowave.core.geotime.store.query.SpatialQuery; import mil.nga.giat.geowave.core.store.CloseableIterator; import mil.nga.giat.geowave.core.store.DataStore; import mil.nga.giat.geowave.core.store.IndexWriter; import mil.nga.giat.geowave.core.store.StoreFactoryFamilySpi; import mil.nga.giat.geowave.core.store.StoreFactoryOptions; import mil.nga.giat.geowave.core.store.adapter.AdapterPersistenceEncoding; import mil.nga.giat.geowave.core.store.adapter.IndexFieldHandler; import mil.nga.giat.geowave.core.store.adapter.IndexedAdapterPersistenceEncoding; import mil.nga.giat.geowave.core.store.data.PersistentDataset; import mil.nga.giat.geowave.core.store.data.visibility.GlobalVisibilityHandler; import mil.nga.giat.geowave.core.store.index.CommonIndexValue; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.core.store.memory.MemoryStoreFactoryFamily; import mil.nga.giat.geowave.core.store.query.QueryOptions; import mil.nga.giat.geowave.core.store.util.DataStoreUtils; public class AvroFeatureDataAdapterTest { private SimpleFeatureType schema; private SimpleFeature newFeature; private Date time1; private Date time2; private static DataStore dataStore; GeometryFactory factory = new GeometryFactory( new PrecisionModel( PrecisionModel.FIXED)); @SuppressWarnings("unchecked") @Before public void setup() throws SchemaException, CQLException, ParseException { final StoreFactoryFamilySpi storeFactoryFamily = new MemoryStoreFactoryFamily(); StoreFactoryOptions opts = storeFactoryFamily.getDataStoreFactory().createOptionsInstance(); opts.setGeowaveNamespace("test_avro"); dataStore = storeFactoryFamily.getDataStoreFactory().createStore( opts); try { time1 = DateUtilities.parseISO("2005-05-19T18:33:55Z"); time2 = DateUtilities.parseISO("2005-05-19T19:33:55Z"); schema = DataUtilities.createType( "sp.geostuff", "geometry:Geometry:srid=4326,pop:java.lang.Long,when:Date,whennot:Date,pid:String");// typeBuilder.buildFeatureType(); newFeature = FeatureDataUtils.buildFeature( schema, new Pair[] { Pair.of( "geometry", factory.createPoint(new Coordinate( 27.25, 41.25))), Pair.of( "pop", Long.valueOf(100)), Pair.of( "when", time1), Pair.of( "whennot", time2) }); } catch (final Exception e) { e.printStackTrace(); } } private static void ingestCannedData( final FeatureDataAdapter adapter, final List<SimpleFeature> data ) throws IOException { final PrimaryIndex index = new SpatialIndexBuilder().createIndex(); try (IndexWriter indexWriter = dataStore.createWriter( adapter, index)) { for (final SimpleFeature sf : data) { indexWriter.write( sf, DataStoreUtils.UNCONSTRAINED_VISIBILITY); } } System.out.println("Ingest complete."); } @Test public void basicTest() throws Exception { final AvroFeatureDataAdapter adapter = new AvroFeatureDataAdapter( schema); final GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); final SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder( schema); final int numFeatures = 10; final List<SimpleFeature> data = new ArrayList<SimpleFeature>(); final Map<Integer, SimpleFeature> dataMap = new HashMap<Integer, SimpleFeature>(); // Write data using the whole feature data adapter for (int i = 0; i < numFeatures; i++) { final Point point = geometryFactory.createPoint(new Coordinate( i, i)); featureBuilder.set( "geometry", point); featureBuilder.set( "pop", i); featureBuilder.set( "when", new Date( 0)); featureBuilder.set( "whennot", new Date()); data.add(featureBuilder.buildFeature(Integer.toString(i))); dataMap.put( i, data.get(data.size() - 1)); } ingestCannedData( adapter, data); final Coordinate[] coordArray = new Coordinate[5]; coordArray[0] = new Coordinate( -180, -90); coordArray[1] = new Coordinate( 180, -90); coordArray[2] = new Coordinate( 180, 90); coordArray[3] = new Coordinate( -180, 90); coordArray[4] = new Coordinate( -180, -90); // read data using the whole feature data adapter try (final CloseableIterator<SimpleFeature> itr = dataStore.query( new QueryOptions( adapter, new SpatialIndexBuilder().createIndex()), new SpatialQuery( new GeometryFactory().createPolygon(coordArray)))) { while (itr.hasNext()) { final SimpleFeature feat = itr.next(); final SimpleFeature feature = dataMap.remove(Integer.parseInt(feat.getID())); assertEquals( feature, feat); } assertTrue(dataMap.isEmpty()); } } @Test public void testDifferentProjection() throws SchemaException { final SimpleFeatureType schema = DataUtilities.createType( "sp.geostuff", "geometry:Geometry:srid=4326,pop:java.lang.Long"); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final CoordinateReferenceSystem crs = dataAdapter.getFeatureType().getCoordinateReferenceSystem(); assertTrue(crs.getIdentifiers().toString().contains( "EPSG:4326")); @SuppressWarnings("unchecked") final SimpleFeature originalFeature = FeatureDataUtils.buildFeature( schema, new Pair[] { Pair.of( "geometry", factory.createPoint(new Coordinate( 27.25, 41.25))), Pair.of( "pop", Long.valueOf(100)) }); final AdapterPersistenceEncoding persistenceEncoding = dataAdapter.encode( originalFeature, new SpatialIndexBuilder().createIndex().getIndexModel()); final IndexedAdapterPersistenceEncoding encoding = new IndexedAdapterPersistenceEncoding( dataAdapter.getAdapterId(), persistenceEncoding.getDataId(), null, 1, persistenceEncoding.getCommonData(), new PersistentDataset<byte[]>(), persistenceEncoding.getAdapterExtendedData()); final SimpleFeature decodedFeature = dataAdapter.decode( encoding, new PrimaryIndex( null, // because we know the feature data adapter // doesn't use the numeric index strategy // and only the common index model to decode // the simple feature, we pass along a null // strategy to eliminate the necessity to // send a serialization of the strategy in // the options of this iterator new SpatialIndexBuilder().createIndex().getIndexModel())); assertTrue(originalFeature.getID().equals( decodedFeature.getID())); assertTrue(originalFeature.getAttributeCount() == decodedFeature.getAttributeCount()); for (int i = 0; i < originalFeature.getAttributes().size(); i++) { assertTrue(originalFeature.getAttribute( i).equals( decodedFeature.getAttribute(i))); } } @Test public void testSingleTime() { schema.getDescriptor( "when").getUserData().clear(); schema.getDescriptor( "whennot").getUserData().put( "time", Boolean.TRUE); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final AvroFeatureDataAdapter dataAdapterCopy = new AvroFeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( dataAdapterCopy.getAdapterId(), dataAdapter.getAdapterId()); assertEquals( dataAdapterCopy.getFeatureType(), dataAdapter.getFeatureType()); assertEquals( Boolean.TRUE, dataAdapterCopy.getFeatureType().getDescriptor( "whennot").getUserData().get( "time")); final List<IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object>> handlers = dataAdapterCopy .getDefaultTypeMatchingHandlers(schema); boolean found = false; for (final IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object> handler : handlers) { found |= ((handler instanceof FeatureTimestampHandler) && ((((FeatureTimestampHandler) handler) .toIndexValue( newFeature) .toNumericData() .getMin() - time2.getTime()) < 0.001)); } assertTrue(found); } @Test public void testVisibility() { schema.getDescriptor( "pid").getUserData().clear(); schema.getDescriptor( "pid").getUserData().put( "visibility", Boolean.TRUE); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final AvroFeatureDataAdapter dataAdapterCopy = new AvroFeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( dataAdapterCopy.getAdapterId(), dataAdapter.getAdapterId()); assertEquals( dataAdapterCopy.getFeatureType(), dataAdapter.getFeatureType()); assertEquals( Boolean.TRUE, dataAdapterCopy.getFeatureType().getDescriptor( "pid").getUserData().get( "visibility")); } @Test public void testNoTime() { schema.getDescriptor( "when").getUserData().clear(); schema.getDescriptor( "whennot").getUserData().clear(); schema.getDescriptor( "when").getUserData().put( "time", Boolean.FALSE); schema.getDescriptor( "whennot").getUserData().put( "time", Boolean.FALSE); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final List<IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object>> handlers = dataAdapter .getDefaultTypeMatchingHandlers(schema); boolean found = false; for (final IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object> handler : handlers) { found |= (handler instanceof FeatureTimestampHandler); } assertFalse(found); } @Test public void testInferredTime() { schema.getDescriptor( "when").getUserData().clear(); schema.getDescriptor( "whennot").getUserData().clear(); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final AvroFeatureDataAdapter dataAdapterCopy = new AvroFeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( dataAdapterCopy.getAdapterId(), dataAdapter.getAdapterId()); assertEquals( dataAdapterCopy.getFeatureType(), dataAdapter.getFeatureType()); assertEquals( Boolean.TRUE, dataAdapterCopy.getFeatureType().getDescriptor( "when").getUserData().get( "time")); final List<IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object>> handlers = dataAdapterCopy .getDefaultTypeMatchingHandlers(schema); boolean found = false; for (final IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object> handler : handlers) { found |= ((handler instanceof FeatureTimestampHandler) && ((((FeatureTimestampHandler) handler) .toIndexValue( newFeature) .toNumericData() .getMin() - time1.getTime()) < 0.001)); } assertTrue(found); } @Test public void testRange() { schema.getDescriptor( "when").getUserData().clear(); schema.getDescriptor( "whennot").getUserData().clear(); schema.getDescriptor( "when").getUserData().put( "start", Boolean.TRUE); schema.getDescriptor( "whennot").getUserData().put( "end", Boolean.TRUE); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final AvroFeatureDataAdapter dataAdapterCopy = new AvroFeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( dataAdapterCopy.getAdapterId(), dataAdapter.getAdapterId()); assertEquals( dataAdapterCopy.getFeatureType(), dataAdapter.getFeatureType()); assertEquals( Boolean.TRUE, dataAdapterCopy.getFeatureType().getDescriptor( "whennot").getUserData().get( "end")); assertEquals( Boolean.TRUE, dataAdapterCopy.getFeatureType().getDescriptor( "when").getUserData().get( "start")); final List<IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object>> handlers = dataAdapterCopy .getDefaultTypeMatchingHandlers(schema); boolean found = false; for (final IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object> handler : handlers) { found |= ((handler instanceof FeatureTimeRangeHandler) && ((((FeatureTimeRangeHandler) handler).toIndexValue( newFeature).toNumericData().getMin() - time1.getTime()) < 0.001) && ((((FeatureTimeRangeHandler) handler) .toIndexValue( newFeature) .toNumericData() .getMax() - time2.getTime()) < 0.001)); } assertTrue(found); } @Test public void testInferredRange() throws SchemaException { final SimpleFeatureType schema = DataUtilities.createType( "sp.geostuff", "geometry:Geometry:srid=4326,pop:java.lang.Long,start:Date,end:Date,pid:String"); final List<AttributeDescriptor> descriptors = schema.getAttributeDescriptors(); final Object[] defaults = new Object[descriptors.size()]; int p = 0; for (final AttributeDescriptor descriptor : descriptors) { defaults[p++] = descriptor.getDefaultValue(); } final SimpleFeature newFeature = SimpleFeatureBuilder.build( schema, defaults, UUID.randomUUID().toString()); newFeature.setAttribute( "pop", Long.valueOf(100)); newFeature.setAttribute( "pid", UUID.randomUUID().toString()); newFeature.setAttribute( "start", time1); newFeature.setAttribute( "end", time2); newFeature.setAttribute( "geometry", factory.createPoint(new Coordinate( 27.25, 41.25))); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final AvroFeatureDataAdapter dataAdapterCopy = new AvroFeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( dataAdapterCopy.getAdapterId(), dataAdapter.getAdapterId()); assertEquals( dataAdapterCopy.getFeatureType(), dataAdapter.getFeatureType()); assertEquals( Boolean.TRUE, dataAdapterCopy.getFeatureType().getDescriptor( "end").getUserData().get( "end")); assertEquals( Boolean.TRUE, dataAdapterCopy.getFeatureType().getDescriptor( "start").getUserData().get( "start")); final List<IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object>> handlers = dataAdapterCopy .getDefaultTypeMatchingHandlers(schema); boolean found = false; for (final IndexFieldHandler<SimpleFeature, ? extends CommonIndexValue, Object> handler : handlers) { found |= ((handler instanceof FeatureTimeRangeHandler) && ((((FeatureTimeRangeHandler) handler).toIndexValue( newFeature).toNumericData().getMin() - time1.getTime()) < 0.001) && ((((FeatureTimeRangeHandler) handler) .toIndexValue( newFeature) .toNumericData() .getMax() - time2.getTime()) < 0.001)); } assertTrue(found); } @Test public void testCRSProjecttioin() { final SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder(); typeBuilder.setName("test"); typeBuilder.setCRS(GeoWaveGTDataStore.DEFAULT_CRS); // <- Coordinate // reference // add attributes in order typeBuilder.add( "geom", Point.class); typeBuilder.add( "name", String.class); typeBuilder.add( "count", Long.class); // build the type final SimpleFeatureBuilder builder = new SimpleFeatureBuilder( typeBuilder.buildFeatureType()); final AvroFeatureDataAdapter dataAdapter = new AvroFeatureDataAdapter( builder.getFeatureType(), new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final AvroFeatureDataAdapter dataAdapterCopy = new AvroFeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( dataAdapterCopy.getFeatureType().getCoordinateReferenceSystem().getCoordinateSystem(), GeoWaveGTDataStore.DEFAULT_CRS.getCoordinateSystem()); } }