All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hl7.fhir.r5.terminologies.utilities.ValueSetProcessBase Maven / Gradle / Ivy

package org.hl7.fhir.r5.terminologies.utilities;

import java.util.ArrayList;
import java.util.List;

import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ITerminologyOperationDetails;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.UrlType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.UserDataNames;
import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage;
import org.hl7.fhir.utilities.StandardsStatus;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;

@MarkedToMoveToAdjunctPackage
public class ValueSetProcessBase {

  public static class TerminologyOperationDetails implements ITerminologyOperationDetails {

    private List supplements;

    public TerminologyOperationDetails(List supplements) {
      super();
      this.supplements = supplements;
    }

    @Override
    public void seeSupplement(CodeSystem supp) {
      supplements.remove(supp.getUrl());
      supplements.remove(supp.getVersionedUrl());
    }
  }
  
  public enum OpIssueCode {
    NotInVS, ThisNotInVS, InvalidCode, Display, DisplayComment, NotFound, CodeRule, VSProcessing, InferFailed, StatusCheck, InvalidData;
    
    public String toCode() {
      switch (this) {
      case CodeRule: return "code-rule";
      case Display: return "invalid-display";
      case DisplayComment: return "display-comment";
      case InferFailed: return "cannot-infer";
      case InvalidCode: return "invalid-code";
      case NotFound: return "not-found";
      case NotInVS: return "not-in-vs";
      case InvalidData: return "invalid-data";
      case StatusCheck: return "status-check";
      case ThisNotInVS: return "this-code-not-in-vs";
      case VSProcessing: return "vs-invalid";
      default:
        return "??";      
      }
    }
  }
  protected IWorkerContext context;
  private ContextUtilities cu;
  protected TerminologyOperationContext opContext;
  protected List requiredSupplements = new ArrayList<>();
  
  protected ValueSetProcessBase(IWorkerContext context, TerminologyOperationContext opContext) {
    super();
    this.context = context;
    this.opContext = opContext;
  }
  public static class AlternateCodesProcessingRules {
    private boolean all;
    private List uses = new ArrayList<>();
    
    public AlternateCodesProcessingRules(boolean b) {
      all = b;
    }

    private void seeParameter(DataType value) {
      if (value != null) {
        if (value instanceof BooleanType) {
          all = ((BooleanType) value).booleanValue();
          uses.clear();
        } else if (value.isPrimitive()) {
          String s = value.primitiveValue();
          if (!Utilities.noString(s)) {
            uses.add(s);
          }
        }
      }
    }

    public void seeParameters(Parameters pp) {
      for (ParametersParameterComponent p : pp.getParameter()) {
        String name = p.getName();
        if ("includeAlternateCodes".equals(name)) {
          DataType value = p.getValue();
          seeParameter(value);
        }
      }
    }

    public void seeValueSet(ValueSet vs) {
      if (vs != null) {
        for (Extension ext : vs.getCompose().getExtension()) {
          if ("http://hl7.org/fhir/tools/StructureDefinion/valueset-expansion-param".equals(ext.getUrl())) {
            String name = ext.getExtensionString("name");
            Extension value = ext.getExtensionByUrl("value");
            if ("includeAlternateCodes".equals(name) && value != null && value.hasValue()) {
              seeParameter(value.getValue());
            }
          }
        }
      }
    }

    public boolean passes(List extensions) {
      if (all) {
        return true;
      }

      for (Extension ext : extensions) {
        if (ToolingExtensions.EXT_CS_ALTERNATE_USE.equals(ext.getUrl())) {
          if (ext.hasValueCoding() && Utilities.existsInList(ext.getValueCoding().getCode(), uses)) {
            return true;
          }
        }
      }
      return false;
    }
  }


  protected List makeIssue(IssueSeverity level, IssueType type, String location, String message, OpIssueCode code, String server) {
    return makeIssue(level, type, location, message, code, server, null);
  }
  protected List makeIssue(IssueSeverity level, IssueType type, String location, String message, OpIssueCode code, String server, String msgId) {
    OperationOutcomeIssueComponent result = new OperationOutcomeIssueComponent();
    switch (level) {
    case ERROR:
      result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR);
      break;
    case FATAL:
      result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.FATAL);
      break;
    case INFORMATION:
      result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION);
      break;
    case WARNING:
      result.setSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING);
      break;
    }
    result.setCode(type);
    if (location != null) {
      result.addLocation(location);
      result.addExpression(location);
    }
    result.getDetails().setText(message);
    if (code != null) {
      result.getDetails().addCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", code.toCode(), null);
    }
    if (server != null) {
      result.addExtension(ToolingExtensions.EXT_ISSUE_SERVER, new UrlType(server));
    }
    if (msgId != null) {      
      result.addExtension(ToolingExtensions.EXT_ISSUE_MSG_ID, new StringType(msgId));
    }
    ArrayList list = new ArrayList<>();
    list.add(result);
    return list;
  }
  
  public void checkCanonical(List issues, String path, CanonicalResource resource, CanonicalResource source) {
    if (resource != null) {
      StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
      if (standardsStatus == StandardsStatus.DEPRECATED) {
        addToIssues(issues, makeStatusIssue(path, "deprecated", I18nConstants.MSG_DEPRECATED, resource));
      } else if (standardsStatus == StandardsStatus.WITHDRAWN) {
        addToIssues(issues, makeStatusIssue(path, "withdrawn", I18nConstants.MSG_WITHDRAWN, resource));
      } else if (resource.getStatus() == PublicationStatus.RETIRED) {
        addToIssues(issues, makeStatusIssue(path, "retired", I18nConstants.MSG_RETIRED, resource));
      } else if (source != null) {
        if (resource.getExperimental() && !source.getExperimental()) {
          addToIssues(issues, makeStatusIssue(path, "experimental", I18nConstants.MSG_EXPERIMENTAL, resource));
        } else if ((resource.getStatus() == PublicationStatus.DRAFT || standardsStatus == StandardsStatus.DRAFT)
            && !(source.getStatus() == PublicationStatus.DRAFT || ToolingExtensions.getStandardsStatus(source) == StandardsStatus.DRAFT)) {
          addToIssues(issues, makeStatusIssue(path, "draft", I18nConstants.MSG_DRAFT, resource));
        }
      } else {
        if (resource.getExperimental()) {
          addToIssues(issues, makeStatusIssue(path, "experimental", I18nConstants.MSG_EXPERIMENTAL, resource));
        } else if ((resource.getStatus() == PublicationStatus.DRAFT || standardsStatus == StandardsStatus.DRAFT)) {
          addToIssues(issues, makeStatusIssue(path, "draft", I18nConstants.MSG_DRAFT, resource));
        }
      }
    }
  }

  private List makeStatusIssue(String path, String id, String msg, CanonicalResource resource) {
    List iss = makeIssue(IssueSeverity.INFORMATION, IssueType.BUSINESSRULE, null, context.formatMessage(msg, resource.getVersionedUrl(), null, resource.fhirType()), OpIssueCode.StatusCheck, null);

    // this is a testing hack - see TerminologyServiceTests
    iss.get(0).setUserData(UserDataNames.tx_status_msg_name, "warning-"+id);
    iss.get(0).setUserData(UserDataNames.tx_status_msg_value, new UriType(resource.getVersionedUrl()));
    ToolingExtensions.setStringExtension(iss.get(0), ToolingExtensions.EXT_ISSUE_MSG_ID, msg);
    
    return iss;
  }
  
  private void addToIssues(List issues, List toAdd) {
    for (OperationOutcomeIssueComponent t : toAdd) {
      boolean found = false;
      for (OperationOutcomeIssueComponent i : issues) {
        if (i.getSeverity() == t.getSeverity() && i.getCode() == t.getCode() && i.getDetails().getText().equals(t.getDetails().getText())) { // ignore location
          found = true;
        }
      }
      if (!found) {
        issues.add(t);
      }
    }    
  }

  public void checkCanonical(ValueSetExpansionComponent params, CanonicalResource resource, ValueSet source) {
    if (resource != null) {
      StandardsStatus standardsStatus = ToolingExtensions.getStandardsStatus(resource);
      if (standardsStatus == StandardsStatus.DEPRECATED) {
        if (!params.hasParameterValue("warning-deprecated", resource.getVersionedUrl())) {
          params.addParameter("warning-deprecated", new UriType(resource.getVersionedUrl()));
        } 
      } else if (standardsStatus == StandardsStatus.WITHDRAWN) {
        if (!params.hasParameterValue("warning-withdrawn", resource.getVersionedUrl())) {
          params.addParameter("warning-withdrawn", new UriType(resource.getVersionedUrl()));
        } 
      } else if (resource.getStatus() == PublicationStatus.RETIRED) {
        if (!params.hasParameterValue("warning-retired", resource.getVersionedUrl())) {
          params.addParameter("warning-retired", new UriType(resource.getVersionedUrl()));
        } 
      } else if (resource.getExperimental() && !source.getExperimental()) {
        if (!params.hasParameterValue("warning-experimental", resource.getVersionedUrl())) {
          params.addParameter("warning-experimental", new UriType(resource.getVersionedUrl()));
        }         
      } else if ((resource.getStatus() == PublicationStatus.DRAFT || standardsStatus == StandardsStatus.DRAFT)
          && !(source.getStatus() == PublicationStatus.DRAFT || ToolingExtensions.getStandardsStatus(source) == StandardsStatus.DRAFT)) {
        if (!params.hasParameterValue("warning-draft", resource.getVersionedUrl())) {
          params.addParameter("warning-draft", new UriType(resource.getVersionedUrl()));
        }         
      }
    }
  }

  public TerminologyOperationContext getOpContext() {
    return opContext;
  }

                         
  public ContextUtilities getCu() {
    if (cu == null) {
      cu = new ContextUtilities(context);
    }
    return cu;
  }


  public String removeSupplement(String s) {
    requiredSupplements.remove(s);
    if (s.contains("|")) {
      s = s.substring(0, s.indexOf("|"));
      requiredSupplements.remove(s);
    }
    return s;
  }
  
  protected AlternateCodesProcessingRules altCodeParams = new AlternateCodesProcessingRules(false);
  protected AlternateCodesProcessingRules allAltCodes = new AlternateCodesProcessingRules(true);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy