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}