/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2004-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.data.complex;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import junit.framework.TestCase;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureSource;
import org.geotools.data.complex.config.AppSchemaDataAccessConfigurator;
import org.geotools.data.complex.config.AppSchemaDataAccessDTO;
import org.geotools.data.complex.config.XMLConfigDigester;
import org.geotools.data.memory.MemoryDataStore;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.NameImpl;
import org.geotools.feature.Types;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.feature.type.FeatureTypeFactoryImpl;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.ComplexType;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.FeatureTypeFactory;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.PropertyIsEqualTo;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.xml.sax.helpers.NamespaceSupport;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Point;
/**
*
* @author Gabriel Roldan, Axios Engineering
* @version $Id$
* @source $URL$
* @since 2.4
*/
public class AppSchemaDataAccessTest extends TestCase {
private final static Logger LOGGER = org.geotools.util.logging.Logging
.getLogger(AppSchemaDataAccessTest.class.getPackage().getName());
Name targetName;
FeatureType targetType;
private AppSchemaDataAccess dataStore;
FeatureTypeMapping mapping;
protected void setUp() throws Exception {
super.setUp();
MemoryDataStore ds = createWaterSampleTestFeatures();
targetType = TestData.createComplexWaterSampleType();
FeatureTypeFactory tf = new FeatureTypeFactoryImpl();
AttributeDescriptor targetFeature = tf.createAttributeDescriptor(targetType, targetType
.getName(), 0, Integer.MAX_VALUE, true, null);
targetName = targetFeature.getName();
List mappings = TestData.createMappingsColumnsAndValues(targetFeature);
Name sourceName = TestData.WATERSAMPLE_TYPENAME;
FeatureSource<SimpleFeatureType, SimpleFeature> source = ds.getFeatureSource(sourceName);
// empty nssupport as the sample types have no namespace defined
NamespaceSupport namespaces = new NamespaceSupport();
mapping = new FeatureTypeMapping(source, targetFeature, mappings, namespaces);
dataStore = new AppSchemaDataAccess(Collections.singleton(mapping));
}
protected void tearDown() throws Exception {
super.tearDown();
DataAccessRegistry.unregisterAll();
}
/*
* Test method for 'org.geotools.data.complex.ComplexDataStore.getTypeNames()'
*/
public void testGetTypeNames() throws IOException {
Name[] typeNames = dataStore.getTypeNames();
assertNotNull(typeNames);
assertEquals(1, typeNames.length);
assertEquals(targetName, typeNames[0]);
// DataAccess interface:
List names = dataStore.getNames();
assertNotNull(names);
assertEquals(1, names.size());
assertEquals(targetName, names.get(0));
}
/*
* Test method for 'org.geotools.data.complex.ComplexDataStore.getSchema(String)'
*/
public void testTargetType() throws IOException {
assertEquals(targetType, dataStore.getSchema(targetName));
}
public void testGetBounds() throws IOException {
final String namespaceUri = "http://online.socialchange.net.au";
final String localName = "RoadSegment";
final Name typeName = Types.typeName(namespaceUri, localName);
URL configUrl = getClass().getResource("/test-data/roadsegments.xml");
AppSchemaDataAccessDTO config = new XMLConfigDigester().parse(configUrl);
Set<FeatureTypeMapping> mappings = AppSchemaDataAccessConfigurator.buildMappings(config);
dataStore = new AppSchemaDataAccess(mappings);
FeatureSource<FeatureType, Feature> source = dataStore.getFeatureSource(typeName);
FeatureTypeMapping mapping = (FeatureTypeMapping) mappings.iterator().next();
FeatureSource<SimpleFeatureType, SimpleFeature> mappedSource = mapping.getSource();
Envelope expected = getBounds(mappedSource);
Envelope actual = getBounds(source);
assertEquals(expected, actual);
}
// if someone can tell me how to write this with "? extends Feature" and still have it accepted
// by features.close, I would like to know
@SuppressWarnings("unchecked")
private ReferencedEnvelope getBounds(FeatureSource source) {
try {
ReferencedEnvelope boundingBox = new ReferencedEnvelope(DefaultGeographicCRS.WGS84);
FeatureCollection features = source.getFeatures();
Iterator<Feature> iterator = features.iterator();
try {
while (iterator.hasNext()) {
Feature f = iterator.next();
boundingBox.include(f.getBounds());
}
} finally {
features.close(iterator);
}
return boundingBox;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/*
* Test method for 'org.geotools.data.complex.ComplexDataStore.getFeatureReader(String)'
*/
public void testGetFeatureReader() throws IOException {
FeatureSource<FeatureType, Feature> access = dataStore.getFeatureSource(targetName);
FeatureType type = access.getSchema();
assertEquals(targetType, type);
FeatureCollection<FeatureType, Feature> reader = access.getFeatures();
assertNotNull(reader);
Iterator<Feature> features = reader.iterator();
assertTrue(features.hasNext());
Feature complexFeature = (Feature) features.next();
assertNotNull(complexFeature);
assertEquals(targetType, complexFeature.getType());
reader.close(features);
org.opengis.filter.FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
PropertyName expr;
Object value;
expr = ff.property("measurement[1]");
value = expr.evaluate(complexFeature);
assertNotNull(value);
expr = ff.property("measurement[1]/parameter");
value = expr.evaluate(complexFeature);
assertNotNull(value);
expr = ff.property("measurement[1]/value");
value = expr.evaluate(complexFeature);
assertNotNull(value);
expr = ff.property("measurement[2]/parameter");
value = expr.evaluate(complexFeature);
assertNotNull(value);
expr = ff.property("measurement[2]/value");
value = expr.evaluate(complexFeature);
assertNotNull(value);
expr = ff.property("measurement[3]/parameter");
value = expr.evaluate(complexFeature);
assertNotNull(value);
expr = ff.property("measurement[3]/value");
value = expr.evaluate(complexFeature);
assertNotNull(value);
}
/*
* Test method for 'org.geotools.data.AbstractDataStore.getFeatureSource(String)'
*/
public void testGetFeatureSource() throws IOException {
FeatureSource<FeatureType, Feature> complexSource = dataStore.getFeatureSource(targetName);
assertNotNull(complexSource);
assertEquals(targetType, complexSource.getSchema());
}
/*
* Test method for 'org.geotools.data.AbstractDataStore.getFeatureReader(Query, Transaction)'
*/
public void testGetFeatureReaderQuery() throws Exception {
FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
PropertyName property = ff.property("sample/measurement[1]/parameter");
Literal literal = ff.literal("ph");
Filter filterParameter = ff.equals(property, literal);
property = ff.property("sample/measurement[1]/value");
literal = ff.literal(new Integer(3));
Filter filterValue = ff.equals(property, literal);
Filter filter = ff.and(filterParameter, filterValue);
FeatureSource<FeatureType, Feature> complexSource = dataStore.getFeatureSource(targetName);
FeatureCollection<FeatureType, Feature> features = complexSource.getFeatures(filter);
Iterator<Feature> reader = features.iterator();
PropertyIsEqualTo equivalentSourceFilter = ff.equals(ff.property("ph"), ff
.literal(new Integer(3)));
FeatureCollection<SimpleFeatureType, SimpleFeature> collection = mapping.getSource()
.getFeatures(equivalentSourceFilter);
int count = 0;
int expectedCount = collection.size();
Filter badFilter = ff.greater(ff.property("sample/measurement[1]/value"), ff
.literal(new Integer(3)));
while (reader.hasNext()) {
Feature f = (Feature) reader.next();
assertNotNull(f);
assertTrue(filter.evaluate(f));
assertFalse(badFilter.evaluate(f));
count++;
}
features.close(reader);
assertEquals(expectedCount, count);
}
/**
* Loads config from an xml config file which uses a property datastore as source of features.
*
* @throws IOException
*/
public void testWithConfig() throws Exception {
final String nsUri = "http://online.socialchange.net.au";
final String localName = "RoadSegment";
final Name typeName = new NameImpl(nsUri, localName);
final URL configUrl = getClass().getResource("/test-data/roadsegments.xml");
AppSchemaDataAccessDTO config = new XMLConfigDigester().parse(configUrl);
Set/* <FeatureTypeMapping> */mappings = AppSchemaDataAccessConfigurator
.buildMappings(config);
dataStore = new AppSchemaDataAccess(mappings);
FeatureSource<FeatureType, Feature> source = dataStore.getFeatureSource(typeName);
FeatureType type = source.getSchema();
AttributeDescriptor node;
node = (AttributeDescriptor) Types.descriptor(type, Types.typeName(nsUri, "the_geom"));
assertNotNull(node);
assertEquals("LineStringPropertyType", node.getType().getName().getLocalPart());
assertNotNull(Types.descriptor(type, Types.typeName(nsUri, "name")));
Name ftNodeName = Types.typeName(nsUri, "fromToNodes");
assertNotNull(Types.descriptor(type, ftNodeName));
AttributeDescriptor descriptor = (AttributeDescriptor) Types.descriptor(type, ftNodeName);
ComplexType fromToNodes = (ComplexType) descriptor.getType();
assertFalse(descriptor.isNillable());
assertTrue(fromToNodes.isIdentified());
Name fromNodeName = Types.typeName(nsUri, "fromNode");
AttributeDescriptor fromNode = (AttributeDescriptor) Types.descriptor(fromToNodes,
fromNodeName);
assertNotNull(fromNode);
Name toNodeName = Types.typeName(nsUri, "toNode");
AttributeDescriptor toNode = (AttributeDescriptor) Types
.descriptor(fromToNodes, toNodeName);
assertNotNull(fromNode);
assertEquals(Point.class, fromNode.getType().getBinding());
assertEquals(Point.class, toNode.getType().getBinding());
// test to see if the mapping can successfully substitute a valid narrower type
Name subName = Types.typeName(nsUri, "broadTypeEl");
descriptor = (AttributeDescriptor) Types.descriptor(type, subName);
ComplexType subbedType = (ComplexType) descriptor.getType();
AttributeDescriptor sub = (AttributeDescriptor) Types
.descriptor(subbedType, subName);
// assertNotNull(sub);
// assertEquals(Point.class, fromNode.getType().getBinding());
FeatureCollection<FeatureType, Feature> content = source.getFeatures();
Iterator<Feature> features = content.iterator();
int count = 0;
final int expectedCount = 5;
try {
while (features.hasNext()) {
Feature f = features.next();
LOGGER.finest(String.valueOf(f));
++count;
}
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
content.close(features);
}
assertEquals("feature count", expectedCount, count);
// Test DefaultMappingFeatureIterator MaxFeatures support [GEOS-1930]
final int expectedCount2 = 3;
DefaultQuery query = new DefaultQuery();
query.setMaxFeatures(expectedCount2);
FeatureCollection<FeatureType, Feature> content2 = source.getFeatures(query);
Iterator<Feature> features2 = content2.iterator();
int count2 = 0;
try {
while (features2.hasNext()) {
Feature f = (Feature) features2.next();
LOGGER.finest(String.valueOf(f));
++count2;
}
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
content.close(features2);
}
assertEquals("feature count", expectedCount2, count2);
}
/**
* Creates a MemoryDataStore contaning a simple FeatureType with test data for the "Multiple
* columns could be mapped to a multi-value property" mapping case.
* <p>
* The structure of the "WaterSample" FeatureType is as follows: <table>
* <tr>
* <th>watersampleid</th>
* <th>ph</th>
* <th>temp</th>
* <th>turbidity</th>
* </tr>
* <tr>
* <td>watersample.1</td>
* <td>7</td>
* <td>21</td>
* <td>0.6</td>
* </tr>
* </table>
* </p>
*/
public static MemoryDataStore createWaterSampleTestFeatures() throws Exception {
MemoryDataStore dataStore = new MemoryDataStore();
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
tb.setName(TestData.WATERSAMPLE_TYPENAME.getLocalPart());
tb.add("watersampleid", String.class);
tb.add("ph", Integer.class);
tb.add("temp", Integer.class);
tb.add("turbidity", Float.class);
SimpleFeatureType type = tb.buildFeatureType();
dataStore.createSchema(type);
final int NUM_FEATURES = 10;
SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(type);
for (int i = 0; i < NUM_FEATURES; i++) {
String fid = type.getName().getLocalPart() + "." + i;
fbuilder.add("watersample." + i);
fbuilder.add(new Integer(i));
fbuilder.add(new Integer(10 + i));
fbuilder.add(new Float(i));
SimpleFeature f = fbuilder.buildFeature(fid);
dataStore.addFeature(f);
}
return dataStore;
}
}