/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2009-2011, 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.geotools.data.DataAccess; import org.geotools.data.DataAccessFinder; import org.geotools.data.FeatureSource; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureImpl; import org.geotools.feature.FeatureIterator; import org.geotools.feature.Types; import org.geotools.filter.FilterFactoryImpl; import org.geotools.gml3.bindings.GML3EncodingUtils; import org.geotools.test.AppSchemaTestSupport; import org.junit.BeforeClass; import org.junit.Test; import org.opengis.feature.ComplexAttribute; import org.opengis.feature.Feature; import org.opengis.feature.Property; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.Name; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.Expression; import org.xml.sax.Attributes; import org.xml.sax.helpers.NamespaceSupport; import com.vividsolutions.jts.util.Stopwatch; /** * This is the tests for feature chaining; nesting complex attributes (feature and non-feature) * inside another complex attribute. * * @author Rini Angreani (CSIRO Earth Science and Resource Engineering) * * * * @source $URL$ */ public class FeatureChainingTest extends AppSchemaTestSupport { public static final String GSMLNS = "urn:cgi:xmlns:CGI:GeoSciML:2.0"; public static final String GMLNS = "http://www.opengis.net/gml"; public static final String XLINKNS = "http://www.w3.org/1999/xlink"; static final Name MAPPED_FEATURE_TYPE = Types.typeName(GSMLNS, "MappedFeatureType"); static final Name MAPPED_FEATURE = Types.typeName(GSMLNS, "MappedFeature"); static final Name GEOLOGIC_UNIT_TYPE = Types.typeName(GSMLNS, "GeologicUnitType"); static final Name GEOLOGIC_UNIT = Types.typeName(GSMLNS, "GeologicUnit"); static final Name GEOLOGIC_UNIT_NAME = Types.typeName("myGeologicUnit"); static final Name COMPOSITION_PART_TYPE = Types.typeName(GSMLNS, "CompositionPartType"); static final Name COMPOSITION_PART = Types.typeName(GSMLNS, "CompositionPart"); static final Name CGI_TERM_VALUE = Types.typeName(GSMLNS, "CGI_TermValue"); static final Name CGI_TERM_VALUE_TYPE = Types.typeName(GSMLNS, "CGI_TermValueType"); static final Name CONTROLLED_CONCEPT = Types.typeName(GSMLNS, "ControlledConcept"); static FilterFactory2 ff = new FilterFactoryImpl(null); private NamespaceSupport namespaces = new NamespaceSupport(); public FeatureChainingTest() { namespaces.declarePrefix("gml", GMLNS); namespaces.declarePrefix("gsml", GSMLNS); namespaces.declarePrefix("xlink", XLINKNS); } /** * Map of geological unit values to mapped feature objects based on * mappedFeaturePropertyFile.properties */ final static Map<String, String> mfToGuMap = new HashMap<String, String>() { { put("mf1", "gu.25699"); put("mf2", "gu.25678"); put("mf3", "gu.25678"); put("mf4", "gu.25682"); } }; /** * Map of compositional part values to geological unit objects based on geologicUnit.properties */ final static Map<String, String> guToCpMap = new HashMap<String, String>() { { put("gu.25699", "cp.167775491936278899"); put("gu.25678", "cp.167775491936278844;cp.167775491936278856"); put("gu.25682", "cp.167775491936278812"); } }; /** * Map of exposure colour values to geological unit objects based on geologicUnit.properties */ final static Map<String, String> guToExposureColorMap = new HashMap<String, String>() { { put("gu.25699", "Blue"); put("gu.25678", "Yellow;Blue"); put("gu.25682", "Red"); } }; /** * Map of out crop character values to geological unit objects based on geologicUnit.properties */ static Map<String, String> guToOutcropCharacterMap = new HashMap<String, String>() { { put("gu.25699", "x"); put("gu.25678", "x;y"); put("gu.25682", "z"); } }; private static final String schemaBase = "/test-data/"; private static FeatureSource<FeatureType, Feature> mfSource; /** * Generated mapped features */ private static FeatureCollection<FeatureType, Feature> mfFeatures; /** * Generated geological unit features */ private static FeatureCollection<FeatureType, Feature> guFeatures; /** * Generated compositional part fake "features" */ private static FeatureCollection<FeatureType, Feature> cpFeatures; /** * Generated controlled concept fake "features" */ private static FeatureCollection<FeatureType, Feature> ccFeatures; @BeforeClass public static void setUpBeforeClass() throws Exception { Stopwatch sw = new Stopwatch(); sw.start(); loadDataAccesses(); sw.stop(); System.out.println("Set up time: " + sw.getTimeString()); } /** * Test that chaining works * * @throws Exception */ @Test public void testFeatureChaining() throws Exception { FeatureIterator<Feature> mfIterator = mfFeatures.features(); FeatureIterator<Feature> guIterator = guFeatures.features(); // Extract all geological unit features into a map by id Map<String, Feature> guMap = new HashMap<String, Feature>(); Feature guFeature; while (guIterator.hasNext()) { guFeature = (Feature) guIterator.next(); String guId = guFeature.getIdentifier().getID(); if (!guMap.containsKey(guId)) { guMap.put(guId, guFeature); } } // Extract all compositional part "features" into a map by id FeatureIterator<Feature> cpIterator = cpFeatures.features(); Map<String, Feature> cpMap = new HashMap<String, Feature>(); Feature cpFeature; while (cpIterator.hasNext()) { cpFeature = (Feature) cpIterator.next(); String cpId = cpFeature.getIdentifier().getID(); if (!cpMap.containsKey(cpId)) { cpMap.put(cpId, cpFeature); } } Feature mfFeature; Collection<Property> nestedGuFeatures; String guId; final String NESTED_LINK = "specification"; Collection<Property> nestedCpFeatures; String cpId; while (mfIterator.hasNext()) { mfFeature = (Feature) mfIterator.next(); String mfId = mfFeature.getIdentifier().toString(); String[] guIds = this.mfToGuMap.get(mfId).split(";"); // make sure we have the right number of nested features nestedGuFeatures = (Collection<Property>) mfFeature.getProperties(NESTED_LINK); assertEquals(guIds.length, nestedGuFeatures.size()); ArrayList<String> nestedGuIds = new ArrayList<String>(); for (Property property : nestedGuFeatures) { Object value = property.getValue(); assertNotNull(value); assertTrue(value instanceof Collection); assertEquals(1, ((Collection) value).size()); Feature nestedGuFeature = (Feature) ((Collection) value).iterator().next(); /** * Test geological unit */ // make sure each of the nested geologic unit is valid guId = nestedGuFeature.getIdentifier().toString(); assertTrue(guMap.containsKey(guId)); nestedGuIds.add(guId); // make sure the nested geologic unit feature has the right properties guFeature = guMap.get(guId.toString()); Collection<Property> guProperties = guFeature.getProperties(); assertEquals(nestedGuFeature.getProperties(), guProperties); /** * Test compositional part */ // make sure the right number of nested features are there String[] cpIds = this.guToCpMap.get(guId).split(";"); nestedCpFeatures = (Collection<Property>) guFeature.getProperties("composition"); assertEquals(cpIds.length, nestedCpFeatures.size()); ArrayList<String> nestedCpIds = new ArrayList<String>(); for (Property cpProperty : nestedCpFeatures) { Object cpPropertyValue = cpProperty.getValue(); assertNotNull(cpPropertyValue); assertTrue(cpPropertyValue instanceof Collection); assertEquals(1, ((Collection) cpPropertyValue).size()); Feature nestedCpFeature = (Feature) ((Collection) cpPropertyValue).iterator() .next(); // make sure each of the nested compositional part feature is valid cpId = nestedCpFeature.getIdentifier().toString(); assertTrue(cpMap.containsKey(cpId)); nestedCpIds.add(cpId); // make sure each of the nested compositional part has the right properties cpFeature = cpMap.get(cpId.toString()); Collection<Property> cpProperties = cpFeature.getProperties(); assertEquals(nestedCpFeature.getProperties(), cpProperties); } // make sure all the nested compositional part features are there assertTrue(nestedCpIds.containsAll(Arrays.asList(cpIds))); } // make sure all the nested geological unit features are there assertTrue(nestedGuIds.containsAll(Arrays.asList(guIds))); } mfIterator.close(); guIterator.close(); cpIterator.close(); } /** * testFeatureChaining() tests one to many relationship, but the many side was on the chaining * side ie. geologic unit side (with many composition parts). This is to test that configuring * many on the the chained works. We're using composition part -> lithology here. * * @throws Exception */ @Test public void testManyOnChainedSide() throws Exception { final String LITHOLOGY = "lithology"; // get controlled concept features on their own AbstractMappingFeatureIterator iterator = (AbstractMappingFeatureIterator) ccFeatures .features(); int count = 0; Map<String, Feature> featureList = new HashMap<String, Feature>(); try { while (iterator.hasNext()) { Feature f = iterator.next(); featureList.put(f.getIdentifier().getID(), f); count++; } } finally { iterator.close(); } assertEquals(5, count); FeatureIterator<Feature> cpIterator = cpFeatures.features(); while (cpIterator.hasNext()) { Feature cpFeature = (Feature) cpIterator.next(); Collection<Property> lithologies = cpFeature.getProperties(LITHOLOGY); if (cpFeature.getIdentifier().toString().equals("cp.167775491936278812")) { // see ControlledConcept.properties file: // _=NAME:String,COMPOSITION_ID:String // cc.1=name_a|cp.167775491936278812 // cc.1=name_b|cp.167775491936278812 // cc.1=name_c|cp.167775491936278812 // cc.2=name_2|cp.167775491936278812 assertEquals(2, ((Collection) lithologies).size()); Collection<String> lithologyIds = new ArrayList<String>(); for (Property lithologyProperty : lithologies) { Feature nestedFeature = (Feature) ((Collection) lithologyProperty.getValue()) .iterator().next(); String fId = nestedFeature.getIdentifier().getID(); lithologyIds.add(fId); Feature lithology = featureList.get(fId); assertEquals(nestedFeature.getProperties(), lithology.getProperties()); } assertTrue(featureList.keySet().containsAll(lithologyIds)); } else { // lithology is required assertEquals(1, lithologies.size()); } } } /** * Test nesting multiple multi valued properties. Both exposure color and outcrop character are * multi valued. By making sure that both are nested inside geological unit feature, it's * verified that nesting multiple multi valued properties is possible. * * @throws Exception */ @Test public void testMultipleMultiValuedProperties() throws Exception { FeatureIterator<Feature> guIterator = guFeatures.features(); Feature guFeature; final String EXPOSURE_COLOR = "exposureColor"; final String OUTCROP_CHARACTER = "outcropCharacter"; while (guIterator.hasNext()) { guFeature = (Feature) guIterator.next(); String guId = guFeature.getIdentifier().toString(); ArrayList realValues = new ArrayList(); /** * Test exposure color */ Collection<Property> nestedTermValues = (Collection<Property>) guFeature .getProperties(EXPOSURE_COLOR); // get exposure color property values from geological unit feature for (Property property : nestedTermValues) { Object value = property.getValue(); assertNotNull(value); assertTrue(value instanceof Collection); assertEquals(1, ((Collection) value).size()); Feature feature = (Feature) ((Collection) value).iterator().next(); for (Property nestedProperty : feature.getProperties("value")) { realValues.add(((Property) ((Collection) nestedProperty.getValue()).iterator() .next()).getValue()); } } // compares the values from the property file String[] values = this.guToExposureColorMap.get(guId).split(";"); assertEquals(realValues.size(), values.length); assertTrue(realValues.containsAll(Arrays.asList(values))); /** * Test outcrop character */ nestedTermValues = (Collection<Property>) guFeature.getProperties(OUTCROP_CHARACTER); realValues.clear(); // get nested outcrop character values from geological unit feature for (Property property : nestedTermValues) { Object value = property.getValue(); assertNotNull(value); assertTrue(value instanceof Collection); assertEquals(1, ((Collection) value).size()); Feature feature = (Feature) ((Collection) value).iterator().next(); for (Property nestedProperty : feature.getProperties("value")) { realValues.add(((Property) ((Collection) nestedProperty.getValue()).iterator() .next()).getValue()); } } // compare with values from property file values = this.guToOutcropCharacterMap.get(guId).split(";"); assertEquals(realValues.size(), values.length); assertTrue(realValues.containsAll(Arrays.asList(values))); } guIterator.close(); } /** * Test mapping multi-valued simple properties still works. * * @throws Exception */ @Test public void testMultiValuedSimpleProperties() throws Exception { FeatureIterator<Feature> iterator = ccFeatures.features(); while (iterator.hasNext()) { Feature next = iterator.next(); Collection<Property> names = next.getProperties("name"); // these are gml:name and gsml:name, so count twice if (next.getIdentifier().toString().equals("cc.1")) { // see ControlledConcept.properties where id = cc.1 assertEquals(6, names.size()); } else { // see ControlledConcept.properties where id = cc.2 assertEquals(2, names.size()); } } iterator.close(); } /** * Test filtering attributes on nested features. * * @throws Exception */ @Test public void testFilters() throws Exception { // make sure filter query can be made on MappedFeature based on GU properties // // <ogc:Filter> // <ogc:PropertyIsLike> // <ogc:PropertyName> // gsml:specification/gsml:GeologicUnit/gml:description // </ogc:PropertyName> // <ogc:Literal>Olivine basalt, tuff, microgabbro, minor sedimentary rocks</ogc:Literal> // </ogc:PropertyIsLike> // </ogc:Filter> Expression property = ff.property("gsml:specification/gsml:GeologicUnit/gml:description", namespaces); Filter filter = ff.like(property, "Olivine basalt, tuff, microgabbro, minor sedimentary rocks"); FeatureCollection<FeatureType, Feature> filteredResults = mfSource.getFeatures(filter); assertEquals(3, size(filteredResults)); FeatureIterator<Feature> iterator = filteredResults.features(); Feature feature = iterator.next(); assertEquals("mf1", feature.getIdentifier().toString()); feature = iterator.next(); assertEquals("mf2", feature.getIdentifier().toString()); feature = iterator.next(); assertEquals("mf3", feature.getIdentifier().toString()); iterator.close(); /** * Test filtering on multi valued properties */ FeatureSource<FeatureType, Feature> guSource = AppSchemaDataAccessRegistry.getFeatureSource(GEOLOGIC_UNIT_NAME); // composition part is a multi valued property // we're testing that we can get a geologic unit which has a composition part with a // significant proportion value property = ff .property("gsml:composition/gsml:CompositionPart/gsml:proportion/gsml:CGI_TermValue/gsml:value", namespaces); filter = ff.equals(property, ff.literal("significant")); filteredResults = guSource.getFeatures(filter); assertEquals(2, size(filteredResults)); iterator = filteredResults.features(); feature = iterator.next(); assertEquals("gu.25678", feature.getIdentifier().toString()); feature = iterator.next(); assertEquals("gu.25682", feature.getIdentifier().toString()); iterator.close(); /** * Test filtering client properties on chained features */ property = ff.property("gsml:specification/gsml:GeologicUnit/gsml:occurrence/@xlink:href", namespaces); filter = ff.like(property, "urn:cgi:feature:MappedFeature:mf1"); filteredResults = mfSource.getFeatures(filter); assertEquals(1, size(filteredResults)); feature = filteredResults.features().next(); assertEquals("mf1", feature.getIdentifier().toString()); /** * Test filtering on denormalised view, see GEOT-2927 */ property = ff.property("gml:name"); filter = ff.equals(property, ff.literal("Yaugher Volcanic Group 2")); filteredResults = guSource.getFeatures(filter); assertEquals(1, size(filteredResults)); // There are 2 rows for 1 feature that matches this filter: // gu.25678=-Py|Yaugher Volcanic Group 1 // gu.25678=-Py|Yaugher Volcanic Group 2 // Check that all 3 names are there: // - Yaugher Volcanic Group 1, Yaugher Volcanic Group 2 and -Py feature = filteredResults.features().next(); assertEquals("gu.25678", feature.getIdentifier().toString()); Collection<Property> properties = feature.getProperties(Types.typeName(GMLNS, "name")); assertTrue(properties.size() == 3); Iterator<Property> propIterator = properties.iterator(); ComplexAttribute complexAttribute; Collection<? extends Property> values; // first complexAttribute = (ComplexAttribute) propIterator.next(); values = complexAttribute.getValue(); assertEquals(1, values.size()); assertEquals("Yaugher Volcanic Group 1", GML3EncodingUtils.getSimpleContent(complexAttribute)); // second complexAttribute = (ComplexAttribute) propIterator.next(); values = complexAttribute.getValue(); assertEquals(1, values.size()); assertEquals("Yaugher Volcanic Group 2", GML3EncodingUtils.getSimpleContent(complexAttribute)); // third complexAttribute = (ComplexAttribute) propIterator.next(); values = complexAttribute.getValue(); assertEquals(1, values.size()); assertEquals("-Py", GML3EncodingUtils.getSimpleContent(complexAttribute)); /** * Same case as above, but the multi-valued property is feature chained */ property = ff.property("gsml:exposureColor/gsml:CGI_TermValue/gsml:value", namespaces); filter = ff.equals(property, ff.literal("Yellow")); filteredResults = guSource.getFeatures(filter); assertEquals(1, size(filteredResults)); feature = filteredResults.features().next(); // ensure it's the right feature assertEquals("gu.25678", feature.getIdentifier().toString()); properties = feature.getProperties(Types.typeName(GSMLNS, "exposureColor")); assertTrue(properties.size() == 2); propIterator = properties.iterator(); values = (Collection) propIterator.next().getValue(); assertEquals(1, values.size()); Feature cgiFeature = (Feature) values.iterator().next(); // and that both gsml:exposureColor values from 2 denormalised view rows are there assertEquals("Yellow", cgiFeature.getIdentifier().toString()); values = (Collection) propIterator.next().getValue(); assertEquals(1, values.size()); cgiFeature = (Feature) values.iterator().next(); assertEquals("Blue", cgiFeature.getIdentifier().toString()); } /** * Test nesting features of a complex type with simple content. Previously didn't get encoded. * Also making sure that a feature type can have multiple FEATURE_LINK to be referred by * different types. * * @throws Exception */ @Test public void testComplexTypeWithSimpleContent() throws Exception { Map dsParams = new HashMap(); URL url = getClass().getResource(schemaBase + "FirstParentFeature.xml"); assertNotNull(url); dsParams.put("dbtype", "app-schema"); dsParams.put("url", url.toExternalForm()); DataAccess<FeatureType, Feature> dataAccess = DataAccessFinder.getDataStore(dsParams); assertNotNull(dataAccess); // <AttributeMapping> // <targetAttribute>FEATURE_LINK[1]</targetAttribute> // <sourceExpression> // <OCQL>LINK_ONE</OCQL> // </sourceExpression> // </AttributeMapping> Name typeName = Types.typeName("http://example.com", "FirstParentFeature"); FeatureType featureType = dataAccess.getSchema(typeName); assertNotNull(featureType); FeatureSource fSource = (FeatureSource) dataAccess.getFeatureSource(typeName); FeatureCollection features = (FeatureCollection) fSource.getFeatures(); assertEquals(5, size(features)); FeatureIterator iterator = features.features(); while (iterator.hasNext()) { Feature next = iterator.next(); Collection<Property> children = next.getProperties("nestedFeature"); if (next.getIdentifier().toString().equals("cc.1")) { // _=STRING:String,LINK_ONE:String,LINK_TWO:String // sc.1=string_one|cc.1|cc.2 // sc.2=string_two|cc.1|cc.2 // sc.3=string_three|NULL|cc.2 assertEquals(2, children.size()); } else { assertEquals(0, children.size()); } for (Property nestedFeature : children) { Object value = nestedFeature.getValue(); assertNotNull(value); value = ((Collection) value).iterator().next(); assertTrue(value instanceof FeatureImpl); Feature feature = (Feature) value; assertNotNull(feature.getProperty("someAttribute").getValue()); } } // <AttributeMapping> // <targetAttribute>FEATURE_LINK[2]</targetAttribute> // <sourceExpression> // <OCQL>LINK_TWO</OCQL> // </sourceExpression> // </AttributeMapping> dsParams = new HashMap(); url = getClass().getResource(schemaBase + "SecondParentFeature.xml"); assertNotNull(url); dsParams.put("dbtype", "app-schema"); dsParams.put("url", url.toExternalForm()); dataAccess = DataAccessFinder.getDataStore(dsParams); assertNotNull(dataAccess); typeName = Types.typeName("http://example.com", "SecondParentFeature"); featureType = dataAccess.getSchema(typeName); assertNotNull(featureType); fSource = (FeatureSource) dataAccess.getFeatureSource(typeName); features = (FeatureCollection) fSource.getFeatures(); assertEquals(5, size(features)); iterator = features.features(); while (iterator.hasNext()) { Feature next = iterator.next(); Collection<Property> children = next.getProperties("nestedFeature"); if (next.getIdentifier().toString().equals("cc.2")) { // _=STRING:String,LINK_ONE:String,LINK_TWO:String // sc.1=string_one|cc.1|cc.2 // sc.2=string_two|cc.1|cc.2 // sc.3=string_three|NULL|cc.2 assertEquals(3, children.size()); } else { assertEquals(0, children.size()); } for (Property nestedFeature : children) { Object value = nestedFeature.getValue(); assertNotNull(value); value = ((Collection) value).iterator().next(); assertTrue(value instanceof FeatureImpl); Feature feature = (Feature) value; assertNotNull(feature.getProperty("someAttribute").getValue()); } } dataAccess.dispose(); } /** * Test chaining multi-valued by reference (xlink:href). It should result with multiple * attributes with no nested attributes, but only client property with xlink:href. * * @throws Exception */ @Test public void testMultiValuedPropertiesByRef() throws Exception { final String MF_PREFIX = "urn:cgi:feature:MappedFeature:"; final String OCCURENCE = "occurrence"; final Map<String, String> guToOccurrenceMap = new HashMap<String, String>() { { put("gu.25699", "mf1"); put("gu.25678", "mf2;mf3"); put("gu.25682", "mf4"); } }; ArrayList<String> processedFeatureIds = new ArrayList<String>(); FeatureIterator<Feature> guIterator = guFeatures.features(); while (guIterator.hasNext()) { Feature guFeature = (Feature) guIterator.next(); String guId = guFeature.getIdentifier().toString(); String[] mfIds = guToOccurrenceMap.get(guId).split(";"); Collection<Property> properties = guFeature.getProperties(OCCURENCE); assertEquals(mfIds.length, properties.size()); int propertyIndex = 0; for (Property property : properties) { Object clientProps = property.getUserData().get(Attributes.class); assertNotNull(clientProps); assertTrue(clientProps instanceof HashMap); Object hrefValue = ((Map) clientProps) .get(AbstractMappingFeatureIterator.XLINK_HREF_NAME); // ensure the right href:xlink is there assertEquals(MF_PREFIX + mfIds[propertyIndex], hrefValue); // ensure no attributes would be encoded assertTrue(((Collection) property.getValue()).isEmpty()); propertyIndex++; } processedFeatureIds.add(guId); } assertEquals(guToOccurrenceMap.size(), processedFeatureIds.size()); assertTrue(processedFeatureIds.containsAll(guToOccurrenceMap.keySet())); // clean ups guIterator.close(); } /** * Load all the data accesses. * * @return * @throws Exception */ private static void loadDataAccesses() throws Exception { /** * Load mapped feature data access */ Map dsParams = new HashMap(); URL url = FeatureChainingTest.class.getResource(schemaBase + "MappedFeaturePropertyfile.xml"); assertNotNull(url); dsParams.put("dbtype", "app-schema"); dsParams.put("url", url.toExternalForm()); DataAccess<FeatureType, Feature> mfDataAccess = DataAccessFinder.getDataStore(dsParams); assertNotNull(mfDataAccess); FeatureType mappedFeatureType = mfDataAccess.getSchema(MAPPED_FEATURE); assertNotNull(mappedFeatureType); mfSource = (FeatureSource) mfDataAccess.getFeatureSource(MAPPED_FEATURE); mfFeatures = (FeatureCollection) mfSource.getFeatures(); /** * Load geologic unit data access */ url = FeatureChainingTest.class.getResource(schemaBase + "GeologicUnit.xml"); assertNotNull(url); dsParams.put("url", url.toExternalForm()); DataAccess<FeatureType, Feature> guDataAccess = DataAccessFinder.getDataStore(dsParams); assertNotNull(guDataAccess); FeatureType guType = guDataAccess.getSchema(GEOLOGIC_UNIT); assertNotNull(guType); FeatureSource<FeatureType, Feature> guSource = (FeatureSource<FeatureType, Feature>) guDataAccess .getFeatureSource(GEOLOGIC_UNIT); guFeatures = (FeatureCollection) guSource.getFeatures(); /** * Non-feature types that are included in geologicUnit.xml should be loaded when geologic * unit data access is created */ // Composition Part cpFeatures = DataAccessRegistry.getFeatureSource(COMPOSITION_PART).getFeatures(); // CGI TermValue FeatureCollection<FeatureType, Feature> cgiFeatures = DataAccessRegistry.getFeatureSource( CGI_TERM_VALUE).getFeatures(); // ControlledConcept ccFeatures = DataAccessRegistry.getFeatureSource(CONTROLLED_CONCEPT).getFeatures(); assertEquals(4, size(mfFeatures)); assertEquals(3, size(guFeatures)); assertEquals(4, size(cpFeatures)); assertEquals(6, size(cgiFeatures)); } private static int size(FeatureCollection<FeatureType, Feature> features) { int size = 0; for (Iterator i = features.iterator(); i.hasNext(); i.next()) { size++; } return size; } }