001package ca.uhn.fhir.rest.param; 002 003import static org.apache.commons.lang3.StringUtils.isNotBlank; 004 005/* 006 * #%L 007 * HAPI FHIR - Core Library 008 * %% 009 * Copyright (C) 2014 - 2016 University Health Network 010 * %% 011 * Licensed under the Apache License, Version 2.0 (the "License"); 012 * you may not use this file except in compliance with the License. 013 * You may obtain a copy of the License at 014 * 015 * http://www.apache.org/licenses/LICENSE-2.0 016 * 017 * Unless required by applicable law or agreed to in writing, software 018 * distributed under the License is distributed on an "AS IS" BASIS, 019 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 020 * See the License for the specific language governing permissions and 021 * limitations under the License. 022 * #L% 023 */ 024 025import java.lang.reflect.Method; 026import java.util.ArrayList; 027import java.util.Collection; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031 032import org.hl7.fhir.instance.model.api.IBaseResource; 033 034import ca.uhn.fhir.context.FhirContext; 035import ca.uhn.fhir.rest.method.BaseMethodBinding; 036import ca.uhn.fhir.rest.method.IParameter; 037import ca.uhn.fhir.rest.method.QualifiedParamList; 038import ca.uhn.fhir.rest.method.RequestDetails; 039import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum; 040import ca.uhn.fhir.rest.method.SearchMethodBinding; 041import ca.uhn.fhir.rest.method.SearchMethodBinding.QualifierDetails; 042import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 043import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 044 045public abstract class BaseQueryParameter implements IParameter { 046 047 private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseQueryParameter.class); 048 049 public abstract List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException; 050 051 public abstract String getName(); 052 053 public abstract RestSearchParameterTypeEnum getParamType(); 054 055 /** 056 * Returns null if blacklist is "none" 057 */ 058 public Set<String> getQualifierBlacklist() { 059 return null; 060 } 061 062 /** 063 * Returns null if whitelist is "all" 064 */ 065 public Set<String> getQualifierWhitelist() { 066 return null; 067 } 068 069 /** 070 * Parameter should return true if {@link #parse(FhirContext, List)} should be called even if the query string 071 * contained no values for the given parameter 072 */ 073 public abstract boolean handlesMissing(); 074 075 @Override 076 public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) { 077 // ignore for now 078 } 079 080 public abstract boolean isRequired(); 081 082 public abstract Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException; 083 084 private void parseParams(RequestDetails theRequest, List<QualifiedParamList> paramList, String theQualifiedParamName, String theQualifier) { 085 QualifierDetails qualifiers = SearchMethodBinding.extractQualifiersFromParameterName(theQualifier); 086 if (!qualifiers.passes(getQualifierWhitelist(), getQualifierBlacklist())) { 087 return; 088 } 089 090 String[] value = theRequest.getParameters().get(theQualifiedParamName); 091 if (value != null) { 092 for (String nextParam : value) { 093 if (nextParam.contains(",") == false) { 094 paramList.add(QualifiedParamList.singleton(theQualifier, nextParam)); 095 } else { 096 paramList.add(QualifiedParamList.splitQueryStringByCommasIgnoreEscape(theQualifier, nextParam)); 097 } 098 } 099 } 100 } 101 102 @Override 103 public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { 104 if (theSourceClientArgument == null) { 105 if (isRequired()) { 106 throw new NullPointerException("SearchParameter '" + getName() + "' is required and may not be null"); 107 } 108 } else { 109 List<QualifiedParamList> value = encode(theContext, theSourceClientArgument); 110 111 for (QualifiedParamList nextParamEntry : value) { 112 StringBuilder b = new StringBuilder(); 113 for (String str : nextParamEntry) { 114 if (b.length() > 0) { 115 b.append(","); 116 } 117 b.append(str); 118 } 119 120 String qualifier = nextParamEntry.getQualifier(); 121 String paramName = isNotBlank(qualifier) ? getName() + qualifier : getName(); 122 List<String> paramValues = theTargetQueryArguments.get(paramName); 123 if (paramValues == null) { 124 paramValues = new ArrayList<String>(value.size()); 125 theTargetQueryArguments.put(paramName, paramValues); 126 } 127 128 paramValues.add(b.toString()); 129 } 130 131 } 132 } 133 134 @Override 135 public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException { 136 137 List<QualifiedParamList> paramList = new ArrayList<QualifiedParamList>(); 138 String name = getName(); 139 parseParams(theRequest, paramList, name, null); 140 141 List<String> qualified = theRequest.getUnqualifiedToQualifiedNames().get(name); 142 if (qualified != null) { 143 for (String nextQualified : qualified) { 144 parseParams(theRequest, paramList, nextQualified, nextQualified.substring(name.length())); 145 } 146 } 147 148 if (paramList.isEmpty()) { 149 150 ourLog.debug("No value for parameter '{}' - Qualified names {} and qualifier whitelist {}", new Object[] { getName(), qualified, getQualifierWhitelist() }); 151 152 if (handlesMissing()) { 153 return parse(theRequest.getServer().getFhirContext(), paramList); 154 } else { 155 return null; 156 } 157 } 158 159 return parse(theRequest.getServer().getFhirContext(), paramList); 160 161 } 162 163}