001/*
002 * #%L
003 * HAPI FHIR - Client 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.client.method;
021
022import ca.uhn.fhir.context.ConfigurationException;
023import ca.uhn.fhir.context.FhirContext;
024import ca.uhn.fhir.context.FhirVersionEnum;
025import ca.uhn.fhir.i18n.Msg;
026import ca.uhn.fhir.rest.annotation.Sort;
027import ca.uhn.fhir.rest.api.Constants;
028import ca.uhn.fhir.rest.api.SortOrderEnum;
029import ca.uhn.fhir.rest.api.SortSpec;
030import ca.uhn.fhir.rest.param.ParameterUtil;
031import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
032import org.hl7.fhir.instance.model.api.IBaseResource;
033
034import java.lang.reflect.Method;
035import java.util.ArrayList;
036import java.util.Collection;
037import java.util.List;
038import java.util.Map;
039
040import static org.apache.commons.lang3.StringUtils.isNotBlank;
041
042public class SortParameter implements IParameter {
043
044        private FhirContext myContext;
045
046        public SortParameter(FhirContext theContext) {
047                myContext = theContext;
048        }
049
050        @Override
051        public void initializeTypes(
052                        Method theMethod,
053                        Class<? extends Collection<?>> theOuterCollectionType,
054                        Class<? extends Collection<?>> theInnerCollectionType,
055                        Class<?> theParameterType) {
056                if (theOuterCollectionType != null || theInnerCollectionType != null) {
057                        throw new ConfigurationException(Msg.code(1463) + "Method '" + theMethod.getName() + "' in type '"
058                                        + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + Sort.class.getName()
059                                        + " but can not be of collection type");
060                }
061                if (!theParameterType.equals(SortSpec.class)) {
062                        throw new ConfigurationException(Msg.code(1464) + "Method '" + theMethod.getName() + "' in type '"
063                                        + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + Sort.class.getName()
064                                        + " but is an invalid type, must be: " + SortSpec.class.getCanonicalName());
065                }
066        }
067
068        @Override
069        public void translateClientArgumentIntoQueryArgument(
070                        FhirContext theContext,
071                        Object theSourceClientArgument,
072                        Map<String, List<String>> theTargetQueryArguments,
073                        IBaseResource theTargetResource)
074                        throws InternalErrorException {
075                SortSpec ss = (SortSpec) theSourceClientArgument;
076
077                if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU2)) {
078                        String string = createSortStringDstu3(ss);
079                        if (string.length() > 0) {
080                                if (!theTargetQueryArguments.containsKey(Constants.PARAM_SORT)) {
081                                        theTargetQueryArguments.put(Constants.PARAM_SORT, new ArrayList<String>());
082                                }
083                                theTargetQueryArguments.get(Constants.PARAM_SORT).add(string);
084                        }
085
086                } else {
087
088                        while (ss != null) {
089                                String name;
090                                if (ss.getOrder() == null) {
091                                        name = Constants.PARAM_SORT;
092                                } else if (ss.getOrder() == SortOrderEnum.ASC) {
093                                        name = Constants.PARAM_SORT_ASC;
094                                } else {
095                                        name = Constants.PARAM_SORT_DESC;
096                                }
097
098                                if (ss.getParamName() != null) {
099                                        if (!theTargetQueryArguments.containsKey(name)) {
100                                                theTargetQueryArguments.put(name, new ArrayList<String>());
101                                        }
102
103                                        theTargetQueryArguments.get(name).add(ss.getParamName());
104                                }
105                                ss = ss.getChain();
106                        }
107                }
108        }
109
110        public static String createSortStringDstu3(SortSpec ss) {
111                StringBuilder val = new StringBuilder();
112                while (ss != null) {
113
114                        if (isNotBlank(ss.getParamName())) {
115                                if (val.length() > 0) {
116                                        val.append(',');
117                                }
118                                if (ss.getOrder() == SortOrderEnum.DESC) {
119                                        val.append('-');
120                                }
121                                val.append(ParameterUtil.escape(ss.getParamName()));
122                        }
123
124                        ss = ss.getChain();
125                }
126
127                String string = val.toString();
128                return string;
129        }
130}