
001package ca.uhn.fhir.jpa.provider; 002 003/* 004 * #%L 005 * HAPI FHIR JPA Server 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.i18n.Msg; 024import ca.uhn.fhir.context.FhirContext; 025import ca.uhn.fhir.context.support.IValidationSupport; 026import ca.uhn.fhir.context.support.ValueSetExpansionOptions; 027import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; 028import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoValueSet; 029import ca.uhn.fhir.jpa.model.util.JpaConstants; 030import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; 031import ca.uhn.fhir.model.dstu2.composite.CodingDt; 032import ca.uhn.fhir.model.dstu2.resource.Parameters; 033import ca.uhn.fhir.model.dstu2.resource.ValueSet; 034import ca.uhn.fhir.model.primitive.BooleanDt; 035import ca.uhn.fhir.model.primitive.CodeDt; 036import ca.uhn.fhir.model.primitive.IdDt; 037import ca.uhn.fhir.model.primitive.StringDt; 038import ca.uhn.fhir.model.primitive.UriDt; 039import ca.uhn.fhir.rest.annotation.IdParam; 040import ca.uhn.fhir.rest.annotation.Operation; 041import ca.uhn.fhir.rest.annotation.OperationParam; 042import ca.uhn.fhir.rest.api.server.RequestDetails; 043import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 044import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; 045import ca.uhn.fhir.util.ParametersUtil; 046import org.hl7.fhir.instance.model.api.IBaseParameters; 047 048import javax.servlet.http.HttpServletRequest; 049 050import static org.apache.commons.lang3.StringUtils.isNotBlank; 051 052public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDstu2<ValueSet> { 053 054 055 @Operation(name = JpaConstants.OPERATION_EXPAND, idempotent = true) 056 public ValueSet expand( 057 HttpServletRequest theServletRequest, 058 @IdParam(optional = true) IdDt theId, 059 @OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet, 060 @OperationParam(name = "identifier", min = 0, max = 1) UriDt theIdentifier, 061 @OperationParam(name = "filter", min = 0, max = 1) StringDt theFilter, 062 RequestDetails theRequestDetails) { 063 064 boolean haveId = theId != null && theId.hasIdPart(); 065 boolean haveIdentifier = theIdentifier != null && isNotBlank(theIdentifier.getValue()); 066 boolean haveValueSet = theValueSet != null && theValueSet.isEmpty() == false; 067 068 if (!haveId && !haveIdentifier && !haveValueSet) { 069 throw new InvalidRequestException(Msg.code(1130) + "$expand operation at the type level (no ID specified) requires an identifier or a valueSet as a part of the request"); 070 } 071 072 if (moreThanOneTrue(haveId, haveIdentifier, haveValueSet)) { 073 throw new InvalidRequestException(Msg.code(1131) + "$expand must EITHER be invoked at the type level, or have an identifier specified, or have a ValueSet specified. Can not combine these options."); 074 } 075 076 startRequest(theServletRequest); 077 try { 078 IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao(); 079 if (haveId) { 080 return dao.expand(theId, toFilterString(theFilter), theRequestDetails); 081 } else if (haveIdentifier) { 082 return dao.expandByIdentifier(theIdentifier.getValue(), toFilterString(theFilter)); 083 } else { 084 return dao.expand(theValueSet, toFilterString(theFilter)); 085 } 086 087 } finally { 088 endRequest(theServletRequest); 089 } 090 } 091 092 private ValueSetExpansionOptions toFilterString(StringDt theFilter) { 093 if (theFilter != null) { 094 return ValueSetExpansionOptions.forOffsetAndCount(0, 1000).setFilter(theFilter.getValue()); 095 } 096 return null; 097 } 098 099 @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters = { 100 @OperationParam(name = "name", type = StringDt.class, min = 1), 101 @OperationParam(name = "version", type = StringDt.class, min = 0), 102 @OperationParam(name = "display", type = StringDt.class, min = 1), 103 @OperationParam(name = "abstract", type = BooleanDt.class, min = 1), 104 }) 105 public Parameters lookup( 106 HttpServletRequest theServletRequest, 107 @OperationParam(name = "code", min = 0, max = 1) CodeDt theCode, 108 @OperationParam(name = "system", min = 0, max = 1) UriDt theSystem, 109 @OperationParam(name = "coding", min = 0, max = 1) CodingDt theCoding, 110 RequestDetails theRequestDetails 111 ) { 112 113 startRequest(theServletRequest); 114 try { 115 IFhirResourceDaoCodeSystem<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoCodeSystem<ValueSet, CodingDt, CodeableConceptDt>) getDao(); 116 IValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, null, theRequestDetails); 117 if (result.isFound() == false) { 118 throw new ResourceNotFoundException(Msg.code(1132) + "Unable to find code[" + result.getSearchedForCode() + "] in system[" + result.getSearchedForSystem() + "]"); 119 } 120 Parameters retVal = new Parameters(); 121 retVal.addParameter().setName("name").setValue(new StringDt(result.getCodeSystemDisplayName())); 122 if (isNotBlank(result.getCodeSystemVersion())) { 123 retVal.addParameter().setName("version").setValue(new StringDt(result.getCodeSystemVersion())); 124 } 125 retVal.addParameter().setName("display").setValue(new StringDt(result.getCodeDisplay())); 126 retVal.addParameter().setName("abstract").setValue(new BooleanDt(result.isCodeIsAbstract())); 127 return retVal; 128 } finally { 129 endRequest(theServletRequest); 130 } 131 } 132 133 @Operation(name = JpaConstants.OPERATION_VALIDATE_CODE, idempotent = true, returnParameters = { 134 @OperationParam(name = "result", type = BooleanDt.class, min = 1), 135 @OperationParam(name = "message", type = StringDt.class), 136 @OperationParam(name = "display", type = StringDt.class) 137 }) 138 public Parameters validateCode( 139 HttpServletRequest theServletRequest, 140 @IdParam(optional = true) IdDt theId, 141 @OperationParam(name = "identifier", min = 0, max = 1) UriDt theValueSetIdentifier, 142 @OperationParam(name = "code", min = 0, max = 1) CodeDt theCode, 143 @OperationParam(name = "system", min = 0, max = 1) UriDt theSystem, 144 @OperationParam(name = "display", min = 0, max = 1) StringDt theDisplay, 145 @OperationParam(name = "coding", min = 0, max = 1) CodingDt theCoding, 146 @OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConceptDt theCodeableConcept, 147 RequestDetails theRequestDetails 148 ) { 149 150 startRequest(theServletRequest); 151 try { 152 IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao(); 153 IValidationSupport.CodeValidationResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails); 154 return (Parameters) toValidateCodeResult(getContext(), result); 155 } finally { 156 endRequest(theServletRequest); 157 } 158 } 159 160 public static IBaseParameters toValidateCodeResult(FhirContext theContext, IValidationSupport.CodeValidationResult theResult) { 161 IBaseParameters retVal = ParametersUtil.newInstance(theContext); 162 163 ParametersUtil.addParameterToParametersBoolean(theContext, retVal, "result", theResult.isOk()); 164 if (isNotBlank(theResult.getMessage())) { 165 ParametersUtil.addParameterToParametersString(theContext, retVal, "message", theResult.getMessage()); 166 } 167 if (isNotBlank(theResult.getDisplay())) { 168 ParametersUtil.addParameterToParametersString(theContext, retVal, "display", theResult.getDisplay()); 169 } 170 171 return retVal; 172 } 173 174 private static boolean moreThanOneTrue(boolean... theBooleans) { 175 boolean haveOne = false; 176 for (boolean next : theBooleans) { 177 if (next) { 178 if (haveOne) { 179 return true; 180 } else { 181 haveOne = true; 182 } 183 } 184 } 185 return false; 186 } 187 188 189}