001package ca.uhn.fhir.rest.api; 002 003import ca.uhn.fhir.context.FhirContext; 004import ca.uhn.fhir.model.api.IQueryParameterOr; 005import ca.uhn.fhir.model.api.IQueryParameterType; 006 007import java.util.ArrayList; 008import java.util.StringTokenizer; 009 010import static org.apache.commons.lang3.StringUtils.isBlank; 011 012/* 013 * #%L 014 * HAPI FHIR - Core Library 015 * %% 016 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 017 * %% 018 * Licensed under the Apache License, Version 2.0 (the "License"); 019 * you may not use this file except in compliance with the License. 020 * You may obtain a copy of the License at 021 * 022 * http://www.apache.org/licenses/LICENSE-2.0 023 * 024 * Unless required by applicable law or agreed to in writing, software 025 * distributed under the License is distributed on an "AS IS" BASIS, 026 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 027 * See the License for the specific language governing permissions and 028 * limitations under the License. 029 * #L% 030 */ 031 032public class QualifiedParamList extends ArrayList<String> { 033 034 private static final long serialVersionUID = 1L; 035 036 private String myQualifier; 037 038 public QualifiedParamList() { 039 super(); 040 } 041 042 public QualifiedParamList(int theCapacity) { 043 super(theCapacity); 044 } 045 046 public QualifiedParamList(IQueryParameterOr<?> theNextOr, FhirContext theContext) { 047 for (IQueryParameterType next : theNextOr.getValuesAsQueryTokens()) { 048 if (myQualifier == null) { 049 myQualifier = next.getQueryParameterQualifier(); 050 } 051 add(next.getValueAsQueryToken(theContext)); 052 } 053 } 054 055 public String getQualifier() { 056 return myQualifier; 057 } 058 059 public void setQualifier(String theQualifier) { 060 myQualifier = theQualifier; 061 } 062 063 public static QualifiedParamList singleton(String theParamValue) { 064 return singleton(null, theParamValue); 065 } 066 067 public static QualifiedParamList singleton(String theQualifier, String theParamValue) { 068 QualifiedParamList retVal = new QualifiedParamList(1); 069 retVal.setQualifier(theQualifier); 070 retVal.add(theParamValue); 071 return retVal; 072 } 073 074 public static QualifiedParamList splitQueryStringByCommasIgnoreEscape(String theQualifier, String theParams) { 075 QualifiedParamList retVal = new QualifiedParamList(); 076 retVal.setQualifier(theQualifier); 077 078 StringTokenizer tok = new StringTokenizer(theParams, ",", true); 079 String prev = null; 080 while (tok.hasMoreElements()) { 081 String str = tok.nextToken(); 082 if (isBlank(str)) { 083 prev = null; 084 continue; 085 } 086 087 if (str.equals(",")) { 088 if (countTrailingSlashes(prev) % 2 == 1) { 089 int idx = retVal.size() - 1; 090 String existing = retVal.get(idx); 091 prev = existing.substring(0, existing.length() - 1) + ','; 092 retVal.set(idx, prev); 093 } else { 094 prev = null; 095 } 096 continue; 097 } 098 099 if (prev != null && prev.length() > 0 && prev.charAt(prev.length() - 1) == ',') { 100 int idx = retVal.size() - 1; 101 String existing = retVal.get(idx); 102 prev = existing + str; 103 retVal.set(idx, prev); 104 } else { 105 retVal.add(str); 106 prev = str; 107 } 108 109 } 110 111 // If no value was found, at least add that empty string as a value. It should get ignored later, but at 112 // least this lets us give a sensible error message if the parameter name was bad. See 113 // ResourceProviderR4Test#testParameterWithNoValueThrowsError_InvalidChainOnCustomSearch for an example 114 if (retVal.size() == 0) { 115 retVal.add(""); 116 } 117 118 return retVal; 119 } 120 121 private static int countTrailingSlashes(String theString) { 122 if (theString == null) { 123 return 0; 124 } 125 int retVal = 0; 126 for (int i = theString.length() - 1; i >= 0; i--) { 127 char nextChar = theString.charAt(i); 128 if (nextChar != '\\') { 129 break; 130 } 131 retVal++; 132 } 133 return retVal; 134 } 135 136}