private void getNestedValues(
      NestedAttributeMapping mapping, List<Feature> features, List<Object> values, int nextIndex) {
    FeatureTypeMapping nextFMapping = null;
    for (Feature f : features) {
      try {
        nextFMapping = mapping.getFeatureTypeMapping(f);
      } catch (IOException e) {
        nextFMapping = null;
      }
      if (nextFMapping != null && mapping.isSameSource()) {
        // same root/database row, different mappings, used in
        // polymorphism
        List<Feature> nestedRoots = new ArrayList<Feature>(1);
        nestedRoots.add(f);
        List<Object> nestedValues =
            getValues(nextIndex, nextIndex, nestedRoots, nextFMapping, mapping);

        if (nestedValues != null) {
          values.addAll(nestedValues);
        }
        continue;
      }
      try {
        List<Feature> nestedFeatures = getNestedFeatures(f, mapping, nextFMapping);
        if (nestedFeatures == null || nestedFeatures.isEmpty()) {
          continue;
        }

        if (nextFMapping != null) {
          List<Object> nestedValues =
              getValues(nextIndex, nextIndex, nestedFeatures, nextFMapping, mapping);
          if (nestedValues != null) {
            values.addAll(nestedValues);
          }
        } else if (!nestedFeatures.isEmpty()) {
          throw new UnsupportedOperationException(
              "FeatureTypeMapping not found for "
                  + attPath
                  + ". This shouldn't happen if it's set in AppSchemaDataAccess mapping file!");
        }
      } 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
        continue;
      }
    }
  }
 private void getNestedClientProperties(
     NestedAttributeMapping mapping,
     List<Feature> features,
     List<Object> values,
     boolean isXlinkHref) {
   FeatureTypeMapping nextFMapping = null;
   for (Feature f : features) {
     try {
       nextFMapping = mapping.getFeatureTypeMapping(f);
       if (nextFMapping != null) {
         List<Feature> nestedFeatures;
         nestedFeatures = getNestedFeatures(f, mapping, nextFMapping);
         if (nestedFeatures == null || nestedFeatures.isEmpty()) {
           continue;
         }
         if (isXlinkHref) {
           // xlink:href mapping done in the root mapping file
           // there is no need to find attributeMapping in the nested feature type mapping
           getClientProperties(mapping, values, nestedFeatures);
         } else {
           List<AttributeMapping> nestedAttMappings =
               nextFMapping.getAttributeMappingsIgnoreIndex(mapping.getTargetXPath());
           AttributeMapping attMapping = null;
           boolean found = false;
           if (!nestedAttMappings.isEmpty()) {
             attMapping = nestedAttMappings.get(0);
             found = getClientProperties(attMapping, values, nestedFeatures);
           }
           if (!found && getLastStep().isId()) {
             setIdValues(attMapping, nestedFeatures, values);
           }
         }
       }
     } 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
       continue;
     }
   }
 }
 /**
  * Get nested features from a feature chaining attribute mapping
  *
  * @param root Root feature being evaluated
  * @param nestedMapping Attribute mapping for nested features
  * @param fMapping The root feature type mapping
  * @return list of nested features
  * @throws IOException
  */
 private List<Feature> getNestedFeatures(
     Feature root, NestedAttributeMapping nestedMapping, FeatureTypeMapping fMapping)
     throws IOException {
   Object fTypeName = nestedMapping.getNestedFeatureType(root);
   if (fTypeName == null || !(fTypeName instanceof Name)) {
     return null;
   }
   boolean hasSimpleFeatures = AppSchemaDataAccessRegistry.hasName((Name) fTypeName);
   // get foreign key
   Object val = getValue(nestedMapping.getSourceExpression(), root);
   if (val == null) {
     return null;
   }
   if (hasSimpleFeatures) {
     // normal app-schema mapping
     return nestedMapping.getInputFeatures(val, fMapping);
   } else {
     // app-schema with a complex feature source
     return nestedMapping.getFeatures(val, null, root);
   }
 }