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