/* Copyright (c) 2013-2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Gabriel Roldan (Boundless) - initial implementation
*/
package org.locationtech.geogig.geotools.data;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.junit.Test;
import org.locationtech.geogig.api.NodeRef;
import org.locationtech.geogig.api.plumbing.LsTreeOp;
import org.locationtech.geogig.api.plumbing.LsTreeOp.Strategy;
import org.locationtech.geogig.api.porcelain.CommitOp;
import org.locationtech.geogig.test.integration.RepositoryTestCase;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.identity.FeatureId;
import org.opengis.filter.identity.ResourceId;
import org.opengis.filter.sort.SortBy;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.vividsolutions.jts.geom.Polygon;
public class GeoGigFeatureSourceTest extends RepositoryTestCase {
private static final FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
private GeoGigDataStore dataStore;
private SimpleFeatureSource pointsSource;
private SimpleFeatureSource linesSource;
@Override
protected void setUpInternal() throws Exception {
dataStore = new GeoGigDataStore(geogig);
dataStore.createSchema(super.pointsType);
dataStore.createSchema(super.linesType);
insertAndAdd(points1, points2, points3, lines1, lines2, lines3);
geogig.command(CommitOp.class).setAuthor("yo", "yo@test.com")
.setCommitter("me", "me@test.com").setMessage("initial import").call();
pointsSource = dataStore.getFeatureSource(pointsTypeName);
linesSource = dataStore.getFeatureSource(linesTypeName);
}
@Override
protected void tearDownInternal() throws Exception {
dataStore.dispose();
dataStore = null;
pointsSource = null;
linesSource = null;
}
@Test
public void testGetName() {
assertEquals(pointsName, pointsSource.getName().getLocalPart());
assertEquals(linesName, linesSource.getName().getLocalPart());
}
@Test
public void testGetInfo() {
assertNotNull(pointsSource.getInfo());
assertNotNull(pointsSource.getInfo().getBounds());
assertNotNull(pointsSource.getInfo().getCRS());
assertEquals(pointsName, pointsSource.getInfo().getName());
assertNotNull(linesSource.getInfo());
assertNotNull(linesSource.getInfo().getBounds());
assertNotNull(linesSource.getInfo().getCRS());
assertEquals(linesName, linesSource.getInfo().getName());
}
@Test
public void testGetDataStore() {
assertSame(dataStore, pointsSource.getDataStore());
assertSame(dataStore, linesSource.getDataStore());
}
@Test
public void testGetQueryCapabilities() {
assertNotNull(pointsSource.getQueryCapabilities());
assertFalse(pointsSource.getQueryCapabilities().isJoiningSupported());
assertTrue(pointsSource.getQueryCapabilities().isOffsetSupported());
assertTrue(pointsSource.getQueryCapabilities().isReliableFIDSupported());
// TODO: add this ability back
// assertTrue(pointsSource.getQueryCapabilities().isUseProvidedFIDSupported());
SortBy[] sortAttributes = { SortBy.NATURAL_ORDER };
assertTrue(pointsSource.getQueryCapabilities().supportsSorting(sortAttributes));
}
@Test
public void testGetSchema() {
assertEquals(pointsType, pointsSource.getSchema());
assertEquals(linesType, linesSource.getSchema());
}
@Test
public void testGetBounds() throws IOException {
ReferencedEnvelope expected;
ReferencedEnvelope bounds;
bounds = pointsSource.getBounds();
assertNotNull(bounds);
expected = boundsOf(points1, points2, points3);
assertEquals(expected, bounds);
bounds = linesSource.getBounds();
assertNotNull(bounds);
expected = boundsOf(lines1, lines2, lines3);
assertEquals(expected, bounds);
}
@Test
public void testGetBoundsQuery() throws Exception {
ReferencedEnvelope bounds;
Filter filter;
filter = ff.id(Collections.singleton(ff.featureId(RepositoryTestCase.idP2)));
bounds = pointsSource.getBounds(new Query(pointsName, filter));
assertEquals(boundsOf(points2), bounds);
ReferencedEnvelope queryBounds = boundsOf(points1, points2);
Polygon geometry = JTS.toGeometry(queryBounds);
filter = ff.intersects(ff.property(pointsType.getGeometryDescriptor().getLocalName()),
ff.literal(geometry));
bounds = pointsSource.getBounds(new Query(pointsName, filter));
assertEquals(boundsOf(points1, points2), bounds);
ReferencedEnvelope transformedQueryBounds;
CoordinateReferenceSystem queryCrs = CRS.decode("EPSG:3857");
transformedQueryBounds = queryBounds.transform(queryCrs, true);
geometry = JTS.toGeometry(transformedQueryBounds);
geometry.setUserData(queryCrs);
filter = ff.intersects(ff.property(pointsType.getGeometryDescriptor().getLocalName()),
ff.literal(geometry));
bounds = pointsSource.getBounds(new Query(pointsName, filter));
assertEquals(boundsOf(points1, points2), bounds);
filter = ECQL.toFilter("sp = 'StringProp2_3' OR ip = 2000");
bounds = linesSource.getBounds(new Query(linesName, filter));
assertEquals(boundsOf(lines3, lines2), bounds);
}
@Test
public void testGetCount() throws Exception {
assertEquals(3, pointsSource.getCount(Query.ALL));
assertEquals(3, linesSource.getCount(Query.ALL));
Filter filter;
filter = ff.id(Collections.singleton(ff.featureId(RepositoryTestCase.idP2)));
assertEquals(1, pointsSource.getCount(new Query(pointsName, filter)));
ReferencedEnvelope queryBounds = boundsOf(points1, points2);
Polygon geometry = JTS.toGeometry(queryBounds);
filter = ff.intersects(ff.property(pointsType.getGeometryDescriptor().getLocalName()),
ff.literal(geometry));
assertEquals(2, pointsSource.getCount(new Query(pointsName, filter)));
ReferencedEnvelope transformedQueryBounds;
CoordinateReferenceSystem queryCrs = CRS.decode("EPSG:3857");
transformedQueryBounds = queryBounds.transform(queryCrs, true);
geometry = JTS.toGeometry(transformedQueryBounds);
geometry.setUserData(queryCrs);
filter = ff.intersects(ff.property(pointsType.getGeometryDescriptor().getLocalName()),
ff.literal(geometry));
assertEquals(2, pointsSource.getCount(new Query(pointsName, filter)));
filter = ECQL.toFilter("sp = 'StringProp2_3' OR ip = 2000");
assertEquals(2, linesSource.getCount(new Query(linesName, filter)));
}
@Test
public void testGetFeatures() throws Exception {
SimpleFeatureCollection collection;
Set<List<Object>> actual;
Set<List<Object>> expected;
collection = pointsSource.getFeatures();
assertEquals(pointsType, collection.getSchema());
actual = Sets.newHashSet();
for (Feature f : toList(collection)) {
SimpleFeature sf = (SimpleFeature) f;
actual.add(sf.getAttributes());
}
expected = ImmutableSet.of(((SimpleFeature) points1).getAttributes(),
((SimpleFeature) points2).getAttributes(),
((SimpleFeature) points3).getAttributes());
assertEquals(expected, actual);
collection = linesSource.getFeatures();
assertEquals(linesType, collection.getSchema());
actual = Sets.newHashSet();
for (Feature f : toList(collection)) {
actual.add(((SimpleFeature) f).getAttributes());
}
expected = ImmutableSet.of(((SimpleFeature) lines1).getAttributes(),
((SimpleFeature) lines2).getAttributes(), ((SimpleFeature) lines3).getAttributes());
assertEquals(expected, actual);
}
@Test
public void testGetFeaturesFilter() throws Exception {
SimpleFeatureCollection collection;
Set<List<Object>> actual;
Set<List<Object>> expected;
Filter filter;
filter = ff.id(Collections.singleton(ff.featureId(RepositoryTestCase.idP2)));
collection = pointsSource.getFeatures(new Query(pointsName, filter));
actual = Sets.newHashSet();
for (SimpleFeature f : toList(collection)) {
actual.add(f.getAttributes());
}
expected = Collections.singleton(((SimpleFeature) points2).getAttributes());
assertEquals(expected, actual);
ReferencedEnvelope queryBounds = boundsOf(points1, points2);
Polygon geometry = JTS.toGeometry(queryBounds);
filter = ff.intersects(ff.property(pointsType.getGeometryDescriptor().getLocalName()),
ff.literal(geometry));
collection = pointsSource.getFeatures(new Query(pointsName, filter));
actual = Sets.newHashSet();
for (SimpleFeature f : toList(collection)) {
actual.add(f.getAttributes());
}
expected = ImmutableSet.of(((SimpleFeature) points1).getAttributes(),
((SimpleFeature) points2).getAttributes());
assertEquals(expected, actual);
ReferencedEnvelope transformedQueryBounds;
CoordinateReferenceSystem queryCrs = CRS.decode("EPSG:3857");
transformedQueryBounds = queryBounds.transform(queryCrs, true);
geometry = JTS.toGeometry(transformedQueryBounds);
geometry.setUserData(queryCrs);
filter = ff.intersects(ff.property(pointsType.getGeometryDescriptor().getLocalName()),
ff.literal(geometry));
collection = pointsSource.getFeatures(new Query(pointsName, filter));
actual = Sets.newHashSet();
for (SimpleFeature f : toList(collection)) {
actual.add(f.getAttributes());
}
expected = ImmutableSet.of(((SimpleFeature) points1).getAttributes(),
((SimpleFeature) points2).getAttributes());
assertEquals(expected.size(), actual.size());
assertEquals(expected, actual);
filter = ECQL.toFilter("sp = 'StringProp2_3' OR ip = 2000");
collection = linesSource.getFeatures(new Query(linesName, filter));
actual = Sets.newHashSet();
for (SimpleFeature f : toList(collection)) {
actual.add(f.getAttributes());
}
expected = ImmutableSet.of(((SimpleFeature) lines2).getAttributes(),
((SimpleFeature) lines3).getAttributes());
assertEquals(expected, actual);
}
@Test
public void testFeatureIdsAreVersioned() throws IOException {
SimpleFeatureCollection collection = pointsSource.getFeatures(Query.ALL);
SimpleFeatureIterator features = collection.features();
Set<FeatureId> ids = Sets.newHashSet();
try {
while (features.hasNext()) {
SimpleFeature next = features.next();
FeatureId identifier = next.getIdentifier();
ids.add(identifier);
}
} finally {
features.close();
}
List<NodeRef> refs = toList(repo.command(LsTreeOp.class).setReference(pointsName)
.setStrategy(Strategy.FEATURES_ONLY).call());
assertEquals(3, refs.size());
Map<String, NodeRef> expected = new HashMap<String, NodeRef>();
for (NodeRef ref : refs) {
expected.put(ref.path(), ref);
}
for (FeatureId id : ids) {
assertFalse("ResourceId is a query object", id instanceof ResourceId);
assertNotNull(id.getID());
assertNotNull(id + " has no featureVersion set", id.getFeatureVersion());
NodeRef ref = expected.get(id.getID());
assertNotNull(ref);
assertEquals(ref.objectId().toString(), id.getFeatureVersion());
}
}
private List<SimpleFeature> toList(SimpleFeatureCollection collection) {
List<SimpleFeature> features = Lists.newArrayList();
SimpleFeatureIterator iterator = collection.features();
try {
while (iterator.hasNext()) {
features.add(iterator.next());
}
} finally {
iterator.close();
}
return features;
}
}