protected void validateSofaMappings()

in uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AnalysisEngineDescription_impl.java [496:650]


  protected void validateSofaMappings() throws ResourceInitializationException {
    if (this.isPrimitive()) {
      return;
    }
    String aggName = this.getAnalysisEngineMetaData().getName();
    // build an actual Map (key: componentKey@/@componentSofa) from the sofa mappings
    // along the way check that all component keys and component sofa names exist
    Map<String, String> sofamap = new TreeMap<>();
    SofaMapping[] sofaMappings = this.getSofaMappings();
    if (sofaMappings != null) {
      for (int s = 0; s < sofaMappings.length; s++) {
        String componentKey = sofaMappings[s].getComponentKey();
        ResourceSpecifier componentSpec = getComponentSpecifier(componentKey);
        if (componentSpec == null) {
          throw new ResourceInitializationException(
                  ResourceInitializationException.SOFA_MAPPING_HAS_UNDEFINED_COMPONENT_KEY,
                  new Object[] { componentKey, sofaMappings[s].getAggregateSofaName(), aggName,
                      getSourceUrlString() });
        }
        String componentSofaName = sofaMappings[s].getComponentSofaName();
        if (componentSofaName == null) {
          componentSofaName = CAS.NAME_DEFAULT_SOFA;
        } else if (componentSpec instanceof AnalysisEngineDescription
                && !CAS.NAME_DEFAULT_SOFA.equals(componentSofaName)
                && !declaresSofa((AnalysisEngineDescription) componentSpec, componentSofaName)) {
          throw new ResourceInitializationException(
                  ResourceInitializationException.SOFA_MAPPING_HAS_UNDEFINED_COMPONENT_SOFA,
                  new Object[] { componentKey, componentSofaName,
                      sofaMappings[s].getAggregateSofaName(), aggName, getSourceUrlString() });
        }

        String compoundKey = sofaMappings[s].getComponentKey() + "@/@"
                + sofaMappings[s].getComponentSofaName();
        String aggSofaName = sofaMappings[s].getAggregateSofaName();
        // check for double-mapping
        String existingMapping = sofamap.get(compoundKey);
        if (existingMapping != null && !existingMapping.equals(aggSofaName)) {
          throw new ResourceInitializationException(
                  ResourceInitializationException.SOFA_MAPPING_CONFLICT,
                  new Object[] { sofaMappings[s].getComponentSofaName(),
                      sofaMappings[s].getComponentKey(), aggName, existingMapping, aggSofaName,
                      getSourceUrlString() });
        } else {
          sofamap.put(compoundKey, aggSofaName);
        }
      }
    }

    // Rules for SofAs:
    // (1) Each component output sofa must be mapped to an aggregate output sofa
    // (2) Each aggregate output sofa must be mapped to a component output sofa
    // (3) Each component input sofa must be mapped to an aggregate input sofa OR a component output
    // sofa
    // (4) Each aggregate input sofa must be mapped to a component input sofa

    // From (1) and (3) we derive that:
    // Each component input sofa must be mapped to an aggregate input sofa OR an aggregate output
    // sofa
    // (which is easier to check)

    // Exception: if aggregate contains a remote component, we cannot check that remote
    // component's input or output sofas, so rules (2) and (4) cannot be checked.

    boolean containsRemote = false;
    Set<String> correctlyMappedAggregateOutputs = new HashSet<>();
    Set<String> correctlyMappedAggregateInputs = new HashSet<>();

    Iterator<Map.Entry<String, ResourceSpecifier>> iter;
    try {
      iter = getDelegateAnalysisEngineSpecifiers().entrySet().iterator();
    } catch (InvalidXMLException e) {
      throw new ResourceInitializationException(e);
    }
    while (iter.hasNext()) {
      Map.Entry<String, ResourceSpecifier> entry = iter.next();
      String componentKey = entry.getKey();
      ResourceSpecifier delegateSpec = entry.getValue();

      if (delegateSpec instanceof AnalysisEngineDescription) {
        Capability[] caps = ((AnalysisEngineDescription) delegateSpec).getAnalysisEngineMetaData()
                .getCapabilities();
        for (int i = 0; i < caps.length; i++) {
          // all component output sofas must be mapped to aggregate output sofas
          String[] outputSofas = caps[i].getOutputSofas();
          for (int j = 0; j < outputSofas.length; j++) {
            String aggSofa = sofamap.get(componentKey + "@/@" + outputSofas[j]);
            if (aggSofa == null) // no declared mapping, name remains unchanged
            {
              aggSofa = outputSofas[j];
            }
            if (!capabilitiesContainSofa(aggSofa, true)) {
              throw new ResourceInitializationException(
                      ResourceInitializationException.OUTPUT_SOFA_NOT_DECLARED_IN_AGGREGATE,
                      new Object[] { outputSofas[j], componentKey, aggName, getSourceUrlString() });
            }
            correctlyMappedAggregateOutputs.add(aggSofa);
          }

          // all component input sofas must be mapped to aggregate input OR output sofas
          String[] inputSofas = caps[i].getInputSofas();
          for (int j = 0; j < inputSofas.length; j++) {
            String aggSofa = sofamap.get(componentKey + "@/@" + inputSofas[j]);
            if (aggSofa == null) // no declared mapping, name remains unchanged
            {
              aggSofa = inputSofas[j];
            }
            if (!capabilitiesContainSofa(aggSofa, false)
                    && !capabilitiesContainSofa(aggSofa, true)) {
              throw new ResourceInitializationException(
                      ResourceInitializationException.INPUT_SOFA_HAS_NO_SOURCE,
                      new Object[] { inputSofas[j], componentKey, aggName, getSourceUrlString() });
            }
            correctlyMappedAggregateInputs.add(aggSofa);
          }

          // also check default text sofa
          String aggDefSofa = sofamap.get(componentKey + "@/@" + CAS.NAME_DEFAULT_SOFA);
          if (aggDefSofa != null) {
            if (capabilitiesContainSofa(aggDefSofa, true)) {
              correctlyMappedAggregateOutputs.add(aggDefSofa);
            } else {
              correctlyMappedAggregateInputs.add(aggDefSofa);
            }
          }
        }
      } // delegateSpec is not an AnalysisEngineDescription
      else {
        containsRemote = true;
      }
    }

    if (!containsRemote) {
      // check that all aggregate outputs and inputs were mapped correclty to
      // component inputs/outputs
      Capability[] caps = this.getAnalysisEngineMetaData().getCapabilities();
      for (int i = 0; i < caps.length; i++) {
        String[] sofas = caps[i].getOutputSofas();
        for (int j = 0; j < sofas.length; j++) {
          if (!correctlyMappedAggregateOutputs.contains(sofas[j])) {
            throw new ResourceInitializationException(
                    ResourceInitializationException.AGGREGATE_SOFA_NOT_MAPPED,
                    new Object[] { sofas[j], aggName, getSourceUrlString() });
          }
        }
        sofas = caps[i].getInputSofas();
        for (int j = 0; j < sofas.length; j++) {
          if (!correctlyMappedAggregateInputs.contains(sofas[j])) {
            throw new ResourceInitializationException(
                    ResourceInitializationException.AGGREGATE_SOFA_NOT_MAPPED,
                    new Object[] { sofas[j], aggName, getSourceUrlString() });
          }
        }
      }
    }
  }