001package ca.uhn.fhir.rest.method; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2017 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 String unqualifiedParamName = next; 077 RuntimeSearchParam param = myNameToParam.get(next); 078 if (param == null) { 079 int colonIndex = next.indexOf(':'); 080 int dotIndex = next.indexOf('.'); 081 if (colonIndex != -1 || dotIndex != -1) { 082 int index; 083 if (colonIndex != -1 && dotIndex != -1) { 084 index = Math.min(colonIndex, dotIndex); 085 } else { 086 index = (colonIndex != -1) ? colonIndex : dotIndex; 087 } 088 qualifier = next.substring(index); 089 next = next.substring(0, index); 090 unqualifiedParamName = next; 091 param = myNameToParam.get(next); 092 } 093 } 094 095 if (param != null) { 096 097 for (String nextValue : theRequest.getParameters().get(qualifiedParamName)) { 098 QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, nextValue); 099 100 FhirContext ctx = theRequest.getServer().getFhirContext(); 101 102 switch (param.getParamType()) { 103 case COMPOSITE: 104 Class<? extends IQueryParameterType> left = toParamType(param.getCompositeOf().get(0)); 105 Class<? extends IQueryParameterType> right = toParamType(param.getCompositeOf().get(0)); 106 @SuppressWarnings({ "rawtypes" }) 107 CompositeOrListParam compositeOrListParam = new CompositeOrListParam(left, right); 108 compositeOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 109 retVal.add(next, compositeOrListParam); 110 break; 111 case DATE: 112 DateOrListParam dateOrListParam = new DateOrListParam(); 113 dateOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 114 retVal.add(next, dateOrListParam); 115 break; 116 case NUMBER: 117 NumberOrListParam numberOrListParam = new NumberOrListParam(); 118 numberOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 119 retVal.add(next, numberOrListParam); 120 break; 121 case QUANTITY: 122 QuantityOrListParam quantityOrListParam = new QuantityOrListParam(); 123 quantityOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 124 retVal.add(next, quantityOrListParam); 125 break; 126 case REFERENCE: 127 ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam(); 128 referenceOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 129 retVal.add(next, referenceOrListParam); 130 break; 131 case STRING: 132 StringOrListParam stringOrListParam = new StringOrListParam(); 133 stringOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 134 retVal.add(next, stringOrListParam); 135 break; 136 case TOKEN: 137 TokenOrListParam tokenOrListParam = new TokenOrListParam(); 138 tokenOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 139 retVal.add(next, tokenOrListParam); 140 break; 141 case URI: 142 UriOrListParam uriOrListParam = new UriOrListParam(); 143 uriOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList); 144 retVal.add(next, uriOrListParam); 145 break; 146 case HAS: 147 // Should not happen 148 break; 149 } 150 } 151 } 152 } 153 154 return retVal; 155 } 156 157 private Class<? extends IQueryParameterType> toParamType(RuntimeSearchParam theRuntimeSearchParam) { 158 switch (theRuntimeSearchParam.getParamType()) { 159 case COMPOSITE: 160 throw new IllegalStateException("Composite subtype"); 161 case DATE: 162 return DateParam.class; 163 case NUMBER: 164 return NumberParam.class; 165 case QUANTITY: 166 return QuantityParam.class; 167 case REFERENCE: 168 return ReferenceParam.class; 169 case STRING: 170 return StringParam.class; 171 case TOKEN: 172 return TokenParam.class; 173 default: 174 throw new IllegalStateException("null type"); 175 } 176 } 177 178 @Override 179 public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) { 180 // nothing 181 } 182 183}