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 Returns {@literal null} if no match
044         */
045        RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName);
046
047        /**
048         * @return Returns all active search params for the given resource
049         */
050        ResourceSearchParams getActiveSearchParams(String theResourceName);
051
052        /**
053         * Request that the cache be refreshed now, in the current thread
054         */
055        default void forceRefresh() {}
056
057        /**
058         * Request that the cache be refreshed at the next convenient time (in a different thread)
059         */
060        default void requestRefresh() {}
061
062        /**
063         * When indexing a HumanName, if a StringEncoder is set in the context, then the "phonetic" search parameter will normalize
064         * the String using this encoder.
065         *
066         * @since 5.1.0
067         */
068        default void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {}
069
070        default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
071                return Collections.emptyList();
072        }
073
074        // TODO ND remove default implementation
075        default List<RuntimeSearchParam> getActiveComboSearchParams(
076                        String theResourceName, ComboSearchParamType theParamType) {
077                return Collections.emptyList();
078        }
079
080        // TODO ND remove default implementation
081        default Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
082                return Optional.empty();
083        }
084
085        default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
086                return Collections.emptyList();
087        }
088
089        /**
090         * Returns a collection containing all of the valid active search parameters. This method is intended for
091         * creating error messages for users as opposed to actual search processing. It will include meta parameters
092         * such as <code>_id</code> and <code>_lastUpdated</code>.
093         */
094        default Collection<String> getValidSearchParameterNamesIncludingMeta(String theResourceName) {
095                TreeSet<String> retval;
096                ResourceSearchParams activeSearchParams = getActiveSearchParams(theResourceName);
097                if (activeSearchParams == null) {
098                        retval = new TreeSet<>();
099                } else {
100                        retval = new TreeSet<>(activeSearchParams.getSearchParamNames());
101                }
102                retval.add(IAnyResource.SP_RES_ID);
103                retval.add(Constants.PARAM_LASTUPDATED);
104                return retval;
105        }
106
107        /**
108         * Fetch a SearchParameter by URL
109         *
110         * @return Returns <code>null</code> if it can't be found
111         */
112        @Nullable
113        RuntimeSearchParam getActiveSearchParamByUrl(String theUrl);
114
115        /**
116         * Find a search param for a resource. First, check the resource itself, then check the top-level `Resource` resource.
117         *
118         * @param theResourceType the resource type.
119         * @param theParamName the search parameter name.
120         *
121         * @return the {@link RuntimeSearchParam} that is found.
122         */
123        default RuntimeSearchParam getRuntimeSearchParam(String theResourceType, String theParamName) {
124                RuntimeSearchParam availableSearchParamDef = getActiveSearchParam(theResourceType, theParamName);
125                if (availableSearchParamDef == null) {
126                        availableSearchParamDef = getActiveSearchParam("Resource", theParamName);
127                }
128                if (availableSearchParamDef == null) {
129                        throw new InvalidRequestException(
130                                        Msg.code(1209) + "Unknown parameter name: " + theResourceType + ':' + theParamName);
131                }
132                return availableSearchParamDef;
133        }
134
135        /**
136         * Get all the search params for a resource. First, check the resource itself, then check the top-level `Resource` resource and combine the two.
137         *
138         * @param theResourceType the resource type.
139         *
140         * @return the {@link ResourceSearchParams} that has all the search params.
141         */
142        default ResourceSearchParams getRuntimeSearchParams(String theResourceType) {
143                ResourceSearchParams availableSearchParams =
144                                getActiveSearchParams(theResourceType).makeCopy();
145                ResourceSearchParams resourceSearchParams = getActiveSearchParams("Resource");
146                resourceSearchParams
147                                .getSearchParamNames()
148                                .forEach(param -> availableSearchParams.addSearchParamIfAbsent(param, resourceSearchParams.get(param)));
149                return availableSearchParams;
150        }
151}