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.ConfigurationException;
023import ca.uhn.fhir.i18n.Msg;
024import ca.uhn.fhir.rest.api.Constants;
025import ca.uhn.fhir.rest.api.SummaryEnum;
026import ca.uhn.fhir.rest.api.server.RequestDetails;
027import ca.uhn.fhir.rest.param.binder.CollectionBinder;
028import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
029import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
030
031import java.lang.reflect.Method;
032import java.util.Collection;
033import java.util.Collections;
034import java.util.HashSet;
035import java.util.Set;
036
037import static org.apache.commons.lang3.StringUtils.isBlank;
038
039public class SummaryEnumParameter implements IParameter {
040
041        @SuppressWarnings("rawtypes")
042        private Class<? extends Collection> myInnerCollectionType;
043
044        @Override
045        @SuppressWarnings({"rawtypes", "unchecked"})
046        public Object translateQueryParametersIntoServerArgument(
047                        RequestDetails theRequest, BaseMethodBinding theMethodBinding)
048                        throws InternalErrorException, InvalidRequestException {
049                Set<SummaryEnum> value = getSummaryValueOrNull(theRequest);
050                if (value == null || value.isEmpty()) {
051                        return null;
052                }
053
054                if (myInnerCollectionType == null) {
055                        return value.iterator().next();
056                }
057
058                try {
059                        Collection retVal = myInnerCollectionType.newInstance();
060                        retVal.addAll(value);
061                        return retVal;
062                } catch (InstantiationException e) {
063                        throw new InternalErrorException(Msg.code(378) + "Failed to instantiate " + myInnerCollectionType, e);
064                } catch (IllegalAccessException e) {
065                        throw new InternalErrorException(Msg.code(379) + "Failed to instantiate " + myInnerCollectionType, e);
066                }
067        }
068
069        public static Set<SummaryEnum> getSummaryValueOrNull(RequestDetails theRequest) {
070                String[] summary = theRequest.getParameters().get(Constants.PARAM_SUMMARY);
071
072                Set<SummaryEnum> retVal;
073                if (summary == null || summary.length == 0) {
074                        retVal = null;
075                } else if (isBlank(summary[0])) {
076                        retVal = null;
077                } else if (summary.length == 1 && summary[0].indexOf(',') == -1) {
078                        retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0]));
079                        if (retVal == null) {
080                                retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0].toLowerCase()));
081                        }
082                } else {
083                        retVal = new HashSet<>();
084                        for (String nextParamValue : summary) {
085                                for (String nextParamValueTok : nextParamValue.split(",")) {
086                                        SummaryEnum value = SummaryEnum.fromCode(nextParamValueTok);
087                                        if (value == null) {
088                                                value = SummaryEnum.fromCode(nextParamValueTok.toLowerCase());
089                                        }
090                                        if (value != null) {
091                                                retVal.add(value);
092                                        }
093                                }
094                        }
095                }
096
097                if (retVal != null) {
098                        if (retVal.contains(SummaryEnum.TEXT)) {
099                                if (retVal.size() > 1) {
100                                        String msg = theRequest
101                                                        .getServer()
102                                                        .getFhirContext()
103                                                        .getLocalizer()
104                                                        .getMessage(SummaryEnumParameter.class, "cantCombineText");
105                                        throw new InvalidRequestException(Msg.code(380) + msg);
106                                }
107                        }
108                }
109
110                return retVal;
111        }
112
113        private static Set<SummaryEnum> toCollectionOrNull(SummaryEnum theFromCode) {
114                if (theFromCode == null) {
115                        return null;
116                }
117                return Collections.singleton(theFromCode);
118        }
119
120        @Override
121        public void initializeTypes(
122                        Method theMethod,
123                        Class<? extends Collection<?>> theOuterCollectionType,
124                        Class<? extends Collection<?>> theInnerCollectionType,
125                        Class<?> theParameterType) {
126                if (theOuterCollectionType != null) {
127                        throw new ConfigurationException(Msg.code(381) + "Method '" + theMethod.getName() + "' in type '"
128                                        + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
129                                        + " but can not be a collection of collections");
130                }
131                if (theInnerCollectionType != null) {
132                        myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(
133                                        theInnerCollectionType, SummaryEnum.class.getSimpleName());
134                }
135        }
136}