001package ca.uhn.fhir.util; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.context.*; 024import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 025import org.hl7.fhir.instance.model.api.IBase; 026import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; 027import org.hl7.fhir.instance.model.api.IBaseResource; 028import org.hl7.fhir.instance.model.api.IPrimitiveType; 029 030import java.util.List; 031 032import static org.apache.commons.lang3.StringUtils.isNotBlank; 033 034/** 035 * Utilities for dealing with OperationOutcome resources across various model versions 036 */ 037public class OperationOutcomeUtil { 038 039 /** 040 * Add an issue to an OperationOutcome 041 * @param theCtx The fhir context 042 * @param theOperationOutcome The OO resource to add to 043 * @param theSeverity The severity (fatal | error | warning | information) 044 * @param theDetails The details string 045 * @param theCode 046 * @return Returns the newly added issue 047 */ 048 public static IBase addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails, String theLocation, String theCode) { 049 IBase issue = createIssue(theCtx, theOperationOutcome); 050 populateDetails(theCtx, issue, theSeverity, theDetails, theLocation, theCode); 051 return issue; 052 } 053 054 private static IBase createIssue(FhirContext theCtx, IBaseResource theOutcome) { 055 RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome); 056 BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue"); 057 BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) issueChild.getChildByName("issue"); 058 059 IBase issue = issueElement.newInstance(); 060 issueChild.getMutator().addValue(theOutcome, issue); 061 return issue; 062 } 063 064 public static String getFirstIssueDetails(FhirContext theCtx, IBaseOperationOutcome theOutcome) { 065 return getFirstIssueStringPart(theCtx, theOutcome, "diagnostics"); 066 } 067 068 public static String getFirstIssueLocation(FhirContext theCtx, IBaseOperationOutcome theOutcome) { 069 return getFirstIssueStringPart(theCtx, theOutcome, "location"); 070 } 071 072 private static String getFirstIssueStringPart(FhirContext theCtx, IBaseOperationOutcome theOutcome, String name) { 073 if (theOutcome == null) { 074 return null; 075 } 076 077 RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome); 078 BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue"); 079 080 List<IBase> issues = issueChild.getAccessor().getValues(theOutcome); 081 if (issues.isEmpty()) { 082 return null; 083 } 084 085 IBase issue = issues.get(0); 086 BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(issue.getClass()); 087 BaseRuntimeChildDefinition detailsChild = issueElement.getChildByName(name); 088 089 List<IBase> details = detailsChild.getAccessor().getValues(issue); 090 if (details.isEmpty()) { 091 return null; 092 } 093 return ((IPrimitiveType<?>) details.get(0)).getValueAsString(); 094 } 095 096 /** 097 * Returns true if the given OperationOutcome has 1 or more Operation.issue repetitions 098 */ 099 public static boolean hasIssues(FhirContext theCtx, IBaseOperationOutcome theOutcome) { 100 if (theOutcome == null) { 101 return false; 102 } 103 return getIssueCount(theCtx, theOutcome) > 0; 104 } 105 106 public static int getIssueCount(FhirContext theCtx, IBaseOperationOutcome theOutcome) { 107 RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome); 108 BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue"); 109 return issueChild.getAccessor().getValues(theOutcome).size(); 110 } 111 112 public static IBaseOperationOutcome newInstance(FhirContext theCtx) { 113 RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition("OperationOutcome"); 114 try { 115 return (IBaseOperationOutcome) ooDef.getImplementingClass().newInstance(); 116 } catch (InstantiationException e) { 117 throw new InternalErrorException("Unable to instantiate OperationOutcome", e); 118 } catch (IllegalAccessException e) { 119 throw new InternalErrorException("Unable to instantiate OperationOutcome", e); 120 } 121 } 122 123 private static void populateDetails(FhirContext theCtx, IBase theIssue, String theSeverity, String theDetails, String theLocation, String theCode) { 124 BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(theIssue.getClass()); 125 BaseRuntimeChildDefinition detailsChild; 126 detailsChild = issueElement.getChildByName("diagnostics"); 127 128 BaseRuntimeChildDefinition codeChild = issueElement.getChildByName("code"); 129 IPrimitiveType<?> codeElem = (IPrimitiveType<?>) codeChild.getChildByName("code").newInstance(codeChild.getInstanceConstructorArguments()); 130 codeElem.setValueAsString(theCode); 131 codeChild.getMutator().addValue(theIssue, codeElem); 132 133 BaseRuntimeElementDefinition<?> stringDef = detailsChild.getChildByName(detailsChild.getElementName()); 134 BaseRuntimeChildDefinition severityChild = issueElement.getChildByName("severity"); 135 136 IPrimitiveType<?> severityElem = (IPrimitiveType<?>) severityChild.getChildByName("severity").newInstance(severityChild.getInstanceConstructorArguments()); 137 severityElem.setValueAsString(theSeverity); 138 severityChild.getMutator().addValue(theIssue, severityElem); 139 140 IPrimitiveType<?> string = (IPrimitiveType<?>) stringDef.newInstance(); 141 string.setValueAsString(theDetails); 142 detailsChild.getMutator().setValue(theIssue, string); 143 144 addLocationToIssue(theCtx, theIssue, theLocation); 145 } 146 147 public static void addLocationToIssue(FhirContext theContext, IBase theIssue, String theLocation) { 148 if (isNotBlank(theLocation)) { 149 BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theIssue.getClass()); 150 BaseRuntimeChildDefinition locationChild = issueElement.getChildByName("location"); 151 IPrimitiveType<?> locationElem = (IPrimitiveType<?>) locationChild.getChildByName("location").newInstance(locationChild.getInstanceConstructorArguments()); 152 locationElem.setValueAsString(theLocation); 153 locationChild.getMutator().addValue(theIssue, locationElem); 154 } 155 } 156}