}
private List<Object> getValues(Feature feature, NestedAttributeMapping nestedMapping,
StepList steps) {
List<Object> values = new ArrayList<Object>();
FeatureTypeMapping nextFMapping;
try {
nextFMapping = nestedMapping.getFeatureTypeMapping(feature);
} catch (IOException e) {
nextFMapping = null;
}
if (nextFMapping == null) {
// throw error unless this is polymorphism
if (nestedMapping.isConditional()) {
return values;
}
throw new UnsupportedOperationException("FeatureTypeMapping not found for " + attPath
+ ". Please revise PropertyName in your filter!");
}
List<Feature> nestedFeatures = new ArrayList<Feature>();
if (nestedMapping.isSameSource()) {
// same root/database row, different mappings, used in
// polymorphism
nestedFeatures = new ArrayList<Feature>();
nestedFeatures.add(feature);
} else {
// get nested features
try {
nestedFeatures = getNestedFeatures(feature, nestedMapping, nextFMapping);
} catch (IOException e) {
throw new RuntimeException("Failed evaluating filter expression: '" + attPath
+ "'. Caused by: " + e.getMessage());
} catch (IllegalArgumentException e) {
// might be a polymorphic case where it's looking for an attribute
// from another type
// that doesn't match this, but might match another database row
// so just continue
return values;
}
}
boolean isClientProperty = isClientProperty(steps);
StepList newSteps = null;
if (isClientProperty) {
// check for client properties for this mapping
newSteps = steps.subList(0, steps.size() - 1);
if (newSteps.size() == 1) {
// special case for client property for this NestedAttributeMapping
for (Feature f : nestedFeatures) {
values.addAll(getClientProperties(nestedMapping, f));
}
}
}
// skip element name that is mapped at the next FeatureTypeMapping
// except when it's a simple content
// if simple content, then there will be no type name in the xpath, e.g. when gml:name
// is
// feature chained the path stays as gml:name.. but if it's a complex type with complex
// content, e.g. gsml:specification the path will be
// gsml:specification/gsml:GeologicUnit/<some leaf attribute to filter by>
Name nextElementName = nextFMapping.getTargetFeature().getName();
// starting index for the next search
int startPos = -1;
if (Types.equals(nextElementName, steps.get(0).getName())) {
// simple contents where nested element name is the same as the nesting element
startPos = 0;
} else {
Step elementNameStep = steps.get(nestedMapping.getTargetXPath().size());
// support polymorphism
// check that element type matches the steps
if (Types.equals(nextElementName, elementNameStep.getName())) {
startPos = nestedMapping.getTargetXPath().size();
if (steps.size() > startPos + 1 && !steps.get(startPos + 1).isXmlAttribute()) {
// skip next element name for next evaluation
// except if the next step is a client property for that element name
// since we'd need the AttributeMapping for the client property
startPos++;
}
}
}
if (startPos > -1) {
newSteps = steps.subList(startPos, steps.size());
if (!newSteps.isEmpty()) {
List<NestedAttributeMapping> nestedMappings = nextFMapping.getNestedMappings();
if (!nestedMappings.isEmpty()) {
for (NestedAttributeMapping mapping : nestedMappings) {
if (newSteps.startsWith(mapping.getTargetXPath())) {
for (Feature f : nestedFeatures) {
// loop to this method
values.addAll(getValues(f, mapping, newSteps));
}
}
}
}
if (isClientProperty) {
// check for client properties
newSteps = newSteps.subList(0, newSteps.size() - 1);
}
boolean isXlinkHref = isClientProperty && isXlinkHref(steps);
List<AttributeMapping> attMappings = nextFMapping
.getAttributeMappingsIgnoreIndex(newSteps);
for (AttributeMapping attMapping : attMappings) {
if (isClientProperty) {
if (!(isXlinkHref && attMapping instanceof NestedAttributeMapping)) {
// if it's an xlink href,