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 */
022
023import java.lang.reflect.Method;
024import java.util.Collection;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Map;
028
029import org.hl7.fhir.instance.model.api.IBaseResource;
030
031import ca.uhn.fhir.context.FhirContext;
032import ca.uhn.fhir.context.RuntimeSearchParam;
033import ca.uhn.fhir.model.api.IQueryParameterType;
034import ca.uhn.fhir.rest.param.CompositeOrListParam;
035import ca.uhn.fhir.rest.param.DateOrListParam;
036import ca.uhn.fhir.rest.param.DateParam;
037import ca.uhn.fhir.rest.param.NumberOrListParam;
038import ca.uhn.fhir.rest.param.NumberParam;
039import ca.uhn.fhir.rest.param.QuantityOrListParam;
040import ca.uhn.fhir.rest.param.QuantityParam;
041import ca.uhn.fhir.rest.param.ReferenceOrListParam;
042import ca.uhn.fhir.rest.param.ReferenceParam;
043import ca.uhn.fhir.rest.param.StringOrListParam;
044import ca.uhn.fhir.rest.param.StringParam;
045import ca.uhn.fhir.rest.param.TokenOrListParam;
046import ca.uhn.fhir.rest.param.TokenParam;
047import ca.uhn.fhir.rest.param.UriOrListParam;
048import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
049import ca.uhn.fhir.rest.server.SearchParameterMap;
050import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
051import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
052
053public class DynamicSearchParameter implements IParameter {
054
055        private Map<String, RuntimeSearchParam> myNameToParam = new HashMap<String, RuntimeSearchParam>();
056
057        public DynamicSearchParameter(IDynamicSearchResourceProvider theProvider) {
058                for (RuntimeSearchParam next : theProvider.getSearchParameters()) {
059                        myNameToParam.put(next.getName(), next);
060                }
061        }
062
063        @Override
064        public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
065                throw new UnsupportedOperationException("Dynamic search is not supported in client mode (use fluent client for dynamic-like searches)");
066        }
067
068        @SuppressWarnings("unchecked")
069        @Override
070        public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
071                SearchParameterMap retVal = new SearchParameterMap();
072
073                for (String next : theRequest.getParameters().keySet()) {
074                        String qualifier = null;
075                        String qualifiedParamName = next;
076                        RuntimeSearchParam param = myNameToParam.get(next);
077                        if (param == null) {
078                                int colonIndex = next.indexOf(':');
079                                int dotIndex = next.indexOf('.');
080                                if (colonIndex != -1 || dotIndex != -1) {
081                                        int index;
082                                        if (colonIndex != -1 && dotIndex != -1) {
083                                                index = Math.min(colonIndex, dotIndex);
084                                        } else {
085                                                index = (colonIndex != -1) ? colonIndex : dotIndex;
086                                        }
087                                        qualifier = next.substring(index);
088                                        next = next.substring(0, index);
089                                        param = myNameToParam.get(next);
090                                }
091                        }
092
093                        if (param != null) {
094
095                                for (String nextValue : theRequest.getParameters().get(qualifiedParamName)) {
096                                        QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, nextValue);
097
098                                        switch (param.getParamType()) {
099                                        case COMPOSITE:
100                                                Class<? extends IQueryParameterType> left = toParamType(param.getCompositeOf().get(0));
101                                                Class<? extends IQueryParameterType> right = toParamType(param.getCompositeOf().get(0));
102                                                @SuppressWarnings({ "rawtypes" })
103                                                CompositeOrListParam compositeOrListParam = new CompositeOrListParam(left, right);
104                                                compositeOrListParam.setValuesAsQueryTokens(paramList);
105                                                retVal.add(next, compositeOrListParam);
106                                                break;
107                                        case DATE:
108                                                DateOrListParam dateOrListParam = new DateOrListParam();
109                                                dateOrListParam.setValuesAsQueryTokens(paramList);
110                                                retVal.add(next, dateOrListParam);
111                                                break;
112                                        case NUMBER:
113                                                NumberOrListParam numberOrListParam = new NumberOrListParam();
114                                                numberOrListParam.setValuesAsQueryTokens(paramList);
115                                                retVal.add(next, numberOrListParam);
116                                                break;
117                                        case QUANTITY:
118                                                QuantityOrListParam quantityOrListParam = new QuantityOrListParam();
119                                                quantityOrListParam.setValuesAsQueryTokens(paramList);
120                                                retVal.add(next, quantityOrListParam);
121                                                break;
122                                        case REFERENCE:
123                                                ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam();
124                                                referenceOrListParam.setValuesAsQueryTokens(paramList);
125                                                retVal.add(next, referenceOrListParam);
126                                                break;
127                                        case STRING:
128                                                StringOrListParam stringOrListParam = new StringOrListParam();
129                                                stringOrListParam.setValuesAsQueryTokens(paramList);
130                                                retVal.add(next, stringOrListParam);
131                                                break;
132                                        case TOKEN:
133                                                TokenOrListParam tokenOrListParam = new TokenOrListParam();
134                                                tokenOrListParam.setValuesAsQueryTokens(paramList);
135                                                retVal.add(next, tokenOrListParam);
136                                                break;
137                                        case URI:
138                                                UriOrListParam uriOrListParam = new UriOrListParam();
139                                                uriOrListParam.setValuesAsQueryTokens(paramList);
140                                                retVal.add(next, uriOrListParam);
141                                                break;
142                                        }
143                                }
144                        }
145                }
146
147                return retVal;
148        }
149
150        private Class<? extends IQueryParameterType> toParamType(RuntimeSearchParam theRuntimeSearchParam) {
151                switch (theRuntimeSearchParam.getParamType()) {
152                case COMPOSITE:
153                        throw new IllegalStateException("Composite subtype");
154                case DATE:
155                        return DateParam.class;
156                case NUMBER:
157                        return NumberParam.class;
158                case QUANTITY:
159                        return QuantityParam.class;
160                case REFERENCE:
161                        return ReferenceParam.class;
162                case STRING:
163                        return StringParam.class;
164                case TOKEN:
165                        return TokenParam.class;
166                default:
167                        throw new IllegalStateException("null type");
168                }
169        }
170
171        @Override
172        public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
173                // nothing
174        }
175
176}