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.jpa.api.dao.IFhirSystemDao;
025import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
026import ca.uhn.fhir.jpa.api.model.ExpungeOutcome;
027import ca.uhn.fhir.jpa.model.util.JpaConstants;
028import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
029import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
030import ca.uhn.fhir.jpa.term.api.ReindexTerminologyResult;
031import ca.uhn.fhir.rest.annotation.At;
032import ca.uhn.fhir.rest.annotation.History;
033import ca.uhn.fhir.rest.annotation.Offset;
034import ca.uhn.fhir.rest.annotation.Operation;
035import ca.uhn.fhir.rest.annotation.OperationParam;
036import ca.uhn.fhir.rest.annotation.Since;
037import ca.uhn.fhir.rest.api.server.IBundleProvider;
038import ca.uhn.fhir.rest.api.server.RequestDetails;
039import ca.uhn.fhir.rest.param.DateRangeParam;
040import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
041import ca.uhn.fhir.rest.server.provider.ProviderConstants;
042import ca.uhn.fhir.util.ParametersUtil;
043import ca.uhn.fhir.util.StopWatch;
044import org.apache.commons.lang3.exception.ExceptionUtils;
045import org.hl7.fhir.instance.model.api.IBaseParameters;
046import org.hl7.fhir.instance.model.api.IPrimitiveType;
047import org.slf4j.Logger;
048import org.slf4j.LoggerFactory;
049import org.springframework.beans.factory.annotation.Autowired;
050import org.springframework.beans.factory.annotation.Required;
051
052import javax.servlet.http.HttpServletRequest;
053import java.util.Date;
054
055public class BaseJpaSystemProvider<T, MT> extends BaseJpaProvider implements IJpaSystemProvider {
056        private static final Logger ourLog = LoggerFactory.getLogger(BaseJpaSystemProvider.class);
057
058        public static final String RESP_PARAM_SUCCESS = "success";
059
060        /**
061         * @see ProviderConstants#OPERATION_REINDEX
062         * @deprecated
063         */
064        @Deprecated
065        public static final String MARK_ALL_RESOURCES_FOR_REINDEXING = ProviderConstants.MARK_ALL_RESOURCES_FOR_REINDEXING;
066        /**
067         * @see ProviderConstants#OPERATION_REINDEX
068         * @deprecated
069         */
070        @Deprecated
071        public static final String PERFORM_REINDEXING_PASS = ProviderConstants.PERFORM_REINDEXING_PASS;
072
073        private IFhirSystemDao<T, MT> myDao;
074        @Autowired
075        private IResourceReindexingSvc myResourceReindexingSvc;
076
077        @Autowired
078        private ITermReadSvc myTermReadSvc;
079
080
081        public BaseJpaSystemProvider() {
082                // nothing
083        }
084
085        protected IResourceReindexingSvc getResourceReindexingSvc() {
086                return myResourceReindexingSvc;
087        }
088
089        @Operation(name = ProviderConstants.OPERATION_EXPUNGE, idempotent = false, returnParameters = {
090                @OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, typeName = "integer")
091        })
092        public IBaseParameters expunge(
093                @OperationParam(name = ProviderConstants.OPERATION_EXPUNGE_PARAM_LIMIT, typeName = "integer") IPrimitiveType<Integer> theLimit,
094                @OperationParam(name = ProviderConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES, typeName = "boolean") IPrimitiveType<Boolean> theExpungeDeletedResources,
095                @OperationParam(name = ProviderConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS, typeName = "boolean") IPrimitiveType<Boolean> theExpungeOldVersions,
096                @OperationParam(name = ProviderConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_EVERYTHING, typeName = "boolean") IPrimitiveType<Boolean> theExpungeEverything,
097                RequestDetails theRequestDetails
098        ) {
099                ExpungeOptions options = createExpungeOptions(theLimit, theExpungeDeletedResources, theExpungeOldVersions, theExpungeEverything);
100                ExpungeOutcome outcome = getDao().expunge(options, theRequestDetails);
101                return createExpungeResponse(outcome);
102        }
103
104        protected IBaseParameters doExpunge(IPrimitiveType<? extends Integer> theLimit, IPrimitiveType<? extends Boolean> theExpungeDeletedResources, IPrimitiveType<? extends Boolean> theExpungeOldVersions, IPrimitiveType<? extends Boolean> theExpungeEverything, RequestDetails theRequestDetails) {
105                ExpungeOptions options = createExpungeOptions(theLimit, theExpungeDeletedResources, theExpungeOldVersions, theExpungeEverything);
106                ExpungeOutcome outcome = getDao().expunge(options, theRequestDetails);
107                return createExpungeResponse(outcome);
108        }
109
110        protected IFhirSystemDao<T, MT> getDao() {
111                return myDao;
112        }
113
114        @Required
115        public void setDao(IFhirSystemDao<T, MT> theDao) {
116                myDao = theDao;
117        }
118
119        @History
120        public IBundleProvider historyServer(
121                HttpServletRequest theRequest,
122                @Offset Integer theOffset,
123                @Since Date theDate,
124                @At DateRangeParam theAt,
125                RequestDetails theRequestDetails) {
126                startRequest(theRequest);
127                try {
128                        DateRangeParam range = super.processSinceOrAt(theDate, theAt);
129                        return myDao.history(range.getLowerBoundAsInstant(), range.getUpperBoundAsInstant(), theOffset, theRequestDetails);
130                } finally {
131                        endRequest(theRequest);
132                }
133        }
134
135
136        @Operation(name = ProviderConstants.OPERATION_REINDEX_TERMINOLOGY, idempotent = false)
137        public IBaseParameters reindexTerminology(RequestDetails theRequestDetails) {
138
139                ReindexTerminologyResult result;
140                StopWatch sw = new StopWatch();
141                try {
142                        result = myTermReadSvc.reindexTerminology();
143
144                } catch (Exception theE) {
145                        throw new InternalErrorException(Msg.code(2072) +
146                                "Re-creating terminology freetext indexes failed with exception: " + theE.getMessage() +
147                                NL +  "With trace:" + NL + ExceptionUtils.getStackTrace(theE));
148                }
149
150                IBaseParameters retVal = ParametersUtil.newInstance(getContext());
151                if ( ! result.equals(ReindexTerminologyResult.SUCCESS) ) {
152                        ParametersUtil.addParameterToParametersBoolean(getContext(), retVal, RESP_PARAM_SUCCESS, false);
153                        String msg = result.equals(ReindexTerminologyResult.SEARCH_SVC_DISABLED)
154                                ? "Freetext service is not configured. Operation didn't run."
155                                : "Operation was cancelled because other terminology background tasks are currently running. Try again in a few minutes.";
156                        ParametersUtil.addParameterToParametersString(getContext(), retVal, "message", msg);
157                        return retVal;
158                }
159
160                ParametersUtil.addParameterToParametersBoolean(getContext(), retVal, RESP_PARAM_SUCCESS, true);
161                ourLog.info("Re-creating terminology freetext indexes took {}", sw);
162                return retVal;
163        }
164
165
166        public static final String NL = System.getProperty("line.separator");
167
168}