001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017: package org.geotools.data.complex;
018:
019: import java.io.IOException;
020: import java.net.URL;
021: import java.util.Collection;
022: import java.util.Collections;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Set;
026: import java.util.logging.Logger;
027:
028: import junit.framework.AssertionFailedError;
029: import junit.framework.TestCase;
030:
031: import org.geotools.data.Source;
032: import org.geotools.data.complex.config.ComplexDataStoreConfigurator;
033: import org.geotools.data.complex.config.ComplexDataStoreDTO;
034: import org.geotools.data.complex.config.XMLConfigDigester;
035: import org.geotools.data.feature.FeatureSource2;
036: import org.geotools.data.feature.memory.MemoryDataAccess;
037: import org.geotools.factory.CommonFactoryFinder;
038: import org.geotools.feature.iso.Types;
039: import org.geotools.feature.iso.simple.SimpleFeatureBuilder;
040: import org.geotools.feature.iso.simple.SimpleFeatureFactoryImpl;
041: import org.geotools.feature.iso.simple.SimpleTypeBuilder;
042: import org.geotools.feature.iso.simple.SimpleTypeFactoryImpl;
043: import org.geotools.feature.iso.type.TypeFactoryImpl;
044: import org.geotools.geometry.jts.ReferencedEnvelope;
045: import org.geotools.referencing.crs.DefaultGeographicCRS;
046: import org.opengis.feature.Attribute;
047: import org.opengis.feature.Feature;
048: import org.opengis.feature.FeatureCollection;
049: import org.opengis.feature.simple.SimpleFeature;
050: import org.opengis.feature.simple.SimpleFeatureFactory;
051: import org.opengis.feature.simple.SimpleFeatureType;
052: import org.opengis.feature.simple.SimpleTypeFactory;
053: import org.opengis.feature.type.AttributeDescriptor;
054: import org.opengis.feature.type.AttributeType;
055: import org.opengis.feature.type.ComplexType;
056: import org.opengis.feature.type.FeatureType;
057: import org.opengis.feature.type.Name;
058: import org.opengis.feature.type.TypeFactory;
059: import org.opengis.filter.Filter;
060: import org.opengis.filter.FilterFactory;
061: import org.opengis.filter.PropertyIsEqualTo;
062: import org.opengis.filter.expression.Literal;
063: import org.opengis.filter.expression.PropertyName;
064: import org.opengis.geometry.BoundingBox;
065: import org.xml.sax.helpers.NamespaceSupport;
066:
067: import com.vividsolutions.jts.geom.Envelope;
068: import com.vividsolutions.jts.geom.Point;
069:
070: /**
071: *
072: * @author Gabriel Roldan, Axios Engineering
073: * @version $Id: ComplexDataStoreTest.java 28577 2008-01-03 15:44:29Z groldan $
074: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/community-schemas/community-schema-ds/src/test/java/org/geotools/data/complex/ComplexDataStoreTest.java $
075: * @since 2.4
076: */
077: public class ComplexDataStoreTest extends TestCase {
078:
079: private final static Logger LOGGER = org.geotools.util.logging.Logging
080: .getLogger(ComplexDataStoreTest.class.getPackage()
081: .getName());
082:
083: Name targetName;
084:
085: FeatureType targetType;
086:
087: private ComplexDataStore dataStore;
088:
089: FeatureTypeMapping mapping;
090:
091: protected void setUp() throws Exception {
092: super .setUp();
093: MemoryDataAccess ds = createWaterSampleTestFeatures();
094: targetType = TestData.createComplexWaterSampleType();
095: TypeFactory tf = new TypeFactoryImpl();
096: AttributeDescriptor targetFeature = tf
097: .createAttributeDescriptor(targetType, targetType
098: .getName(), 0, Integer.MAX_VALUE, true, null);
099: targetName = targetFeature.getName();
100: List mappings = TestData
101: .createMappingsColumnsAndValues(targetFeature);
102:
103: Name sourceName = TestData.WATERSAMPLE_TYPENAME;
104: FeatureSource2 source = (FeatureSource2) ds.access(sourceName);
105:
106: // empty nssupport as the sample types have no namespace defined
107: NamespaceSupport namespaces = new NamespaceSupport();
108: mapping = new FeatureTypeMapping(source, targetFeature,
109: mappings, namespaces);
110:
111: dataStore = new ComplexDataStore(Collections.singleton(mapping));
112:
113: }
114:
115: protected void tearDown() throws Exception {
116: super .tearDown();
117: }
118:
119: /*
120: * Test method for
121: * 'org.geotools.data.complex.ComplexDataStore.getTypeNames()'
122: */
123: public void testGetTypeNames() throws IOException {
124: String[] typeNames = dataStore.getTypeNames();
125: assertNotNull(typeNames);
126: assertEquals(1, typeNames.length);
127: assertEquals(targetName.getLocalPart(), typeNames[0]);
128:
129: // DataAccess interface:
130: List names = dataStore.getNames();
131: assertNotNull(names);
132: assertEquals(1, names.size());
133: assertEquals(targetName, names.get(0));
134: }
135:
136: /*
137: * Test method for
138: * 'org.geotools.data.complex.ComplexDataStore.getSchema(String)'
139: */
140: public void testDescribeType() throws IOException {
141: AttributeDescriptor descriptor = (AttributeDescriptor) dataStore
142: .describe(targetName);
143: assertNotNull(descriptor);
144: assertEquals(targetType, descriptor.type());
145: }
146:
147: public void testGetBounds() throws IOException {
148: final String namespaceUri = "http://online.socialchange.net.au";
149: final String localName = "RoadSegment";
150: final Name typeName = Types.typeName(namespaceUri, localName);
151:
152: URL configUrl = getClass().getResource(
153: "/test-data/roadsegments.xml");
154:
155: ComplexDataStoreDTO config = new XMLConfigDigester()
156: .parse(configUrl);
157:
158: Set/* <FeatureTypeMapping> */mappings = ComplexDataStoreConfigurator
159: .buildMappings(config);
160:
161: dataStore = new ComplexDataStore(mappings);
162: FeatureSource2 source = (FeatureSource2) dataStore
163: .access(typeName);
164:
165: AttributeDescriptor describe = (AttributeDescriptor) source
166: .describe();
167: FeatureType mappedType = (FeatureType) describe.type();
168: assertNotNull(mappedType.getDefaultGeometry());
169:
170: FeatureTypeMapping mapping = (FeatureTypeMapping) mappings
171: .iterator().next();
172:
173: FeatureSource2 mappedSource = mapping.getSource();
174: ReferencedEnvelope expected = getBounds(mappedSource);
175: Envelope actual = getBounds(source);
176:
177: assertEquals(expected, actual);
178:
179: }
180:
181: private ReferencedEnvelope getBounds(FeatureSource2 source) {
182: ReferencedEnvelope boundingBox = new ReferencedEnvelope(
183: DefaultGeographicCRS.WGS84);
184: FeatureCollection features = (FeatureCollection) source
185: .content();
186: Iterator iterator = features.iterator();
187: try {
188: while (iterator.hasNext()) {
189: Feature f = (Feature) iterator.next();
190: BoundingBox bounds = f.getBounds();
191: boundingBox.include(bounds);
192: }
193: } finally {
194: features.close(iterator);
195: }
196:
197: return boundingBox;
198: }
199:
200: /*
201: * Test method for
202: * 'org.geotools.data.complex.ComplexDataStore.getFeatureReader(String)'
203: */
204: public void testGetFeatureReader() throws IOException {
205: Source access = dataStore.access(targetName);
206: Object describe = access.describe();
207: assertTrue(describe instanceof AttributeDescriptor);
208: assertEquals(targetType, ((AttributeDescriptor) describe)
209: .type());
210:
211: FeatureCollection reader = (FeatureCollection) access.content();
212: assertNotNull(reader);
213:
214: Iterator features = reader.iterator();
215: assertTrue(features.hasNext());
216:
217: Feature complexFeature = (Feature) features.next();
218: assertNotNull(complexFeature);
219: assertEquals(targetType, complexFeature.getType());
220:
221: reader.close(features);
222:
223: org.opengis.filter.FilterFactory ff = CommonFactoryFinder
224: .getFilterFactory(null);
225: PropertyName expr;
226: Object value;
227:
228: expr = ff.property("measurement[1]");
229: value = expr.evaluate(complexFeature);
230: assertNotNull(value);
231:
232: expr = ff.property("measurement[1]/parameter");
233: value = expr.evaluate(complexFeature);
234: assertNotNull(value);
235:
236: expr = ff.property("measurement[1]/value");
237: value = expr.evaluate(complexFeature);
238: assertNotNull(value);
239:
240: expr = ff.property("measurement[2]/parameter");
241: value = expr.evaluate(complexFeature);
242: assertNotNull(value);
243:
244: expr = ff.property("measurement[2]/value");
245: value = expr.evaluate(complexFeature);
246: assertNotNull(value);
247:
248: expr = ff.property("measurement[3]/parameter");
249: value = expr.evaluate(complexFeature);
250: assertNotNull(value);
251:
252: expr = ff.property("measurement[3]/value");
253: value = expr.evaluate(complexFeature);
254: assertNotNull(value);
255:
256: }
257:
258: /*
259: * Test method for
260: * 'org.geotools.data.AbstractDataStore.getFeatureSource(String)'
261: */
262: public void testGetFeatureSource() throws IOException {
263: Source complexSource = dataStore.access(targetName);
264: assertNotNull(complexSource);
265: Object describe = complexSource.describe();
266: assertTrue(describe instanceof AttributeDescriptor);
267: assertEquals(targetType, ((AttributeDescriptor) describe)
268: .type());
269: }
270:
271: /*
272: * Test method for
273: * 'org.geotools.data.AbstractDataStore.getFeatureReader(Query,
274: * Transaction)'
275: */
276: public void testGetFeatureReaderQuery() throws Exception {
277: FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
278:
279: PropertyName property = ff
280: .property("sample/measurement[1]/parameter");
281: Literal literal = ff.literal("ph");
282: Filter filterParameter = ff.equals(property, literal);
283:
284: property = ff.property("sample/measurement[1]/value");
285: literal = ff.literal(new Integer(3));
286: Filter filterValue = ff.equals(property, literal);
287:
288: Filter filter = ff.and(filterParameter, filterValue);
289:
290: Source complexSource = dataStore.access(targetName);
291: FeatureCollection features = (FeatureCollection) complexSource
292: .content(filter);
293:
294: Iterator reader = features.iterator();
295:
296: PropertyIsEqualTo equivalentSourceFilter = ff.equals(ff
297: .property("ph"), ff.literal(new Integer(3)));
298: Collection collection = mapping.getSource().content(
299: equivalentSourceFilter);
300:
301: int count = 0;
302: int expectedCount = collection.size();
303:
304: Filter badFilter = ff.greater(ff
305: .property("sample/measurement[1]/value"), ff
306: .literal(new Integer(3)));
307:
308: while (reader.hasNext()) {
309: Feature f = (Feature) reader.next();
310: assertNotNull(f);
311: assertTrue(filter.evaluate(f));
312: assertFalse(badFilter.evaluate(f));
313: count++;
314: }
315: features.close(reader);
316: assertEquals(expectedCount, count);
317: }
318:
319: public void testGroupByFeatureReader() throws Exception {
320:
321: LOGGER.info("DATA TEST: testGroupByFeatureReader");
322:
323: // dataStore with denormalized wq_ir_results type
324: MemoryDataAccess dataStore = TestData
325: .createDenormalizedWaterQualityResults();
326: // mapping definitions from simple wq_ir_results type to complex wq_plus
327: // type
328: FeatureTypeMapping mapper = TestData
329: .createMappingsGroupByStation(dataStore);
330:
331: // for(Iterator it = mapper.getSource().content().iterator();
332: // it.hasNext();){
333: // SimpleFeature f = (SimpleFeature) it.next();
334: // for(int i = 0; i < f.getNumberOfAttributes(); i++){
335: // Object o = f.get(i);
336: // System.out.print(o + ",\t");
337: // }
338: // System.out.println("");
339: // }
340:
341: targetName = mapper.getTargetFeature().getName();
342:
343: Set/* <FeatureTypeMapping> */mappings = Collections
344: .singleton(mapper);
345:
346: ComplexDataStore complexDataStore = new ComplexDataStore(
347: mappings);
348:
349: Source complexSource = complexDataStore.access(targetName);
350: assertNotNull(complexSource);
351:
352: AttributeDescriptor sourceDescriptor;
353: sourceDescriptor = (AttributeDescriptor) complexSource
354: .describe();
355: targetType = (FeatureType) sourceDescriptor.type();
356: assertNotNull(targetType);
357:
358: FeatureCollection complexFeatures = (FeatureCollection) complexSource
359: .content();
360: assertNotNull(complexFeatures);
361:
362: final int EXPECTED_FEATURE_COUNT = 10;// as results from applying the
363: // mappings to the simple
364: // FeatureSource
365:
366: int featureCount = 0;
367: Iterator it = complexFeatures.iterator();
368: Name measurementName = Types.typeName("measurement");
369: while (it.hasNext()) {
370:
371: Feature currFeature = (Feature) it.next();
372: featureCount++;
373:
374: assertNotNull(currFeature);
375:
376: // currFeature must have as many "measurement" complex attribute
377: // instances as the current iteration number
378: // This check relies on MemoryDataStore returning Features in the
379: // same order they was inserted
380:
381: int expectedMeasurementInstances = featureCount;
382:
383: List/* <Attribute> */measurements = currFeature
384: .get(measurementName);
385:
386: assertNotNull(measurements);
387:
388: try {
389: for (Iterator itr = measurements.iterator(); itr
390: .hasNext();) {
391: Attribute attribute = (Attribute) itr.next();
392: String measurementId = attribute.getID();
393: assertNotNull("expected not null id", measurementId);
394: }
395: assertEquals(expectedMeasurementInstances, measurements
396: .size());
397: } catch (AssertionFailedError e) {
398: LOGGER.warning(currFeature.toString());
399: throw e;
400: }
401:
402: }
403: complexFeatures.close(it);
404: assertEquals(EXPECTED_FEATURE_COUNT, featureCount);
405: }
406:
407: public void testGroupingFeatureIterator() throws Exception {
408: // dataStore with denormalized wq_ir_results type
409: MemoryDataAccess dataStore = TestData
410: .createDenormalizedWaterQualityResults();
411: // mapping definitions from simple wq_ir_results type to complex wq_plus
412: // type
413: FeatureTypeMapping mapper = TestData
414: .createMappingsGroupByStation(dataStore);
415:
416: targetName = mapper.getTargetFeature().getName();
417:
418: Set/* <FeatureTypeMapping> */mappings = Collections
419: .singleton(mapper);
420:
421: ComplexDataStore complexDataStore = new ComplexDataStore(
422: mappings);
423:
424: Source complexSource = complexDataStore.access(targetName);
425: assertNotNull(complexSource);
426:
427: FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
428: Filter filter = ff.equals(ff.property("anzlic_no"), ff
429: .literal("anzlic_no1"));
430: FeatureCollection complexFeatures = (FeatureCollection) complexSource
431: .content(filter);
432: assertNotNull(complexFeatures);
433:
434: Iterator it = complexFeatures.iterator();
435:
436: while (it.hasNext()) {
437: assertTrue(it.hasNext());
438: Feature currFeature = (Feature) it.next();
439: assertNotNull(currFeature);
440: }
441: complexFeatures.close(it);
442: }
443:
444: /**
445: * Loads config from an xml config file which uses a property datastore as
446: * source of features.
447: *
448: * @throws IOException
449: */
450: public void testWithConfig() throws Exception {
451: final String nsUri = "http://online.socialchange.net.au";
452: final String localName = "RoadSegment";
453: final Name typeName = new org.geotools.feature.type.TypeName(
454: nsUri, localName);
455:
456: final URL configUrl = getClass().getResource(
457: "/test-data/roadsegments.xml");
458:
459: ComplexDataStoreDTO config = new XMLConfigDigester()
460: .parse(configUrl);
461:
462: Set/* <FeatureTypeMapping> */mappings = ComplexDataStoreConfigurator
463: .buildMappings(config);
464:
465: dataStore = new ComplexDataStore(mappings);
466: Source source = dataStore.access(typeName);
467:
468: AttributeDescriptor sdesc = (AttributeDescriptor) source
469: .describe();
470: FeatureType type = (FeatureType) sdesc.type();
471:
472: AttributeDescriptor node;
473: node = (AttributeDescriptor) Types.descriptor(type, Types
474: .typeName(nsUri, "the_geom"));
475: assertNotNull(node);
476: assertEquals("LineStringPropertyType", node.type().getName()
477: .getLocalPart());
478:
479: assertNotNull(type.getDefaultGeometry());
480: assertEquals(node.type(), type.getDefaultGeometry().type());
481:
482: assertNotNull(Types.descriptor(type, Types.typeName(nsUri,
483: "name")));
484:
485: Name ftNodeName = Types.typeName(nsUri, "fromToNodes");
486: assertNotNull(Types.descriptor(type, ftNodeName));
487:
488: AttributeDescriptor descriptor = (AttributeDescriptor) Types
489: .descriptor(type, ftNodeName);
490:
491: ComplexType fromToNodes = (ComplexType) descriptor.type();
492:
493: assertFalse(descriptor.isNillable());
494: assertTrue(fromToNodes.isIdentified());
495:
496: Name fromNodeName = Types.typeName(nsUri, "fromNode");
497: AttributeDescriptor fromNode = (AttributeDescriptor) Types
498: .descriptor(fromToNodes, fromNodeName);
499: assertNotNull(fromNode);
500:
501: Name toNodeName = Types.typeName(nsUri, "toNode");
502: AttributeDescriptor toNode = (AttributeDescriptor) Types
503: .descriptor(fromToNodes, toNodeName);
504: assertNotNull(fromNode);
505:
506: assertEquals(Point.class, ((AttributeType) fromNode.type())
507: .getBinding());
508: assertEquals(Point.class, ((AttributeType) toNode.type())
509: .getBinding());
510:
511: FeatureCollection content = (FeatureCollection) source
512: .content();
513: Iterator features = content.iterator();
514: int count = 0;
515: final int expectedCount = 5;
516: try {
517: while (features.hasNext()) {
518: Feature f = (Feature) features.next();
519: LOGGER.finest(String.valueOf(f));
520: ++count;
521: }
522: } catch (Exception e) {
523: e.printStackTrace();
524: throw e;
525: } finally {
526: content.close(features);
527: }
528: assertEquals("feature count", expectedCount, count);
529: }
530:
531: /**
532: * Creates a MemoryDataStore contaning a simple FeatureType with test data
533: * for the "Multiple columns could be mapped to a multi-value property"
534: * mapping case.
535: * <p>
536: * The structure of the "WaterSample" FeatureType is as follows: <table>
537: * <tr>
538: * <th>watersampleid</th>
539: * <th>ph</th>
540: * <th>temp</th>
541: * <th>turbidity</th>
542: * </tr>
543: * <tr>
544: * <td>watersample.1</td>
545: * <td>7</td>
546: * <td>21</td>
547: * <td>0.6</td>
548: * </tr>
549: * </table>
550: * </p>
551: */
552: public static MemoryDataAccess createWaterSampleTestFeatures()
553: throws Exception {
554: MemoryDataAccess dataStore = new MemoryDataAccess();
555: SimpleTypeFactory tf = new SimpleTypeFactoryImpl();
556: SimpleTypeBuilder tb = new SimpleTypeBuilder(tf);
557:
558: tb.setName(TestData.WATERSAMPLE_TYPENAME.getLocalPart());
559: tb.addAttribute("watersampleid", String.class);
560: tb.addAttribute("ph", Integer.class);
561: tb.addAttribute("temp", Integer.class);
562: tb.addAttribute("turbidity", Float.class);
563:
564: SimpleFeatureType type = tb.feature();
565:
566: dataStore.createSchemaInternal(type);
567:
568: final int NUM_FEATURES = 10;
569: SimpleFeatureFactory af = new SimpleFeatureFactoryImpl();
570:
571: SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(
572: new SimpleFeatureFactoryImpl());
573: for (int i = 0; i < NUM_FEATURES; i++) {
574: String fid = type.getName().getLocalPart() + "." + i;
575:
576: fbuilder.init();
577: fbuilder.setType(type);
578: fbuilder.add("watersample." + i);
579: fbuilder.add(new Integer(i));
580: fbuilder.add(new Integer(10 + i));
581: fbuilder.add(new Float(i));
582:
583: SimpleFeature f = fbuilder.feature(fid);
584: dataStore.addFeatureInternal(f);
585: }
586: return dataStore;
587: }
588: }
|