001package ca.uhn.fhir.jpa.provider.r5;
002
003import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
004import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
005import ca.uhn.fhir.jpa.model.util.JpaConstants;
006import ca.uhn.fhir.jpa.provider.BaseJpaSystemProviderDstu2Plus;
007import ca.uhn.fhir.model.api.annotation.Description;
008import ca.uhn.fhir.rest.annotation.IdParam;
009import ca.uhn.fhir.rest.annotation.Operation;
010import ca.uhn.fhir.rest.annotation.OperationParam;
011import ca.uhn.fhir.rest.annotation.Transaction;
012import ca.uhn.fhir.rest.annotation.TransactionParam;
013import ca.uhn.fhir.rest.api.server.RequestDetails;
014import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
015import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
016import org.hl7.fhir.instance.model.api.IBaseBundle;
017import org.hl7.fhir.instance.model.api.IIdType;
018import org.hl7.fhir.r5.model.BooleanType;
019import org.hl7.fhir.r5.model.Bundle;
020import org.hl7.fhir.r5.model.DecimalType;
021import org.hl7.fhir.r5.model.IntegerType;
022import org.hl7.fhir.r5.model.Meta;
023import org.hl7.fhir.r5.model.Parameters;
024import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
025import org.hl7.fhir.r5.model.StringType;
026import org.springframework.beans.factory.annotation.Autowired;
027import org.springframework.beans.factory.annotation.Qualifier;
028
029import javax.servlet.http.HttpServletRequest;
030import java.util.Collections;
031import java.util.List;
032import java.util.Map;
033import java.util.Map.Entry;
034import java.util.TreeMap;
035
036import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
037import static org.apache.commons.lang3.StringUtils.isBlank;
038
039/*
040 * #%L
041 * HAPI FHIR JPA Server
042 * %%
043 * Copyright (C) 2014 - 2021 Smile CDR, Inc.
044 * %%
045 * Licensed under the Apache License, Version 2.0 (the "License");
046 * you may not use this file except in compliance with the License.
047 * You may obtain a copy of the License at
048 *
049 *      http://www.apache.org/licenses/LICENSE-2.0
050 *
051 * Unless required by applicable law or agreed to in writing, software
052 * distributed under the License is distributed on an "AS IS" BASIS,
053 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
054 * See the License for the specific language governing permissions and
055 * limitations under the License.
056 * #L%
057 */
058
059public class JpaSystemProviderR5 extends BaseJpaSystemProviderDstu2Plus<Bundle, Meta> {
060
061        @Autowired()
062        @Qualifier("mySystemDaoR5")
063        private IFhirSystemDao<Bundle, Meta> mySystemDao;
064
065        @Autowired(required = false)
066        private IFulltextSearchSvc mySearchDao;
067
068        @Operation(name = JpaConstants.OPERATION_EXPUNGE, idempotent = false, returnParameters = {
069                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
070        })
071        public Parameters expunge(
072                @IdParam IIdType theIdParam,
073                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
074                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
075                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions,
076                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_EVERYTHING) BooleanType theExpungeEverything,
077                RequestDetails theRequestDetails
078        ) {
079                org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(theLimit, theExpungeDeletedResources, theExpungeOldVersions, theExpungeEverything, theRequestDetails);
080                return org.hl7.fhir.convertors.conv40_50.Parameters40_50.convertParameters(parameters);
081        }
082
083        @Operation(name = JpaConstants.OPERATION_EXPUNGE, idempotent = false, returnParameters = {
084                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
085        })
086        public Parameters expunge(
087                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
088                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
089                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions,
090                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_EVERYTHING) BooleanType theExpungeEverything,
091                RequestDetails theRequestDetails
092        ) {
093                org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(theLimit, theExpungeDeletedResources, theExpungeOldVersions, theExpungeEverything, theRequestDetails);
094                return org.hl7.fhir.convertors.conv40_50.Parameters40_50.convertParameters(parameters);
095        }
096
097        // This is generated by hand:
098        // ls hapi-fhir-structures-dstu2/target/generated-sources/tinder/ca/uhn/fhir/model/dstu2/resource/ | sort | sed "s/.java//" | sed "s/^/@OperationParam(name=\"/" | sed "s/$/\", type=IntegerType.class, min=0, max=1),/"
099        @Operation(name = JpaConstants.OPERATION_GET_RESOURCE_COUNTS, idempotent = true, returnParameters = {
100                @OperationParam(name = "AllergyIntolerance", type = IntegerType.class, min = 0, max = 1),
101                @OperationParam(name = "Appointment", type = IntegerType.class, min = 0, max = 1),
102                @OperationParam(name = "AppointmentResponse", type = IntegerType.class, min = 0, max = 1),
103                @OperationParam(name = "AuditEvent", type = IntegerType.class, min = 0, max = 1),
104                @OperationParam(name = "Basic", type = IntegerType.class, min = 0, max = 1),
105                @OperationParam(name = "Binary", type = IntegerType.class, min = 0, max = 1),
106                @OperationParam(name = "BodySite", type = IntegerType.class, min = 0, max = 1),
107                @OperationParam(name = "Bundle", type = IntegerType.class, min = 0, max = 1),
108                @OperationParam(name = "CarePlan", type = IntegerType.class, min = 0, max = 1),
109                @OperationParam(name = "CarePlan2", type = IntegerType.class, min = 0, max = 1),
110                @OperationParam(name = "Claim", type = IntegerType.class, min = 0, max = 1),
111                @OperationParam(name = "ClaimResponse", type = IntegerType.class, min = 0, max = 1),
112                @OperationParam(name = "ClinicalImpression", type = IntegerType.class, min = 0, max = 1),
113                @OperationParam(name = "Communication", type = IntegerType.class, min = 0, max = 1),
114                @OperationParam(name = "CommunicationRequest", type = IntegerType.class, min = 0, max = 1),
115                @OperationParam(name = "Composition", type = IntegerType.class, min = 0, max = 1),
116                @OperationParam(name = "ConceptMap", type = IntegerType.class, min = 0, max = 1),
117                @OperationParam(name = "Condition", type = IntegerType.class, min = 0, max = 1),
118                @OperationParam(name = "Conformance", type = IntegerType.class, min = 0, max = 1),
119                @OperationParam(name = "Contract", type = IntegerType.class, min = 0, max = 1),
120                @OperationParam(name = "Contraindication", type = IntegerType.class, min = 0, max = 1),
121                @OperationParam(name = "Coverage", type = IntegerType.class, min = 0, max = 1),
122                @OperationParam(name = "DataElement", type = IntegerType.class, min = 0, max = 1),
123                @OperationParam(name = "Device", type = IntegerType.class, min = 0, max = 1),
124                @OperationParam(name = "DeviceComponent", type = IntegerType.class, min = 0, max = 1),
125                @OperationParam(name = "DeviceMetric", type = IntegerType.class, min = 0, max = 1),
126                @OperationParam(name = "DeviceUseRequest", type = IntegerType.class, min = 0, max = 1),
127                @OperationParam(name = "DeviceUseStatement", type = IntegerType.class, min = 0, max = 1),
128                @OperationParam(name = "DiagnosticOrder", type = IntegerType.class, min = 0, max = 1),
129                @OperationParam(name = "DiagnosticReport", type = IntegerType.class, min = 0, max = 1),
130                @OperationParam(name = "DocumentManifest", type = IntegerType.class, min = 0, max = 1),
131                @OperationParam(name = "DocumentReference", type = IntegerType.class, min = 0, max = 1),
132                @OperationParam(name = "EligibilityRequest", type = IntegerType.class, min = 0, max = 1),
133                @OperationParam(name = "EligibilityResponse", type = IntegerType.class, min = 0, max = 1),
134                @OperationParam(name = "Encounter", type = IntegerType.class, min = 0, max = 1),
135                @OperationParam(name = "EnrollmentRequest", type = IntegerType.class, min = 0, max = 1),
136                @OperationParam(name = "EnrollmentResponse", type = IntegerType.class, min = 0, max = 1),
137                @OperationParam(name = "EpisodeOfCare", type = IntegerType.class, min = 0, max = 1),
138                @OperationParam(name = "ExplanationOfBenefit", type = IntegerType.class, min = 0, max = 1),
139                @OperationParam(name = "FamilyMemberHistory", type = IntegerType.class, min = 0, max = 1),
140                @OperationParam(name = "Flag", type = IntegerType.class, min = 0, max = 1),
141                @OperationParam(name = "Goal", type = IntegerType.class, min = 0, max = 1),
142                @OperationParam(name = "Group", type = IntegerType.class, min = 0, max = 1),
143                @OperationParam(name = "HealthcareService", type = IntegerType.class, min = 0, max = 1),
144                @OperationParam(name = "ImagingObjectSelection", type = IntegerType.class, min = 0, max = 1),
145                @OperationParam(name = "ImagingStudy", type = IntegerType.class, min = 0, max = 1),
146                @OperationParam(name = "Immunization", type = IntegerType.class, min = 0, max = 1),
147                @OperationParam(name = "ImmunizationRecommendation", type = IntegerType.class, min = 0, max = 1),
148                @OperationParam(name = "ListResource", type = IntegerType.class, min = 0, max = 1),
149                @OperationParam(name = "Location", type = IntegerType.class, min = 0, max = 1),
150                @OperationParam(name = "Media", type = IntegerType.class, min = 0, max = 1),
151                @OperationParam(name = "Medication", type = IntegerType.class, min = 0, max = 1),
152                @OperationParam(name = "MedicationAdministration", type = IntegerType.class, min = 0, max = 1),
153                @OperationParam(name = "MedicationDispense", type = IntegerType.class, min = 0, max = 1),
154                @OperationParam(name = "MedicationPrescription", type = IntegerType.class, min = 0, max = 1),
155                @OperationParam(name = "MedicationStatement", type = IntegerType.class, min = 0, max = 1),
156                @OperationParam(name = "MessageHeader", type = IntegerType.class, min = 0, max = 1),
157                @OperationParam(name = "NamingSystem", type = IntegerType.class, min = 0, max = 1),
158                @OperationParam(name = "NutritionOrder", type = IntegerType.class, min = 0, max = 1),
159                @OperationParam(name = "Observation", type = IntegerType.class, min = 0, max = 1),
160                @OperationParam(name = "OperationDefinition", type = IntegerType.class, min = 0, max = 1),
161                @OperationParam(name = "OperationOutcome", type = IntegerType.class, min = 0, max = 1),
162                @OperationParam(name = "Order", type = IntegerType.class, min = 0, max = 1),
163                @OperationParam(name = "OrderResponse", type = IntegerType.class, min = 0, max = 1),
164                @OperationParam(name = "Organization", type = IntegerType.class, min = 0, max = 1),
165                @OperationParam(name = "Parameters", type = IntegerType.class, min = 0, max = 1),
166                @OperationParam(name = "Patient", type = IntegerType.class, min = 0, max = 1),
167                @OperationParam(name = "PaymentNotice", type = IntegerType.class, min = 0, max = 1),
168                @OperationParam(name = "PaymentReconciliation", type = IntegerType.class, min = 0, max = 1),
169                @OperationParam(name = "Person", type = IntegerType.class, min = 0, max = 1),
170                @OperationParam(name = "Practitioner", type = IntegerType.class, min = 0, max = 1),
171                @OperationParam(name = "Procedure", type = IntegerType.class, min = 0, max = 1),
172                @OperationParam(name = "ProcedureRequest", type = IntegerType.class, min = 0, max = 1),
173                @OperationParam(name = "ProcessRequest", type = IntegerType.class, min = 0, max = 1),
174                @OperationParam(name = "ProcessResponse", type = IntegerType.class, min = 0, max = 1),
175                @OperationParam(name = "Provenance", type = IntegerType.class, min = 0, max = 1),
176                @OperationParam(name = "Questionnaire", type = IntegerType.class, min = 0, max = 1),
177                @OperationParam(name = "QuestionnaireAnswers", type = IntegerType.class, min = 0, max = 1),
178                @OperationParam(name = "ReferralRequest", type = IntegerType.class, min = 0, max = 1),
179                @OperationParam(name = "RelatedPerson", type = IntegerType.class, min = 0, max = 1),
180                @OperationParam(name = "RiskAssessment", type = IntegerType.class, min = 0, max = 1),
181                @OperationParam(name = "Schedule", type = IntegerType.class, min = 0, max = 1),
182                @OperationParam(name = "SearchParameter", type = IntegerType.class, min = 0, max = 1),
183                @OperationParam(name = "Slot", type = IntegerType.class, min = 0, max = 1),
184                @OperationParam(name = "Specimen", type = IntegerType.class, min = 0, max = 1),
185                @OperationParam(name = "StructureDefinition", type = IntegerType.class, min = 0, max = 1),
186                @OperationParam(name = "Subscription", type = IntegerType.class, min = 0, max = 1),
187                @OperationParam(name = "Substance", type = IntegerType.class, min = 0, max = 1),
188                @OperationParam(name = "Supply", type = IntegerType.class, min = 0, max = 1),
189                @OperationParam(name = "ValueSet", type = IntegerType.class, min = 0, max = 1),
190                @OperationParam(name = "VisionPrescription", type = IntegerType.class, min = 0, max = 1)
191        })
192        @Description(shortDefinition = "Provides the number of resources currently stored on the server, broken down by resource type")
193        public Parameters getResourceCounts() {
194                Parameters retVal = new Parameters();
195
196                Map<String, Long> counts = mySystemDao.getResourceCountsFromCache();
197                counts = defaultIfNull(counts, Collections.emptyMap());
198                counts = new TreeMap<>(counts);
199                for (Entry<String, Long> nextEntry : counts.entrySet()) {
200                        retVal.addParameter().setName((nextEntry.getKey())).setValue(new IntegerType(nextEntry.getValue().intValue()));
201                }
202
203                return retVal;
204        }
205
206        @Operation(name = JpaConstants.OPERATION_META, idempotent = true, returnParameters = {
207                @OperationParam(name = "return", type = Meta.class)
208        })
209        public Parameters meta(RequestDetails theRequestDetails) {
210                Parameters parameters = new Parameters();
211                parameters.addParameter().setName("return").setValue(getDao().metaGetOperation(theRequestDetails));
212                return parameters;
213        }
214
215        /**
216         * /$process-message
217         */
218        @Operation(name = JpaConstants.OPERATION_PROCESS_MESSAGE, idempotent = false)
219        public IBaseBundle processMessage(
220                HttpServletRequest theServletRequest,
221                RequestDetails theRequestDetails,
222
223                @OperationParam(name = "content", min = 1, max = 1)
224                @Description(formalDefinition = "The message to process (or, if using asynchronous messaging, it may be a response message to accept)")
225                        Bundle theMessageToProcess
226        ) {
227
228                startRequest(theServletRequest);
229                try {
230                        return getDao().processMessage(theRequestDetails, theMessageToProcess);
231                } finally {
232                        endRequest(theServletRequest);
233                }
234
235        }
236
237        @Transaction
238        public Bundle transaction(RequestDetails theRequestDetails, @TransactionParam Bundle theResources) {
239                startRequest(((ServletRequestDetails) theRequestDetails).getServletRequest());
240                try {
241                        return getDao().transaction(theRequestDetails, theResources);
242                } finally {
243                        endRequest(((ServletRequestDetails) theRequestDetails).getServletRequest());
244                }
245        }
246
247}