001/*
002 * #%L
003 * HAPI FHIR - Server Framework
004 * %%
005 * Copyright (C) 2014 - 2024 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.rest.server.util;
021
022import ca.uhn.fhir.context.ComboSearchParamType;
023import ca.uhn.fhir.context.RuntimeSearchParam;
024import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
025import ca.uhn.fhir.i18n.Msg;
026import ca.uhn.fhir.rest.api.Constants;
027import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
028import jakarta.annotation.Nullable;
029import org.hl7.fhir.instance.model.api.IAnyResource;
030import org.hl7.fhir.instance.model.api.IIdType;
031
032import java.util.Collection;
033import java.util.Collections;
034import java.util.List;
035import java.util.Optional;
036import java.util.Set;
037import java.util.TreeSet;
038
039// TODO: JA remove default methods
040public interface ISearchParamRegistry {
041
042        /**
043         * Return true if this registry is initialized and ready to handle
044         * searches and use its cache.
045         * Return false if cache has not been initialized.
046         */
047        default boolean isInitialized() {
048                // default initialized to not break current implementers
049                return true;
050        }
051
052        /**
053         * @return Returns {@literal null} if no match
054         */
055        RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName);
056
057        /**
058         * @return Returns all active search params for the given resource
059         */
060        ResourceSearchParams getActiveSearchParams(String theResourceName);
061
062        /**
063         * Request that the cache be refreshed now, in the current thread
064         */
065        default void forceRefresh() {}
066
067        /**
068         * Request that the cache be refreshed at the next convenient time (in a different thread)
069         */
070        default void requestRefresh() {}
071
072        /**
073         * When indexing a HumanName, if a StringEncoder is set in the context, then the "phonetic" search parameter will normalize
074         * the String using this encoder.
075         *
076         * @since 5.1.0
077         */
078        default void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {}
079
080        default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
081                return Collections.emptyList();
082        }
083
084        // TODO ND remove default implementation
085        default List<RuntimeSearchParam> getActiveComboSearchParams(
086                        String theResourceName, ComboSearchParamType theParamType) {
087                return Collections.emptyList();
088        }
089
090        // TODO ND remove default implementation
091        default Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
092                return Optional.empty();
093        }
094
095        default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
096                return Collections.emptyList();
097        }
098
099        /**
100         * Returns a collection containing all of the valid active search parameters. This method is intended for
101         * creating error messages for users as opposed to actual search processing. It will include meta parameters
102         * such as <code>_id</code> and <code>_lastUpdated</code>.
103         */
104        default Collection<String> getValidSearchParameterNamesIncludingMeta(String theResourceName) {
105                TreeSet<String> retval;
106                ResourceSearchParams activeSearchParams = getActiveSearchParams(theResourceName);
107                if (activeSearchParams == null) {
108                        retval = new TreeSet<>();
109                } else {
110                        retval = new TreeSet<>(activeSearchParams.getSearchParamNames());
111                }
112                retval.add(IAnyResource.SP_RES_ID);
113                retval.add(Constants.PARAM_LASTUPDATED);
114                return retval;
115        }
116
117        /**
118         * Fetch a SearchParameter by URL
119         *
120         * @return Returns <code>null</code> if it can't be found
121         */
122        @Nullable
123        RuntimeSearchParam getActiveSearchParamByUrl(String theUrl);
124
125        /**
126         * Find a search param for a resource. First, check the resource itself, then check the top-level `Resource` resource.
127         *
128         * @param theResourceType the resource type.
129         * @param theParamName the search parameter name.
130         *
131         * @return the {@link RuntimeSearchParam} that is found.
132         */
133        default RuntimeSearchParam getRuntimeSearchParam(String theResourceType, String theParamName) {
134                RuntimeSearchParam availableSearchParamDef = getActiveSearchParam(theResourceType, theParamName);
135                if (availableSearchParamDef == null) {
136                        availableSearchParamDef = getActiveSearchParam("Resource", theParamName);
137                }
138                if (availableSearchParamDef == null) {
139                        throw new InvalidRequestException(
140                                        Msg.code(1209) + "Unknown parameter name: " + theResourceType + ':' + theParamName);
141                }
142                return availableSearchParamDef;
143        }
144
145        /**
146         * Get all the search params for a resource. First, check the resource itself, then check the top-level `Resource` resource and combine the two.
147         *
148         * @param theResourceType the resource type.
149         *
150         * @return the {@link ResourceSearchParams} that has all the search params.
151         */
152        default ResourceSearchParams getRuntimeSearchParams(String theResourceType) {
153                ResourceSearchParams availableSearchParams =
154                                getActiveSearchParams(theResourceType).makeCopy();
155                ResourceSearchParams resourceSearchParams = getActiveSearchParams("Resource");
156                resourceSearchParams
157                                .getSearchParamNames()
158                                .forEach(param -> availableSearchParams.addSearchParamIfAbsent(param, resourceSearchParams.get(param)));
159                return availableSearchParams;
160        }
161}