Author: ang05a Date: 2010-10-29 00:26:59 -0700 (Fri, 29 Oct 2010) New Revision: 36304 Modified: trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/ComplexFeatureConstants.java trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/DataAccessMappingFeatureIterator.java trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/filter/XPath.java trunk/modules/unsupported/app-schema/app-schema/src/test/java/org/geotools/data/complex/XmlDataStoreTest.java Log: GEOT-3304: App-schema: client properties not encoded correctly with polymorphism Modified: trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/ComplexFeatureConstants.java =================================================================== --- trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/ComplexFeatureConstants.java 2010-10-29 06:12:56 UTC (rev 36303) +++ trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/ComplexFeatureConstants.java 2010-10-29 07:26:59 UTC (rev 36304) @@ -38,7 +38,7 @@ /** * Static attribute name used to link different feature types. */ - final public static Name FEATURE_CHAINING_LINK_NAME = new NameImpl("FEATURE_LINK"); + public static final Name FEATURE_CHAINING_LINK_NAME = new NameImpl("FEATURE_LINK"); /** * Static attribute descriptor used to link different feature types. This attribute won't appear @@ -46,7 +46,7 @@ * more than one instances to be used in one type that can be chained by different parent * feature types. */ - final public static PropertyDescriptor FEATURE_CHAINING_LINK = new AttributeDescriptorImpl( + public static final PropertyDescriptor FEATURE_CHAINING_LINK = new AttributeDescriptorImpl( XSSchema.STRING_TYPE, FEATURE_CHAINING_LINK_NAME, 0, -1, true, null); /** @@ -66,4 +66,10 @@ * Hints key for xlink:href used in ToXlinkHrefFunction */ public static final Hints.Key STRING_KEY = new Hints.Key(String.class); + + /** + * User data key to indicate the specified attribute index in the mapping file for the case of + * multi-valued properties, e.g. gml:name[2] + */ + public static final String MAPPED_ATTRIBUTE_INDEX = "MAPPED_ATTRIBUTE_INDEX"; } Modified: trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/DataAccessMappingFeatureIterator.java =================================================================== --- trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/DataAccessMappingFeatureIterator.java 2010-10-29 06:12:56 UTC (rev 36303) +++ trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/DataAccessMappingFeatureIterator.java 2010-10-29 07:26:59 UTC (rev 36304) @@ -484,8 +484,9 @@ setClientProperties(instance, source, clientPropsMappings); for (AttributeMapping mapping : polymorphicMappings) { if (isTopLevelmapping(polymorphicTypeName, mapping.getTargetXPath())) { - // ignore the top level mapping for the Feature itself - // as it was already set + // if the top level mapping for the Feature itself, the attribute instance + // has already been created.. just need to set the client properties + setClientProperties(instance, source, mapping.getClientProperties()); continue; } setAttributeValue(instance, source, mapping); @@ -579,6 +580,10 @@ return; } final Map<Name, Object> targetAttributes = new HashMap<Name, Object>(); + if (target.getUserData().containsValue(Attributes.class)) { + targetAttributes.putAll((Map<? extends Name, ? extends Object>) target.getUserData() + .get(Attributes.class)); + } for (Map.Entry<Name, Expression> entry : clientProperties.entrySet()) { Name propName = entry.getKey(); Object propExpr = entry.getValue(); Modified: trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/filter/XPath.java =================================================================== --- trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/filter/XPath.java 2010-10-29 06:12:56 UTC (rev 36303) +++ trunk/modules/unsupported/app-schema/app-schema/src/main/java/org/geotools/data/complex/filter/XPath.java 2010-10-29 07:26:59 UTC (rev 36304) @@ -320,7 +320,7 @@ sb.append(attributeName.getPrefix()).append(':'); } sb.append(attributeName.getLocalPart()); - if (isIndexed || index > 1) { + if (isIndexed) { // we want to print index = 1 as well if specified // so filtering on the first index doesn't return all // e.g. gml:name[1] doesn't get translated to @@ -696,14 +696,14 @@ return null; } } - int index = currStep.getIndex(); + int index = currStep.isIndexed ? currStep.getIndex() : -1; Attribute attribute = setValue(currStepDescriptor, id, value, index, parent, targetNodeType, isXlinkRef); return attribute; } else { // parent = appendComplexProperty(parent, currStep, // currStepDescriptor); - int index = currStep.getIndex(); + int index = currStep.isIndexed ? currStep.getIndex() : -1; parent = setValue(currStepDescriptor, null, new ArrayList<Property>(), index, parent, null, isXlinkRef); } @@ -717,22 +717,60 @@ // adapt value to context Object convertedValue = convertValue(descriptor, value); Attribute leafAttribute = null; - final Name attributeName = descriptor.getName(); - if (parent instanceof ComplexAttribute) { - Object currStepValue = ((ComplexAttribute) parent).getProperties(attributeName); - if (!isXlinkRef) { - // skip this process if the attribute would only contain xlink:ref - // that is chained, because it won't contain any values, and we - // want to create a new empty leaf attribute + final Name attributeName = descriptor.getName(); + if (!isXlinkRef) { + // skip this process if the attribute would only contain xlink:ref + // that is chained, because it won't contain any values, and we + // want to create a new empty leaf attribute + if (parent instanceof ComplexAttribute) { + Object currStepValue = ((ComplexAttribute) parent).getProperties(attributeName); if (currStepValue instanceof Collection) { List<Attribute> values = new ArrayList((Collection) currStepValue); - if (isEmpty(convertedValue) && values.size() >= index) { - leafAttribute = (Attribute) values.get(index - 1); - } - for (Attribute stepValue : values) { - // eliminate duplicates in case the values come from denormalized view.. - if (stepValue.getValue().equals(convertedValue)) { - return stepValue; + if (!values.isEmpty()) { + if (isEmpty(convertedValue)) { + // when attribute is empty, it is probably just a parent of a leaf + // attribute + // it could already exist from another attribute mapping for a different + // leaf + // e.g. 2 different attribute mappings: + // sa:relatedObservation/om:Observation/om:parameter[2]/swe:Time/swe:uom + // sa:relatedObservation/om:Observation/om:parameter[2]/swe:Time/swe:value + // and this could be processing om:parameter[2] the second time for + // swe:value + // so we need to find it if it already exists + if (index > -1) { + // get the attribute of specified index + for (Attribute stepValue : values) { + if (stepValue.getUserData().containsKey( + ComplexFeatureConstants.MAPPED_ATTRIBUTE_INDEX)) { + if (index == Integer.parseInt( + String.valueOf(stepValue.getUserData().get( + ComplexFeatureConstants.MAPPED_ATTRIBUTE_INDEX)))) { + return stepValue; + } + } + } + } else { + // get the last existing node + return values.get(values.size() - 1); + } + } else { + for (Attribute stepValue : values) { + // eliminate duplicates in case the values come from denormalized + // view.. + boolean sameIndex = true; + if (index > -1) { + if (stepValue.getUserData().containsKey( + ComplexFeatureConstants.MAPPED_ATTRIBUTE_INDEX)) { + sameIndex = (index == Integer.parseInt( + String.valueOf(stepValue.getUserData().get( + ComplexFeatureConstants.MAPPED_ATTRIBUTE_INDEX)))); + } + } + if (sameIndex && stepValue.getValue().equals(convertedValue)) { + return stepValue; + } + } } } } else if (currStepValue instanceof Attribute) { @@ -768,6 +806,11 @@ } else { leafAttribute = builder.add(id, convertedValue, attributeName); } + if (index > -1) { + // set attribute index if specified so it can be retrieved later for grouping + leafAttribute.getUserData().put(ComplexFeatureConstants.MAPPED_ATTRIBUTE_INDEX, + index); + } List newValue = new ArrayList(); newValue.addAll((Collection) parent.getValue()); newValue.add(leafAttribute); Modified: trunk/modules/unsupported/app-schema/app-schema/src/test/java/org/geotools/data/complex/XmlDataStoreTest.java =================================================================== --- trunk/modules/unsupported/app-schema/app-schema/src/test/java/org/geotools/data/complex/XmlDataStoreTest.java 2010-10-29 06:12:56 UTC (rev 36303) +++ trunk/modules/unsupported/app-schema/app-schema/src/test/java/org/geotools/data/complex/XmlDataStoreTest.java 2010-10-29 07:26:59 UTC (rev 36304) @@ -83,6 +83,7 @@ import org.opengis.feature.type.Name; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; +import org.xml.sax.Attributes; import org.xml.sax.helpers.NamespaceSupport; /** @@ -249,13 +250,13 @@ at = attNameList.get(0); assertEquals("Unit Name1248396531312 UC1248396531312 description name", getValueForAttribute(at)); - assertEquals(1, at.getUserData().size()); + assertEquals(1, ((Map) at.getUserData().get(Attributes.class)).size()); assertEquals("gsv:NameSpace", getUserDataForAttribute(at, new NameImpl("codeSpace"))); // Second one has a value and a single attribute--codeSpace at = attNameList.get(1); assertEquals("urn:cgi:feature:GSV:1679161021439131319", getValueForAttribute(at)); - assertTrue(at.getUserData() != null && at.getUserData().size() == 1); + assertTrue(at.getUserData() != null && ((Map) at.getUserData().get(Attributes.class)).size() == 1); assertEquals("gsv:NameSpace", getUserDataForAttribute(at, new NameImpl("codeSpace"))); // *************************************************************************************** @@ -341,8 +342,8 @@ private String getUserDataForAttribute(Attribute sv, Name key) { String value = null; Map<Object, Object> userData = (Map<Object, Object>) sv.getUserData(); - if (userData.size() > 0) { - Map map = (Map) userData.values().iterator().next(); + if (userData.containsKey(Attributes.class)) { + Map map = (Map) userData.get(Attributes.class); value = (String) map.get(key); } return value; |