/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2007-2008, 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.caching.grid.featurecache;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.geotools.caching.CacheOversizedException;
import org.geotools.caching.FeatureCollectingVisitor;
import org.geotools.caching.featurecache.AbstractFeatureCache;
import org.geotools.caching.featurecache.AbstractFeatureCacheTest;
import org.geotools.caching.featurecache.FeatureCache;
import org.geotools.caching.featurecache.FeatureCacheException;
import org.geotools.caching.grid.spatialindex.store.MemoryStorage;
import org.geotools.caching.util.CacheUtil;
import org.geotools.caching.util.Generator;
import org.geotools.data.DataStore;
import org.geotools.data.DefaultQuery;
import org.geotools.data.memory.MemoryDataStore;
import org.geotools.data.memory.MemoryFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.filter.FilterFactoryImpl;
import org.geotools.referencing.crs.DefaultEngineeringCRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
/**
*
*
* @source $URL$
*/
public class GridFeatureCacheTest extends AbstractFeatureCacheTest {
static boolean testEviction_holistic = false;
GridFeatureCache cache;
public static Test suite() {
return new TestSuite(GridFeatureCacheTest.class);
}
@Override
protected AbstractFeatureCache createInstance(int capacity)
throws FeatureCacheException, IOException {
this.cache = new GridFeatureCache((SimpleFeatureStore) ds.getFeatureSource(
dataset.getSchema().getName()), 100, capacity,
MemoryStorage.createInstance());
return this.cache;
}
@Override
public void testEviction() throws IOException, FeatureCacheException {
super.cache = createInstance(numdata / 2);
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
Filter f = Generator.createBboxFilter(new Coordinate(i * 0.1, j * 0.1), 0.1, 0.1);
SimpleFeatureCollection control = ds.getFeatureSource(dataset.getSchema().getName()).getFeatures(f);
SimpleFeatureCollection c = cache.getFeatures(f);
assertEquals(control.size(), c.size());
if (!testEviction_holistic && (cache.tracker.getEvictions() > 10)) { // wait to generate a fair amount of evictions,
// and see everything is still working
return;
}
}
}
System.out.println(cache.tracker.getStatistics());
System.out.println(cache.sourceAccessStats());
if (!testEviction_holistic) {
fail("Did not got enough evictions : " + cache.tracker.getEvictions());
}
}
public void testEviction2() throws IOException, FeatureCacheException{
SimpleFeatureTypeBuilder bb = new SimpleFeatureTypeBuilder();
bb.add("ID", Integer.class);
bb.add("the_geom", Geometry.class, DefaultEngineeringCRS.CARTESIAN_2D);
bb.setDefaultGeometry("the_geom");
bb.setName("My Feature Type");
//bb.setSRS(DefaultEngineeringCRS.CARTESIAN_2D.toString());
SimpleFeatureType featureType = bb.buildFeatureType();
SimpleFeatureBuilder fb = new SimpleFeatureBuilder(featureType);
GeometryFactory gf = new GeometryFactory();
LineString[] geoms = new LineString[8];
int feature1[] = new int[]{1,1, 1,2, 2,2, 2,1, 1,1};
int feature2[] = new int[]{3,3, 3,4, 4,4, 4,3, 3,3};
int feature3[] = new int[]{5,1, 5,2, 6,2, 6,1, 5,1};
int feature4[] = new int[]{7,3, 7,4, 8,4, 8,3, 7,3};
int feature5[] = new int[]{1,5, 1,6, 2,6, 2,5, 1,5};
int feature6[] = new int[]{3,7, 3,8, 4,8, 4,7, 3,7};
int feature7[] = new int[]{5,5, 5,6, 6,6, 6,5, 5,5};
int feature8[] = new int[]{7,7, 7,8, 8,8, 8,7, 7,7};
Object featurescoords[] = new Object[]{feature1, feature2, feature3, feature4, feature5, feature6, feature7, feature8};
for (int i = 0; i < featurescoords.length; i ++){
int[] values = (int[])featurescoords[i];
Coordinate c[] = new Coordinate[5];
for (int j = 0; j < values.length; j = j + 2){
int x = values[j];
int y = values[j+1];
c[j/2] = new Coordinate(x,y);
}
geoms[i] = gf.createLineString(c);
}
SimpleFeature features[] = new SimpleFeature[geoms.length];
MemoryFeatureCollection mm = new MemoryFeatureCollection(featureType);
for (int i = 0; i < geoms.length; i ++){
features[i] = fb.buildFeature(i +"", new Object[]{new Integer(i), geoms[i]});
mm.add(features[i]);
}
DataStore ds = new MemoryDataStore(mm);
FeatureCache cache = new GridFeatureCache(ds.getFeatureSource(featureType.getTypeName()), 4, 4, MemoryStorage.createInstance());
FilterFactory ff = new FilterFactoryImpl();
Filter f1 = ff.bbox("the_geom", 0, 0, 4.4, 4.4, DefaultEngineeringCRS.CARTESIAN_2D.toString());
Envelope e1 = new Envelope(0, 4.4, 0, 4.4);
Filter f2 = ff.bbox("the_geom", 0, 4.6, 4.4, 8.5, DefaultEngineeringCRS.CARTESIAN_2D.toString());
Envelope e2 = new Envelope(0, 4.4, 4.6, 8.5);
Filter f3 = ff.bbox("the_geom", 4.6, 0, 8.5, 4.4, DefaultEngineeringCRS.CARTESIAN_2D.toString());
Envelope e3 = new Envelope(4.6, 8.5, 0, 4.4);
Filter f4 = ff.bbox("the_geom", 4.6, 4.6, 8.5, 8.5, DefaultEngineeringCRS.CARTESIAN_2D.toString());
Envelope e4 = new Envelope(4.6, 8.5, 4.6, 8.5);
//there should be two features in each region
FeatureCollection fc = cache.getFeatures(f1);
assertEquals(2, fc.size());
fc = cache.getFeatures(f2);
assertEquals(2, fc.size());
fc = cache.getFeatures(f3);
assertEquals(2, fc.size());
//at this point the cache should contain feature from area 2 & 3 and features from area 1
//should have been evicted.
assertEquals(0, ((GridFeatureCache)cache).peek(e4).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e1).size());
assertEquals(2, ((GridFeatureCache)cache).peek(e2).size());
assertEquals(2, ((GridFeatureCache)cache).peek(e3).size());
//lets test the last region
fc = cache.getFeatures(f4);
assertEquals(2, fc.size());
//at this point the cache should contain features from areas 3 & 4 and area 2 should
//have been evicted;
assertEquals(2, ((GridFeatureCache)cache).peek(e3).size());
assertEquals(2, ((GridFeatureCache)cache).peek(e4).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e2).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e1).size());
//lets query region 4 again
fc = cache.getFeatures(f4);
assertEquals(2, fc.size());
//at this point the cache should contain features from areas 3 & 4 and area 2 should
//have been evicted;
assertEquals(2, ((GridFeatureCache)cache).peek(e3).size());
assertEquals(2, ((GridFeatureCache)cache).peek(e4).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e2).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e1).size());
//now lets go back to 1
fc = cache.getFeatures(f1);
assertEquals(2, fc.size());
assertEquals(2, ((GridFeatureCache)cache).peek(e4).size());
assertEquals(2, ((GridFeatureCache)cache).peek(e1).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e2).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e3).size());
//if we peek at 4
fc = ((GridFeatureCache)cache).peek(e4);
//now the cache should be order (least recently used to most recently used) 1, 4
//ask for 2
fc = cache.getFeatures(f2);
//cache: 4,2
assertEquals(2, ((GridFeatureCache)cache).peek(e4).size());
assertEquals(2, ((GridFeatureCache)cache).peek(e2).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e1).size());
assertEquals(0, ((GridFeatureCache)cache).peek(e3).size());
}
@Override
public void testPut() throws CacheOversizedException {
cache.put(dataset);
FeatureCollectingVisitor v = new FeatureCollectingVisitor((SimpleFeatureType)dataset.getSchema());
cache.tracker.intersectionQuery(CacheUtil.convert(unitsquare), v);
//assertEquals(0, v.getCollection().size());
List<Envelope> matches = cache.match(unitsquare);
for (Iterator<Envelope> it = matches.iterator(); it.hasNext();) {
cache.register(it.next());
}
cache.put(dataset);
v = new FeatureCollectingVisitor((SimpleFeatureType)dataset.getSchema());
cache.tracker.intersectionQuery(CacheUtil.convert(unitsquare), v);
assertEquals(dataset.size(), v.getCollection().size());
}
/**
* A test that queries the dataset for a given set of attributes and a maximum number
* of features (Skips the geometry attribute)
*/
public void testQuery () throws IOException{
int maxfeatures = 10;
//build up query
SimpleFeatureType schema = dataset.getSchema();
ArrayList<String> attributes = new ArrayList<String>();
for( int i = 0; i < schema.getAttributeCount(); i++ ) {
AttributeDescriptor attr = schema.getDescriptor(i);
if( !(attr instanceof GeometryDescriptor) ){
attributes.add(attr.getName().getLocalPart());
}
}
DefaultQuery query = new DefaultQuery(schema.getTypeName(),Filter.INCLUDE, maxfeatures, attributes.toArray(new String[0]), null);
FeatureCollection features = cache.getFeatures(query);
//ensure feature count is < maximum
assertTrue(features.size() <= maxfeatures);
//ensure attribute count correct
SimpleFeatureType ftype = (SimpleFeatureType)features.getSchema();
assertEquals(attributes.size(), ftype.getAttributeCount());
}
}