package mil.nga.giat.geowave.adapter.vector; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.List; 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.junit.Assert; 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.index.NumericSecondaryIndexConfiguration; import mil.nga.giat.geowave.adapter.vector.index.TemporalSecondaryIndexConfiguration; import mil.nga.giat.geowave.adapter.vector.index.TextSecondaryIndexConfiguration; 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.adapter.vector.utils.SimpleFeatureUserDataConfiguration; import mil.nga.giat.geowave.adapter.vector.utils.SimpleFeatureUserDataConfigurationSet; import mil.nga.giat.geowave.core.geotime.ingest.SpatialDimensionalityTypeProvider; import mil.nga.giat.geowave.core.geotime.store.dimension.GeometryWrapper; 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.data.PersistentValue; 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.SecondaryIndexType; public class FeatureDataAdapterTest { private SimpleFeatureType schema; private SimpleFeature newFeature; private Date time1; private Date time2; GeometryFactory factory = new GeometryFactory( new PrecisionModel( PrecisionModel.FIXED)); @SuppressWarnings("unchecked") @Before public void setup() throws SchemaException, CQLException, ParseException { 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"); 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) }); } @Test public void testDifferentProjection() throws SchemaException { final SimpleFeatureType schema = DataUtilities.createType( "sp.geostuff", "geometry:Geometry:srid=3005,pop:java.lang.Long"); final FeatureDataAdapter dataAdapter = new FeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final CoordinateReferenceSystem crs = dataAdapter.getFeatureType().getCoordinateReferenceSystem(); assertTrue(crs.getIdentifiers().toString().contains( "EPSG:4326")); @SuppressWarnings("unchecked") final SimpleFeature newFeature = 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( newFeature, new SpatialDimensionalityTypeProvider().createPrimaryIndex().getIndexModel()); GeometryWrapper wrapper = null; for (final PersistentValue<?> pv : persistenceEncoding.getCommonData().getValues()) { if (pv.getValue() instanceof GeometryWrapper) { wrapper = (GeometryWrapper) pv.getValue(); } } assertNotNull(wrapper); assertEquals( new Coordinate( -138.0, 44.0), wrapper.getGeometry().getCentroid().getCoordinate()); } @Test public void testSingleTime() { schema.getDescriptor( "when").getUserData().clear(); schema.getDescriptor( "whennot").getUserData().put( "time", Boolean.TRUE); final FeatureDataAdapter dataAdapter = new FeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final FeatureDataAdapter dataAdapterCopy = new FeatureDataAdapter(); 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 FeatureDataAdapter dataAdapter = new FeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final FeatureDataAdapter dataAdapterCopy = new FeatureDataAdapter(); 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 FeatureDataAdapter dataAdapter = new FeatureDataAdapter( 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 FeatureDataAdapter dataAdapter = new FeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final FeatureDataAdapter dataAdapterCopy = new FeatureDataAdapter(); 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 FeatureDataAdapter dataAdapter = new FeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final FeatureDataAdapter dataAdapterCopy = new FeatureDataAdapter(); 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( "http://foo", "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 FeatureDataAdapter dataAdapter = new FeatureDataAdapter( schema, new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final FeatureDataAdapter dataAdapterCopy = new FeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( "http://foo", dataAdapterCopy.getFeatureType().getName().getNamespaceURI()); 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 FeatureDataAdapter dataAdapter = new FeatureDataAdapter( builder.getFeatureType(), new GlobalVisibilityHandler<SimpleFeature, Object>( "default")); final byte[] binary = dataAdapter.toBinary(); final FeatureDataAdapter dataAdapterCopy = new FeatureDataAdapter(); dataAdapterCopy.fromBinary(binary); assertEquals( dataAdapterCopy.getFeatureType().getCoordinateReferenceSystem().getCoordinateSystem(), GeoWaveGTDataStore.DEFAULT_CRS.getCoordinateSystem()); } @Test public void testSecondaryIndicies() throws SchemaException { final SimpleFeatureType sfType = DataUtilities.createType( "stateCapitalData", "location:Geometry," + "city:String," + "state:String," + "since:Date," + "landArea:Double," + "munincipalPop:Integer," + "notes:String"); final List<SimpleFeatureUserDataConfiguration> secondaryIndexConfigs = new ArrayList<>(); secondaryIndexConfigs.add(new NumericSecondaryIndexConfiguration( "landArea", SecondaryIndexType.JOIN)); secondaryIndexConfigs.add(new TextSecondaryIndexConfiguration( "notes", SecondaryIndexType.JOIN)); secondaryIndexConfigs.add(new TemporalSecondaryIndexConfiguration( "since", SecondaryIndexType.JOIN)); final SimpleFeatureUserDataConfigurationSet config = new SimpleFeatureUserDataConfigurationSet( sfType, secondaryIndexConfigs); config.updateType(sfType); final FeatureDataAdapter dataAdapter = new FeatureDataAdapter( sfType); Assert.assertTrue(dataAdapter.getSupportedSecondaryIndices().size() == 3); } }