001/*
002 * #%L
003 * HAPI FHIR JPA Server
004 * %%
005 * Copyright (C) 2014 - 2025 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.provider;
021
022import ca.uhn.fhir.i18n.Msg;
023import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
024import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
025import ca.uhn.fhir.jpa.term.api.ReindexTerminologyResult;
026import ca.uhn.fhir.rest.annotation.At;
027import ca.uhn.fhir.rest.annotation.History;
028import ca.uhn.fhir.rest.annotation.Offset;
029import ca.uhn.fhir.rest.annotation.Operation;
030import ca.uhn.fhir.rest.annotation.Since;
031import ca.uhn.fhir.rest.api.server.IBundleProvider;
032import ca.uhn.fhir.rest.api.server.RequestDetails;
033import ca.uhn.fhir.rest.param.DateRangeParam;
034import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
035import ca.uhn.fhir.rest.server.provider.ProviderConstants;
036import ca.uhn.fhir.util.ParametersUtil;
037import ca.uhn.fhir.util.StopWatch;
038import jakarta.servlet.http.HttpServletRequest;
039import org.apache.commons.lang3.exception.ExceptionUtils;
040import org.hl7.fhir.instance.model.api.IBaseParameters;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043import org.springframework.beans.factory.annotation.Autowired;
044
045import java.util.Date;
046
047public abstract class BaseJpaSystemProvider<T, MT> extends BaseStorageSystemProvider<T, MT>
048                implements IJpaSystemProvider {
049        private static final Logger ourLog = LoggerFactory.getLogger(BaseJpaSystemProvider.class);
050
051        public static final String RESP_PARAM_SUCCESS = "success";
052
053        /**
054         * @see ProviderConstants#OPERATION_REINDEX
055         * @deprecated
056         */
057        @Deprecated
058        public static final String MARK_ALL_RESOURCES_FOR_REINDEXING = ProviderConstants.MARK_ALL_RESOURCES_FOR_REINDEXING;
059        /**
060         * @see ProviderConstants#OPERATION_REINDEX
061         * @deprecated
062         */
063        @Deprecated
064        public static final String PERFORM_REINDEXING_PASS = ProviderConstants.PERFORM_REINDEXING_PASS;
065
066        @Autowired
067        private IResourceReindexingSvc myResourceReindexingSvc;
068
069        @Autowired
070        private ITermReadSvc myTermReadSvc;
071
072        @Autowired
073        private IReplaceReferencesSvc myReplaceReferencesSvc;
074
075        public BaseJpaSystemProvider() {
076                // nothing
077        }
078
079        protected IResourceReindexingSvc getResourceReindexingSvc() {
080                return myResourceReindexingSvc;
081        }
082
083        public IReplaceReferencesSvc getReplaceReferencesSvc() {
084                return myReplaceReferencesSvc;
085        }
086
087        @History
088        public IBundleProvider historyServer(
089                        HttpServletRequest theRequest,
090                        @Offset Integer theOffset,
091                        @Since Date theDate,
092                        @At DateRangeParam theAt,
093                        RequestDetails theRequestDetails) {
094                startRequest(theRequest);
095                try {
096                        DateRangeParam range = super.processSinceOrAt(theDate, theAt);
097                        return myDao.history(
098                                        range.getLowerBoundAsInstant(), range.getUpperBoundAsInstant(), theOffset, theRequestDetails);
099                } finally {
100                        endRequest(theRequest);
101                }
102        }
103
104        @Operation(name = ProviderConstants.OPERATION_REINDEX_TERMINOLOGY, idempotent = false)
105        public IBaseParameters reindexTerminology(RequestDetails theRequestDetails) {
106
107                ReindexTerminologyResult result;
108                StopWatch sw = new StopWatch();
109                try {
110                        result = myTermReadSvc.reindexTerminology();
111
112                } catch (Exception theE) {
113                        throw new InternalErrorException(
114                                        Msg.code(2072) + "Re-creating terminology freetext indexes failed with exception: "
115                                                        + theE.getMessage() + NL
116                                                        + "With trace:" + NL + ExceptionUtils.getStackTrace(theE));
117                }
118
119                IBaseParameters retVal = ParametersUtil.newInstance(getContext());
120                if (!result.equals(ReindexTerminologyResult.SUCCESS)) {
121                        ParametersUtil.addParameterToParametersBoolean(getContext(), retVal, RESP_PARAM_SUCCESS, false);
122                        String msg = result.equals(ReindexTerminologyResult.SEARCH_SVC_DISABLED)
123                                        ? "Freetext service is not configured. Operation didn't run."
124                                        : "Operation was cancelled because other terminology background tasks are currently running. Try again in a few minutes.";
125                        ParametersUtil.addParameterToParametersString(getContext(), retVal, "message", msg);
126                        return retVal;
127                }
128
129                ParametersUtil.addParameterToParametersBoolean(getContext(), retVal, RESP_PARAM_SUCCESS, true);
130                ourLog.info("Re-creating terminology freetext indexes took {}", sw);
131                return retVal;
132        }
133
134        public static final String NL = System.getProperty("line.separator");
135}