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.method;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.rest.api.QualifiedParamList;
024import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
025import ca.uhn.fhir.rest.api.server.RequestDetails;
026import ca.uhn.fhir.rest.param.QualifierDetails;
027import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
028import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
029
030import java.lang.reflect.Method;
031import java.util.ArrayList;
032import java.util.Collection;
033import java.util.List;
034import java.util.Set;
035
036public abstract class BaseQueryParameter implements IParameter {
037
038        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseQueryParameter.class);
039
040        public abstract List<QualifiedParamList> encode(FhirContext theContext, Object theObject)
041                        throws InternalErrorException;
042
043        public abstract String getName();
044
045        public abstract RestSearchParameterTypeEnum getParamType();
046
047        /**
048         * Returns null if blacklist is "none"
049         */
050        public Set<String> getQualifierBlacklist() {
051                return null;
052        }
053
054        /**
055         * Returns null if whitelist is "all"
056         */
057        public Set<String> getQualifierWhitelist() {
058                return null;
059        }
060
061        protected abstract boolean supportsRepetition();
062
063        /**
064         * Parameter should return true if {@link #parse(FhirContext, List)} should be called even if the query string
065         * contained no values for the given parameter
066         */
067        public abstract boolean handlesMissing();
068
069        @Override
070        public void initializeTypes(
071                        Method theMethod,
072                        Class<? extends Collection<?>> theOuterCollectionType,
073                        Class<? extends Collection<?>> theInnerCollectionType,
074                        Class<?> theParameterType) {
075                // ignore for now
076        }
077
078        public abstract boolean isRequired();
079
080        public abstract Object parse(FhirContext theContext, List<QualifiedParamList> theString)
081                        throws InternalErrorException, InvalidRequestException;
082
083        private void parseParams(
084                        RequestDetails theRequest,
085                        List<QualifiedParamList> paramList,
086                        String theQualifiedParamName,
087                        String theQualifier) {
088                QualifierDetails qualifiers = QualifierDetails.extractQualifiersFromParameterName(theQualifier);
089                if (!qualifiers.passes(getQualifierWhitelist(), getQualifierBlacklist())) {
090                        return;
091                }
092
093                String[] value = theRequest.getParameters().get(theQualifiedParamName);
094                if (value != null) {
095                        for (String nextParam : value) {
096                                if (nextParam.contains(",") == false) {
097                                        paramList.add(QualifiedParamList.singleton(theQualifier, nextParam));
098                                } else {
099                                        paramList.add(QualifiedParamList.splitQueryStringByCommasIgnoreEscape(theQualifier, nextParam));
100                                }
101                        }
102                }
103        }
104
105        @Override
106        public Object translateQueryParametersIntoServerArgument(
107                        RequestDetails theRequest, BaseMethodBinding theMethodBinding)
108                        throws InternalErrorException, InvalidRequestException {
109
110                List<QualifiedParamList> paramList = new ArrayList<>();
111                String name = getName();
112                parseParams(theRequest, paramList, name, null);
113
114                List<String> qualified = theRequest.getUnqualifiedToQualifiedNames().get(name);
115                if (qualified != null) {
116                        for (String nextQualified : qualified) {
117                                parseParams(theRequest, paramList, nextQualified, nextQualified.substring(name.length()));
118                        }
119                }
120
121                if (paramList.isEmpty()) {
122
123                        ourLog.debug(
124                                        "No value for parameter '{}' - Qualified names {} and qualifier whitelist {}",
125                                        new Object[] {getName(), qualified, getQualifierWhitelist()});
126
127                        if (handlesMissing()) {
128                                return parse(theRequest.getFhirContext(), paramList);
129                        }
130                        return null;
131                }
132
133                return parse(theRequest.getFhirContext(), paramList);
134        }
135}