001package ca.uhn.fhir.rest.server.method;
002
003/*
004 * #%L
005 * HAPI FHIR - Server Framework
006 * %%
007 * Copyright (C) 2014 - 2019 University Health Network
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 * http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.context.ConfigurationException;
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.ElementsSupportEnum;
029import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
030import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
031import org.apache.commons.lang3.StringUtils;
032
033import java.lang.reflect.Method;
034import java.util.Collection;
035import java.util.HashSet;
036import java.util.Set;
037import java.util.StringTokenizer;
038
039import static org.apache.commons.lang3.StringUtils.isNotBlank;
040
041public class ElementsParameter implements IParameter {
042
043        @SuppressWarnings("rawtypes")
044        private Class<? extends Collection> myInnerCollectionType;
045
046        @Override
047        @SuppressWarnings({"rawtypes", "unchecked"})
048        public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
049                Set<String> value = getElementsValueOrNull(theRequest, false);
050                if (value == null || value.isEmpty()) {
051                        return null;
052                }
053
054                if (myInnerCollectionType == null) {
055                        return StringUtils.join(value, ',');
056                }
057
058                try {
059                        Collection retVal = myInnerCollectionType.newInstance();
060                        retVal.addAll(value);
061                        return retVal;
062                } catch (InstantiationException e) {
063                        throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
064                } catch (IllegalAccessException e) {
065                        throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
066                }
067        }
068
069        @Override
070        public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
071                if (theOuterCollectionType != null) {
072                        throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
073                                + " but can not be a collection of collections");
074                }
075                if (theInnerCollectionType != null) {
076                        myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
077                }
078        }
079
080        public static Set<String> getElementsValueOrNull(RequestDetails theRequest, boolean theExclude) {
081                boolean standardMode = theRequest.getServer().getElementsSupport() != ElementsSupportEnum.EXTENDED;
082                if (theExclude && standardMode) {
083                        return null;
084                }
085
086                String paramName = Constants.PARAM_ELEMENTS;
087                if (theExclude) {
088                        paramName = Constants.PARAM_ELEMENTS + Constants.PARAM_ELEMENTS_EXCLUDE_MODIFIER;
089                }
090                String[] elementsValues = theRequest.getParameters().get(paramName);
091
092                if (elementsValues != null && elementsValues.length > 0) {
093                        Set<String> retVal = new HashSet<>();
094                        for (String next : elementsValues) {
095                                StringTokenizer tok = new StringTokenizer(next, ",");
096                                while (tok.hasMoreTokens()) {
097                                        String token = tok.nextToken();
098                                        if (isNotBlank(token)) {
099                                                if (token.contains("."))
100                                                        if (standardMode) {
101                                                                continue;
102                                                        }
103                                                retVal.add(token);
104                                        }
105                                }
106                        }
107                        if (retVal.isEmpty()) {
108                                return null;
109                        }
110
111                        return retVal;
112                }
113                return null;
114        }
115
116}