/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010, 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.geotoolkit.data.iterator;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import org.apache.sis.referencing.CommonCRS;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import org.apache.sis.storage.DataStoreException;
import org.geotoolkit.data.FeatureCollection;
import org.geotoolkit.data.FeatureIterator;
import org.geotoolkit.data.FeatureReader;
import org.geotoolkit.data.FeatureStoreUtilities;
import org.geotoolkit.data.FeatureWriter;
import org.geotoolkit.data.memory.GenericCachedFeatureIterator;
import org.geotoolkit.data.memory.GenericEmptyFeatureIterator;
import org.geotoolkit.data.memory.GenericFilterFeatureIterator;
import org.geotoolkit.data.memory.GenericMaxFeatureIterator;
import org.geotoolkit.data.memory.GenericModifyFeatureIterator;
import org.geotoolkit.data.memory.GenericSortByFeatureIterator;
import org.geotoolkit.data.memory.GenericStartIndexFeatureIterator;
import org.geotoolkit.data.memory.GenericWrapFeatureIterator;
import org.geotoolkit.data.query.Query;
import org.geotoolkit.data.query.QueryBuilder;
import org.geotoolkit.factory.FactoryFinder;
import org.geotoolkit.factory.Hints;
import org.geotoolkit.factory.HintsPending;
import org.geotoolkit.util.NamesExt;
import org.geotoolkit.geometry.jts.JTS;
import org.geotoolkit.geometry.jts.transform.GeometryScaleTransformer;
import org.geotoolkit.geometry.jts.transform.GeometryTransformer;
import org.junit.Ignore;
import org.junit.Test;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.sort.SortBy;
import org.opengis.filter.sort.SortOrder;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.util.FactoryException;
import org.opengis.util.GenericName;
import static junit.framework.Assert.*;
import org.apache.sis.feature.FeatureTypeExt;
import org.apache.sis.feature.ReprojectFeatureType;
import org.apache.sis.feature.TransformFeatureType;
import org.apache.sis.feature.ViewFeatureType;
import org.apache.sis.feature.builder.AttributeRole;
import org.apache.sis.feature.builder.FeatureTypeBuilder;
import org.apache.sis.referencing.CRS;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.apache.sis.internal.feature.AttributeConvention;
import org.geotoolkit.data.memory.GenericDecoratedFeatureIterator;
/**
* Tests of the different iterators.
*
* @author Johann Sorel (Geomatys)
*/
public class GenericIteratorTest extends org.geotoolkit.test.TestBase {
private static final double DELTA = 0.000001d;
private static final FilterFactory FF = FactoryFinder.getFilterFactory(null);
private static final GeometryFactory GF = new GeometryFactory();
private static final Integer COMPLEX_ID_1 = 11;
private static final Integer COMPLEX_ID_2 = 12;
private static final GenericName NAME = NamesExt.create("http://test.com", "TestSchema");
private final FeatureCollection collection;
private final FeatureCollection collectionComplex;
private final GenericName name;
private final FeatureType originalType;
private final FeatureType reducedType;
private final FeatureType reprojectedType;
private final Integer id1;
private final Integer id2;
private final Integer id3;
private final Feature sf1;
private final Feature sf2;
private final Feature sf3;
public GenericIteratorTest() throws NoSuchAuthorityCodeException, FactoryException{
FeatureTypeBuilder builder = new FeatureTypeBuilder();
name = NamesExt.create("http://test.com", "TestSchema");
builder = new FeatureTypeBuilder();
builder.setName(name);
builder.addAttribute(Integer.class).setName(AttributeConvention.IDENTIFIER_PROPERTY);
builder.addAttribute(Point.class).setName("att_geom").setCRS(CommonCRS.WGS84.normalizedGeographic());
builder.addAttribute(String.class).setName("att_string");
builder.addAttribute(Double.class).setName("att_double");
originalType = builder.build();
//build a reduced type for retype iterator
builder = new FeatureTypeBuilder();
builder.setName(name);
builder.addAttribute(Integer.class).setName(AttributeConvention.IDENTIFIER_PROPERTY);
builder.addAttribute(Double.class).setName("att_double");
reducedType = builder.build();
//build a reprojected type for reproject iterator
builder = new FeatureTypeBuilder();
builder.setName(name);
builder.addAttribute(Integer.class).setName(AttributeConvention.IDENTIFIER_PROPERTY);
builder.addAttribute(Point.class).setName("att_geom").setCRS(CRS.forCode("EPSG:4326"));
builder.addAttribute(String.class).setName("att_string");
builder.addAttribute(Double.class).setName("att_double");
reprojectedType = builder.build();
collection = FeatureStoreUtilities.collection("id", originalType);
id1 = 0;
sf1 = originalType.newInstance();
sf1.setPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString(), id1);
sf1.setPropertyValue("att_geom", GF.createPoint(new Coordinate(3, 0)));
sf1.setPropertyValue("att_string", "bbb");
sf1.setPropertyValue("att_double", 3d);
collection.add(sf1);
id2 = 1;
sf2 = originalType.newInstance();
sf2.setPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString(), id2);
sf2.setPropertyValue("att_geom", GF.createPoint(new Coordinate(1, 0)));
sf2.setPropertyValue("att_string", "ccc");
sf2.setPropertyValue("att_double", 1d);
collection.add(sf2);
id3 = 2;
sf3 = originalType.newInstance();
sf3.setPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString(), id3);
sf3.setPropertyValue("att_geom", GF.createPoint(new Coordinate(2, 0)));
sf3.setPropertyValue("att_string", "aaa");
sf3.setPropertyValue("att_double", 2d);
collection.add(sf3);
builder = new FeatureTypeBuilder();
builder.setName(name);
builder.addAttribute(Integer.class).setName(AttributeConvention.IDENTIFIER_PROPERTY);
builder.addAttribute(String.class).setName("att_string").setMinimumOccurs(0).setMaximumOccurs(1);
builder.addAttribute(Double.class).setName("att_double").setMinimumOccurs(0).setMaximumOccurs(1);
FeatureType ct = builder.build();
collectionComplex = FeatureStoreUtilities.collection("cid", ct);
final Feature f1 = ct.newInstance();
f1.setPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString(), COMPLEX_ID_1);
f1.setPropertyValue("att_string","aaaa");
f1.setPropertyValue("att_double",12.0);
collectionComplex.add(f1);
final Feature f2 = ct.newInstance();
f2.setPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString(), COMPLEX_ID_2);
f2.setPropertyValue("att_string","bbbb");
f2.setPropertyValue("att_double",7.0);
collectionComplex.add(f2);
}
@Test
public void testEmptyIterator(){
final FeatureIterator iterator = GenericEmptyFeatureIterator.createIterator();
assertFalse(iterator.hasNext());
try{
iterator.next();
fail("Next on empty iterator should have raised a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
try{
iterator.remove();
fail("Remove should have raise an error.");
}catch(Exception ex){
//ok
}
iterator.close();
}
@Test
public void testEmptyReader(){
FeatureCollection collection = buildSimpleFeatureCollection();
final FeatureReader iterator = GenericEmptyFeatureIterator.createReader(collection.getFeatureType());
assertEquals(iterator.getFeatureType(), collection.getFeatureType());
assertFalse(iterator.hasNext());
try{
iterator.next();
fail("Next on empty iterator should have raised a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
try{
iterator.remove();
fail("Remove should have raise an error.");
}catch(Exception ex){
//ok
}
iterator.close();
}
@Test
public void testEmptyWriter(){
FeatureCollection collection = buildSimpleFeatureCollection();
final FeatureWriter iterator = GenericEmptyFeatureIterator.createWriter(collection.getFeatureType());
assertEquals(iterator.getFeatureType(), collection.getFeatureType());
assertFalse(iterator.hasNext());
try{
iterator.next();
fail("Next on empty iterator should have raised a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
try{
iterator.remove();
fail("Remove should have raise an error.");
}catch(Exception ex){
//ok
}
iterator.close();
}
@Test
@Ignore("See #GEOTK-489")
public void testCacheIterator(){
FeatureCollection collection = buildSimpleFeatureCollection();
FeatureIterator ite = GenericCachedFeatureIterator.wrap(collection.iterator(), 1);
assertEquals(3, FeatureStoreUtilities.calculateCount(ite));
ite = GenericCachedFeatureIterator.wrap(collection.iterator(), 1);
int mask = 0;
Feature f;
while(ite.hasNext()){
f = ite.next();
final Object id = f.getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString());
if(id1.equals(id)){
mask |= 1<<0;
}else if(id2.equals(id)){
mask |= 1<<1;
}else if(id3.equals(id)){
mask |= 1<<2;
}
}
ite.close();
if(mask!=7){
fail("missing features in iterations");
}
}
@Test
public void testFilterIterator(){
FeatureCollection collection = buildSimpleFeatureCollection();
FeatureIterator ite = GenericFilterFeatureIterator.wrap(collection.iterator(), Filter.INCLUDE);
assertEquals(3, FeatureStoreUtilities.calculateCount(ite));
ite = GenericFilterFeatureIterator.wrap(collection.iterator(), Filter.EXCLUDE);
assertEquals(0, FeatureStoreUtilities.calculateCount(ite));
ite = GenericFilterFeatureIterator.wrap(collection.iterator(), FF.equals(FF.literal("aaa"), FF.property("att_string")));
assertEquals(1, FeatureStoreUtilities.calculateCount(ite));
ite = GenericFilterFeatureIterator.wrap(collection.iterator(), FF.equals(FF.literal("aaa"), FF.property("att_string")));
assertEquals(id3, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//check has next do not iterate
ite = GenericFilterFeatureIterator.wrap(collection.iterator(), Filter.INCLUDE);
testIterationOnNext(ite, 3);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
ite = GenericFilterFeatureIterator.wrap(checkIte, Filter.INCLUDE);
while(ite.hasNext()) ite.next();
ite.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testMaxIterator(){
FeatureCollection collection = buildSimpleFeatureCollection();
FeatureIterator ite = GenericMaxFeatureIterator.wrap(collection.iterator(), 10);
assertEquals(3, FeatureStoreUtilities.calculateCount(ite));
ite = GenericMaxFeatureIterator.wrap(collection.iterator(), 2);
assertEquals(2, FeatureStoreUtilities.calculateCount(ite));
ite = GenericMaxFeatureIterator.wrap(collection.iterator(), 1);
assertEquals(id1, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//check has next do not iterate
ite = GenericMaxFeatureIterator.wrap(collection.iterator(), 10);
testIterationOnNext(ite, 3);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
ite = GenericMaxFeatureIterator.wrap(checkIte, 10);
while(ite.hasNext()) ite.next();
ite.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testModifyIterator(){
FeatureCollection collection = buildSimpleFeatureCollection();
FeatureType originalType = collection.getFeatureType();
Filter filter = Filter.INCLUDE;
Map<String,Object> values = new HashMap<>();
values.put("att_string", "toto");
FeatureIterator ite = GenericModifyFeatureIterator.wrap(collection.iterator(), filter, values);
assertEquals(3, FeatureStoreUtilities.calculateCount(ite));
ite = GenericModifyFeatureIterator.wrap(collection.iterator(), filter, values);
while(ite.hasNext()){
assertTrue(ite.next().getProperty("att_string").getValue().equals("toto"));
}
filter = FF.equals(FF.literal("aaa"), FF.property("att_string"));
ite = GenericModifyFeatureIterator.wrap(collection.iterator(), filter, values);
assertEquals(3, FeatureStoreUtilities.calculateCount(ite));
ite = GenericModifyFeatureIterator.wrap(collection.iterator(), filter, values);
while(ite.hasNext()){
Feature f = ite.next();
if (f.getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()).equals(id3)) {
assertTrue(f.getProperty("att_string").getValue().equals("toto"));
}else{
assertFalse(f.getProperty("att_string").getValue().equals("toto"));
}
}
ite = GenericModifyFeatureIterator.wrap(collection.iterator(), filter, values);
ite.next();
ite.next();
ite.next();
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//check has next do not iterate
ite = GenericModifyFeatureIterator.wrap(collection.iterator(), filter, values);
testIterationOnNext(ite, 3);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
ite = GenericModifyFeatureIterator.wrap(checkIte, filter, values);
while(ite.hasNext()) ite.next();
ite.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testReprojectFeatureIterator() throws DataStoreException, FactoryException{
QueryBuilder qb = new QueryBuilder();
qb.setTypeName(collection.getFeatureType().getName());
Query query = qb.buildQuery();
FeatureReader reader = collection.getSession().getFeatureStore().getFeatureReader(query);
final CoordinateReferenceSystem targetCRS = CommonCRS.WGS84.geographic();
FeatureReader retyped = GenericDecoratedFeatureIterator.wrap(reader, new ReprojectFeatureType(reader.getFeatureType(), targetCRS), new Hints());
int mask = 0;
Feature f;
while(retyped.hasNext()){
f = retyped.next();
final Object id = f.getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString());
assertEquals(4, f.getType().getProperties(true).size());
assertEquals(targetCRS,JTS.findCoordinateReferenceSystem((Geometry)f.getProperty("att_geom").getValue()));
if(id1.equals(id)){
mask |= 1<<0;
assertEquals(GF.createPoint(new Coordinate(0, 3)).toString(), f.getProperty("att_geom").getValue().toString());
}else if(id2.equals(id)){
mask |= 1<<1;
assertEquals(GF.createPoint(new Coordinate(0, 1)).toString(), f.getProperty("att_geom").getValue().toString());
}else if(id3.equals(id)){
mask |= 1<<2;
assertEquals(GF.createPoint(new Coordinate(0, 2)).toString(), f.getProperty("att_geom").getValue().toString());
}
}
if(mask!=7){
fail("missing features in iterations");
}
//check has next do not iterate
reader = collection.getSession().getFeatureStore().getFeatureReader(query);
retyped = GenericDecoratedFeatureIterator.wrap(reader, new ReprojectFeatureType(reader.getFeatureType(), CommonCRS.WGS84.geographic()), new Hints());
testIterationOnNext(retyped, 3);
//check sub iterator is properly closed
reader = collection.getSession().getFeatureStore().getFeatureReader(query);
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(reader);
assertFalse(checkIte.isClosed());
retyped = GenericDecoratedFeatureIterator.wrap(checkIte, new ReprojectFeatureType(checkIte.getFeatureType(), CommonCRS.WGS84.geographic()), new Hints());
while(retyped.hasNext()) retyped.next();
retyped.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testTransformFeatureIterator() throws DataStoreException{
FeatureType originalType = buildOriginalFT();
final FeatureTypeBuilder builder = new FeatureTypeBuilder();
final GenericName name = NamesExt.create("http://test.com", "TestSchema");
builder.setName(name);
builder.addAttribute(String.class).setName(AttributeConvention.IDENTIFIER_PROPERTY);
builder.addAttribute(LineString.class).setName("att_geom").setCRS(CommonCRS.WGS84.normalizedGeographic()).addRole(AttributeRole.DEFAULT_GEOMETRY);
final FeatureType type = builder.build();
final LineString geom = GF.createLineString(
new Coordinate[]{
new Coordinate(0, 0),
new Coordinate(15, 12), //dx 15 , dy 12
new Coordinate(8, 28), //dx 7 , dy 16
new Coordinate(9, 31), //dx 1 , dy 3
new Coordinate(-5, 11), //dx 14 , dy 20
new Coordinate(-1, 9) //dx 4 , dy 2
});
final FeatureCollection collection = FeatureStoreUtilities.collection("id", type);
Feature sf = type.newInstance();
sf.setPropertyValue("att_geom", geom);
collection.add(sf);
//get the reader -------------------------------------------------------
QueryBuilder qb = new QueryBuilder();
qb.setTypeName(originalType.getName());
Query query = qb.buildQuery();
FeatureReader reader = collection.getSession().getFeatureStore().getFeatureReader(query);
//create the decimate reader -------------------------------------------
final Hints hints = new Hints();
hints.put(HintsPending.FEATURE_DETACHED, Boolean.TRUE);
GeometryTransformer decim = new GeometryScaleTransformer(10, 10);
final TransformFeatureType ttype = new TransformFeatureType(reader.getFeatureType(), decim);
FeatureReader retyped = GenericDecoratedFeatureIterator.wrap(reader, ttype, hints);
assertTrue(retyped.hasNext());
LineString decimated = (LineString) retyped.next().getPropertyValue(AttributeConvention.GEOMETRY_PROPERTY.toString());
assertFalse(retyped.hasNext());
retyped.close();
assertEquals(4, decimated.getNumPoints());
assertEquals(geom.getGeometryN(0).getCoordinate(), decimated.getGeometryN(0).getCoordinate());
assertEquals(geom.getGeometryN(1).getCoordinate(), decimated.getGeometryN(1).getCoordinate());
assertEquals(geom.getGeometryN(2).getCoordinate(), decimated.getGeometryN(2).getCoordinate());
assertEquals(geom.getGeometryN(4).getCoordinate(), decimated.getGeometryN(3).getCoordinate());
//check the original geometry has not been modified
reader = collection.getSession().getFeatureStore().getFeatureReader(query);
assertTrue(reader.hasNext());
LineString notDecimated = (LineString) reader.next().getPropertyValue(AttributeConvention.GEOMETRY_PROPERTY.toString());
assertEquals(6, notDecimated.getNumPoints());
assertFalse(reader.hasNext());
reader.close();
// same test but with reuse hint ---------------------------------------
reader = collection.getSession().getFeatureStore().getFeatureReader(query);
hints.put(HintsPending.FEATURE_DETACHED, Boolean.FALSE);
decim = new GeometryScaleTransformer(10, 10);
retyped = GenericDecoratedFeatureIterator.wrap(reader,new TransformFeatureType(reader.getFeatureType(), decim), hints);
assertTrue(retyped.hasNext());
decimated = (LineString) retyped.next().getPropertyValue(AttributeConvention.GEOMETRY_PROPERTY.toString());
assertFalse(retyped.hasNext());
retyped.close();
assertEquals(4, decimated.getNumPoints());
assertEquals(geom.getGeometryN(0).getCoordinate(), decimated.getGeometryN(0).getCoordinate());
assertEquals(geom.getGeometryN(1).getCoordinate(), decimated.getGeometryN(1).getCoordinate());
assertEquals(geom.getGeometryN(2).getCoordinate(), decimated.getGeometryN(2).getCoordinate());
assertEquals(geom.getGeometryN(4).getCoordinate(), decimated.getGeometryN(3).getCoordinate());
//check the original geometry has not been modified
reader = collection.getSession().getFeatureStore().getFeatureReader(query);
assertTrue(reader.hasNext());
notDecimated = (LineString) reader.next().getPropertyValue(AttributeConvention.GEOMETRY_PROPERTY.toString());
assertEquals(6, notDecimated.getNumPoints());
assertFalse(reader.hasNext());
reader.close();
}
@Test
public void testRetypeFeatureIterator() throws DataStoreException{
final FeatureCollection collection = buildSimpleFeatureCollection();
final FeatureType reducedType = new ViewFeatureType(collection.getFeatureType(), AttributeConvention.IDENTIFIER_PROPERTY.toString(),"att_double");
final QueryBuilder qb = new QueryBuilder();
qb.setTypeName(collection.getFeatureType().getName());
final Query query = qb.buildQuery();
FeatureReader reader = collection.getSession().getFeatureStore().getFeatureReader(query);
FeatureReader retyped = GenericDecoratedFeatureIterator.wrap(reader, (ViewFeatureType) reducedType,null);
assertEquals(reducedType,retyped.getFeatureType());
int mask = 0;
Feature f;
while(retyped.hasNext()){
f = retyped.next();
final Object id = f.getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString());
assertEquals(2, f.getType().getProperties(true).size());
if(id1.equals(id)){
mask |= 1<<0;
assertEquals(3d, (Double)f.getProperty("att_double").getValue(), DELTA);
}else if(id2.equals(id)){
mask |= 1<<1;
assertEquals(1d, (Double)f.getProperty("att_double").getValue(), DELTA);
}else if(id3.equals(id)){
mask |= 1<<2;
assertEquals(2d, (Double)f.getProperty("att_double").getValue(), DELTA);
}
}
assertEquals("missing features in iterations", 7, mask);
//check has next do not iterate
reader = collection.getSession().getFeatureStore().getFeatureReader(query);
retyped = GenericDecoratedFeatureIterator.wrap(reader, (ViewFeatureType) reducedType,null);
testIterationOnNext(retyped, 3);
//check sub iterator is properly closed
reader = collection.getSession().getFeatureStore().getFeatureReader(query);
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(reader);
assertFalse(checkIte.isClosed());
retyped = GenericDecoratedFeatureIterator.wrap(checkIte, (ViewFeatureType) reducedType,null);
while(retyped.hasNext()) retyped.next();
retyped.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testSortByIterator(){
SortBy[] sorts = new SortBy[]{
FF.sort("att_string", SortOrder.ASCENDING)
};
FeatureCollection collection = buildSimpleFeatureCollection();
FeatureIterator ite = GenericSortByFeatureIterator.wrap(collection.iterator(), sorts);
assertEquals(3, FeatureStoreUtilities.calculateCount(ite));
ite = GenericSortByFeatureIterator.wrap(collection.iterator(), sorts);
assertEquals(id3, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
assertEquals(id1, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
assertEquals(id2, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//check has next do not iterate
ite = GenericSortByFeatureIterator.wrap(collection.iterator(), sorts);
testIterationOnNext(ite, 3);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
ite = GenericSortByFeatureIterator.wrap(checkIte, sorts);
while(ite.hasNext()) ite.next();
ite.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testSortByIteratorOnComplex(){
FeatureCollection collectionComplex = buildComplexFeatureCollection();
FeatureCollection collection = buildSimpleFeatureCollection();
//test string sort -----------------------------------------------------
SortBy[] sorts = new SortBy[]{
FF.sort("att_string", SortOrder.DESCENDING)
};
FeatureIterator ite = GenericSortByFeatureIterator.wrap(collectionComplex.iterator(), sorts);
assertEquals(2, FeatureStoreUtilities.calculateCount(ite));
ite = GenericSortByFeatureIterator.wrap(collectionComplex.iterator(), sorts);
assertEquals(COMPLEX_ID_2, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
assertEquals(COMPLEX_ID_1, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//test string sort -----------------------------------------------------
sorts = new SortBy[]{
FF.sort("att_double", SortOrder.DESCENDING)
};
ite = GenericSortByFeatureIterator.wrap(collectionComplex.iterator(), sorts);
assertEquals(2, FeatureStoreUtilities.calculateCount(ite));
ite = GenericSortByFeatureIterator.wrap(collectionComplex.iterator(), sorts);
assertEquals(COMPLEX_ID_1, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
assertEquals(COMPLEX_ID_2, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//test double sort -----------------------------------------------------
sorts = new SortBy[]{
FF.sort("att_double", SortOrder.ASCENDING)
};
ite = GenericSortByFeatureIterator.wrap(collectionComplex.iterator(), sorts);
assertEquals(2, FeatureStoreUtilities.calculateCount(ite));
ite = GenericSortByFeatureIterator.wrap(collectionComplex.iterator(), sorts);
assertEquals(COMPLEX_ID_2, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
assertEquals(COMPLEX_ID_1, ite.next().getPropertyValue(AttributeConvention.IDENTIFIER_PROPERTY.toString()));
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//check has next do not iterate
ite = GenericSortByFeatureIterator.wrap(collectionComplex.iterator(), sorts);
testIterationOnNext(ite, 2);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
ite = GenericSortByFeatureIterator.wrap(checkIte, sorts);
while(ite.hasNext()) ite.next();
ite.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testStartIndexIterator(){
FeatureCollection collection = buildSimpleFeatureCollection();
FeatureIterator ite = GenericStartIndexFeatureIterator.wrap(collection.iterator(), 0);
assertEquals(3, FeatureStoreUtilities.calculateCount(ite));
ite = GenericStartIndexFeatureIterator.wrap(collection.iterator(), 1);
assertEquals(2, FeatureStoreUtilities.calculateCount(ite));
ite = GenericStartIndexFeatureIterator.wrap(collection.iterator(), 2);
assertTrue(ite.next() != null);
try{
ite.next();
fail("Should have raise a no such element exception.");
}catch(NoSuchElementException ex){
//ok
}
//check has next do not iterate
ite = GenericStartIndexFeatureIterator.wrap(collection.iterator(), 1);
testIterationOnNext(ite, 2);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
ite = GenericStartIndexFeatureIterator.wrap(checkIte, 1);
while(ite.hasNext()) ite.next();
ite.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testWrapIterator(){
FeatureCollection collection = buildSimpleFeatureCollection();
//check has next do not iterate
FeatureIterator ite = GenericWrapFeatureIterator.wrapToIterator(collection.iterator());
testIterationOnNext(ite, 3);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
ite = GenericWrapFeatureIterator.wrapToIterator(checkIte);
while(ite.hasNext()) ite.next();
ite.close();
assertTrue(checkIte.isClosed());
}
@Test
public void testWrapReader(){
FeatureCollection collection = buildSimpleFeatureCollection();
//check has next do not iterate
FeatureReader reader = GenericWrapFeatureIterator.wrapToReader(collection.iterator(),collection.getFeatureType());
testIterationOnNext(reader, 3);
//check sub iterator is properly closed
CheckCloseFeatureIterator checkIte = new CheckCloseFeatureIterator(collection.iterator());
assertFalse(checkIte.isClosed());
reader = GenericWrapFeatureIterator.wrapToReader(checkIte,collection.getFeatureType());
while(reader.hasNext()) reader.next();
reader.close();
assertTrue(checkIte.isClosed());
}
private FeatureCollection buildComplexFeatureCollection() {
FeatureTypeBuilder builder = new FeatureTypeBuilder();
builder.setName(NAME);
builder.addAttribute(Integer.class).setName("id").addRole(AttributeRole.IDENTIFIER_COMPONENT);
builder.addAttribute(String.class).setName("att_string");
builder.addAttribute(Double.class).setName("att_double");
FeatureType ct = builder.build();
FeatureCollection collectionComplex = FeatureStoreUtilities.collection("cid", ct);
Feature f1 = ct.newInstance();
f1.setPropertyValue("id", COMPLEX_ID_1);
f1.setPropertyValue("att_string", "aaaa");
f1.setPropertyValue("att_double", 12.0);
collectionComplex.add(f1);
Feature f2 = ct.newInstance();
f2.setPropertyValue("id", COMPLEX_ID_2);
f2.setPropertyValue("att_string", "bbbb");
f2.setPropertyValue("att_double", 7.0);
collectionComplex.add(f2);
return collectionComplex;
}
private FeatureCollection buildSimpleFeatureCollection() {
FeatureType originalType = buildOriginalFT();
FeatureCollection collection = FeatureStoreUtilities.collection("id", originalType);
Feature sf1 = originalType.newInstance();
sf1.setPropertyValue("id", 0);
sf1.setPropertyValue("att_geom", GF.createPoint(new Coordinate(3, 0)));
sf1.setPropertyValue("att_string", "bbb");
sf1.setPropertyValue("att_double", 3d);
collection.add(sf1);
Feature sf2 = originalType.newInstance();
sf2.setPropertyValue("id", 1);
sf2.setPropertyValue("att_geom", GF.createPoint(new Coordinate(1, 0)));
sf2.setPropertyValue("att_string", "ccc");
sf2.setPropertyValue("att_double", 1d);
collection.add(sf2);
Feature sf3 = originalType.newInstance();
sf3.setPropertyValue("id", 2);
sf3.setPropertyValue("att_geom", GF.createPoint(new Coordinate(2, 0)));
sf3.setPropertyValue("att_string", "aaa");
sf3.setPropertyValue("att_double", 2d);
collection.add(sf3);
return collection;
}
private FeatureType buildOriginalFT() {
final FeatureTypeBuilder builder = new FeatureTypeBuilder();
builder.setName(NAME);
builder.addAttribute(Integer.class).setName("id").addRole(AttributeRole.IDENTIFIER_COMPONENT);
builder.addAttribute(Point.class).setName("att_geom").setCRS(CommonCRS.WGS84.normalizedGeographic()).addRole(AttributeRole.DEFAULT_GEOMETRY);
builder.addAttribute(String.class).setName("att_string");
builder.addAttribute(Double.class).setName("att_double");
return builder.build();
}
private void testIterationOnNext(final FeatureIterator ite, final int size){
//check that there is no iteration on hasnext()
for(int i=0; i<size+10; i++){
if(!ite.hasNext()){
fail("hasNext() has changed to false, suspicious iteration on hasNext call.");
}
}
//check iteration on next, whithout calling hasNext()
Feature last = ite.next();
for(int i=1;i<size;i++){
Feature current = ite.next();
assertFalse(last.equals(current));
last = current;
}
}
}