docs: @Override
      public boolean isCapabilitySatisfied(Collection<ProvisioningFeatureDefinition> featureDefinitionsToCheck) {
          // If it isn't an autofeature, it's satisfied.
          if (!iAttr.isAutoFeature)
              return true;
  
          if (mfDetails == null)
              throw new IllegalStateException("Method called outside of provisioining operation or without a registered service");
  
          boolean isCapabilitySatisfied = true;
  
          Iterator<Filter> iter = mfDetails.getCapabilityFilters().iterator();
          Set<ProvisioningFeatureDefinition> satisfiedFeatureDefs = new HashSet<ProvisioningFeatureDefinition>();
  
          // Now we need to iterate over each of the filters, until we find we don't have a match.
          while (iter.hasNext() && isCapabilitySatisfied) {
              Filter checkFilter = iter.next();
              Iterator<ProvisioningFeatureDefinition> featureDefIter = featureDefinitionsToCheck.iterator();
  
              // Now for each filter, iterate over each of the FeatureDefinition headers, checking to see if we have a match.
              boolean featureMatch = false;
              while (featureDefIter.hasNext() && !featureMatch) {
                  ProvisioningFeatureDefinition featureDef = featureDefIter.next();
  
                  // If we've already satisfied a capability with this FeatureDefinition, we don't need to use it again
                  if (!satisfiedFeatureDefs.contains(featureDef)) {
  
                      // We have a mismatch between the key the filter is using to look up the feature name and the property containing the name in the
                      // headers. So we need to add a new property for osgi.identity (filter key) that contains the value of the 
                      // Subsystem-SymbolicName (manifest header).
                      // We also have to do this for the Subsystem-Type(manifest header) and the type (filter key).
                      Map<String, String> filterProps = new HashMap<String, String>();
  
                      filterProps.put(FeatureDefinitionUtils.FILTER_FEATURE_KEY, featureDef.getSymbolicName());
                      try {
                          filterProps.put(FeatureDefinitionUtils.FILTER_TYPE_KEY,
                                          mfDetails.getMainAttributeValue(FeatureDefinitionUtils.TYPE));
                      } catch (IOException e) {
                          // We should be well beyond any IOException issues.. 
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                              Tr.debug(tc, "IOException reading manifest attribute from {0}: {1}", iAttr.featureFile, e);
                          }
                          continue;
                      }
  
                      if (checkFilter.matches(filterProps)) {
                          satisfiedFeatureDefs.add(featureDef);
                          featureMatch = true;
                      }
                  }
              }
              // Once we've checked all the FeatureDefinitions, apply the result to the isCapabilitySatisfied boolean, 
              // so we stop processing as soon as we know we don't have a match.
              isCapabilitySatisfied = featureMatch;
          }
  
          return isCapabilitySatisfied;
      }