001package ca.uhn.fhir.rest.method;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2016 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 */
022import static org.apache.commons.lang3.StringUtils.isNotBlank;
023
024import java.lang.reflect.Method;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031import java.util.StringTokenizer;
032
033import org.apache.commons.lang3.StringUtils;
034import org.hl7.fhir.instance.model.api.IBaseResource;
035
036import ca.uhn.fhir.context.ConfigurationException;
037import ca.uhn.fhir.context.FhirContext;
038import ca.uhn.fhir.rest.api.SummaryEnum;
039import ca.uhn.fhir.rest.param.CollectionBinder;
040import ca.uhn.fhir.rest.server.Constants;
041import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
042import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
043
044public class ElementsParameter implements IParameter {
045
046        @SuppressWarnings("rawtypes")
047        private Class<? extends Collection> myInnerCollectionType;
048
049        @SuppressWarnings("unchecked")
050        @Override
051        public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
052                if (theSourceClientArgument instanceof Collection) {
053                        StringBuilder values = new StringBuilder();
054                        for (String next : (Collection<String>) theSourceClientArgument) {
055                                if (isNotBlank(next)) {
056                                        if (values.length() > 0) {
057                                                values.append(',');
058                                        }
059                                        values.append(next);
060                                }
061                        }
062                        theTargetQueryArguments.put(Constants.PARAM_ELEMENTS, Collections.singletonList(values.toString()));
063                } else {
064                        String elements = (String) theSourceClientArgument;
065                        if (elements != null) {
066                                theTargetQueryArguments.put(Constants.PARAM_ELEMENTS, Collections.singletonList(elements));
067                        }
068                }
069        }
070
071        @Override
072        @SuppressWarnings({ "rawtypes", "unchecked" })
073        public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
074                Set<String> value = getElementsValueOrNull(theRequest);
075                if (value == null || value.isEmpty()) {
076                        return null;
077                }
078
079                if (myInnerCollectionType == null) {
080                        return StringUtils.join(value, ',');
081                }
082
083                try {
084                        Collection retVal = myInnerCollectionType.newInstance();
085                        retVal.addAll(value);
086                        return retVal;
087                } catch (InstantiationException e) {
088                        throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
089                } catch (IllegalAccessException e) {
090                        throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
091                }
092        }
093
094        public static Set<String> getElementsValueOrNull(RequestDetails theRequest) {
095                String[] summary = theRequest.getParameters().get(Constants.PARAM_ELEMENTS);
096
097                if (summary != null && summary.length > 0) {
098                        Set<String> retVal = new HashSet<String>();
099                        for (String next : summary) {
100                                StringTokenizer tok = new StringTokenizer(next, ",");
101                                while (tok.hasMoreTokens()) {
102                                        String token = tok.nextToken();
103                                        if (isNotBlank(token)) {
104                                                retVal.add(token);
105                                        }
106                                }
107                        }
108                        if (retVal.isEmpty()) {
109                                return null;
110                        }
111                        return retVal;
112                } else {
113                        return null;
114                }
115        }
116
117        @Override
118        public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
119                if (theOuterCollectionType != null) {
120                        throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class + " but can not be a collection of collections");
121                }
122                if (theInnerCollectionType != null) {
123                        myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
124                }
125        }
126
127}