001package ca.uhn.fhir.rest.param;
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.util.ArrayList;
024import java.util.Collections;
025import java.util.HashSet;
026import java.util.List;
027import java.util.Set;
028
029import ca.uhn.fhir.model.primitive.IntegerDt;
030import ca.uhn.fhir.util.UrlUtil;
031
032public class ParameterUtil {
033
034        private static final Set<Class<?>> BINDABLE_INTEGER_TYPES;
035
036        static {
037                HashSet<Class<?>> intTypes = new HashSet<Class<?>>();
038                intTypes.add(IntegerDt.class);
039                intTypes.add(Integer.class);
040                BINDABLE_INTEGER_TYPES = Collections.unmodifiableSet(intTypes);
041
042        }
043
044        // public static Integer findSinceParameterIndex(Method theMethod) {
045        // return findParamIndex(theMethod, Since.class);
046        // }
047
048        public static int nonEscapedIndexOf(String theString, char theCharacter) {
049                for (int i = 0; i < theString.length(); i++) {
050                        if (theString.charAt(i) == theCharacter) {
051                                if (i == 0 || theString.charAt(i - 1) != '\\') {
052                                        return i;
053                                }
054                        }
055                }
056                return -1;
057        }
058
059
060        public static Object fromInteger(Class<?> theType, IntegerDt theArgument) {
061                if (theType.equals(IntegerDt.class)) {
062                        if (theArgument == null) {
063                                return null;
064                        }
065                        return theArgument;
066                }
067                if (theType.equals(Integer.class)) {
068                        if (theArgument == null) {
069                                return null;
070                        }
071                        return theArgument.getValue();
072                }
073                throw new IllegalArgumentException("Invalid Integer type:" + theType);
074        }
075
076        public static Set<Class<?>> getBindableIntegerTypes() {
077                return BINDABLE_INTEGER_TYPES;
078        }
079
080
081        public static IntegerDt toInteger(Object theArgument) {
082                if (theArgument instanceof IntegerDt) {
083                        return (IntegerDt) theArgument;
084                }
085                if (theArgument instanceof Integer) {
086                        return new IntegerDt((Integer) theArgument);
087                }
088                return null;
089        }
090
091        static List<String> splitParameterString(String theInput, boolean theUnescapeComponents) {
092                return splitParameterString(theInput, ',', theUnescapeComponents);
093        }
094
095        static List<String> splitParameterString(String theInput, char theDelimiter, boolean theUnescapeComponents) {
096                ArrayList<String> retVal = new ArrayList<String>();
097                if (theInput != null) {
098                        StringBuilder b = new StringBuilder();
099                        for (int i = 0; i < theInput.length(); i++) {
100                                char next = theInput.charAt(i);
101                                if (next == theDelimiter) {
102                                        if (i == 0) {
103                                                b.append(next);
104                                        } else {
105                                                char prevChar = theInput.charAt(i - 1);
106                                                if (prevChar == '\\') {
107                                                        b.append(next);
108                                                } else {
109                                                        if (b.length() > 0) {
110                                                                retVal.add(b.toString());
111                                                        } else {
112                                                                retVal.add(null);
113                                                        }
114                                                        b.setLength(0);
115                                                }
116                                        }
117                                } else {
118                                        b.append(next);
119                                }
120                        }
121                        if (b.length() > 0) {
122                                retVal.add(b.toString());
123                        }
124                }
125
126                if (theUnescapeComponents) {
127                        for (int i = 0; i < retVal.size(); i++) {
128                                retVal.set(i, unescape(retVal.get(i)));
129                        }
130                }
131
132                return retVal;
133        }
134
135        /**
136         * Escapes a string according to the rules for parameter escaping specified in the <a href="http://www.hl7.org/implement/standards/fhir/search.html#escaping">FHIR Specification Escaping
137         * Section</a>
138         */
139        public static String escapeWithDefault(Object theValue) {
140                if (theValue == null) {
141                        return "";
142                }
143                return escape(theValue.toString());
144        }
145
146        /**
147         * Escapes a string according to the rules for parameter escaping specified in the <a href="http://www.hl7.org/implement/standards/fhir/search.html#escaping">FHIR Specification Escaping
148         * Section</a>
149         */
150        public static String escape(String theValue) {
151                if (theValue == null) {
152                        return null;
153                }
154                StringBuilder b = new StringBuilder();
155
156                for (int i = 0; i < theValue.length(); i++) {
157                        char next = theValue.charAt(i);
158                        switch (next) {
159                        case '$':
160                        case ',':
161                        case '|':
162                        case '\\':
163                                b.append('\\');
164                                break;
165                        default:
166                                break;
167                        }
168                        b.append(next);
169                }
170
171                return b.toString();
172        }
173
174        /**
175         * Escapes a string according to the rules for parameter escaping specified in the <a href="http://www.hl7.org/implement/standards/fhir/search.html#escaping">FHIR Specification Escaping
176         * Section</a>
177         */
178        public static String escapeAndUrlEncode(String theValue) {
179                if (theValue == null) {
180                        return null;
181                }
182                
183                String escaped = escape(theValue);
184                return UrlUtil.escape(escaped);
185        }
186
187        /**
188         * Unescapes a string according to the rules for parameter escaping specified in the <a href="http://www.hl7.org/implement/standards/fhir/search.html#escaping">FHIR Specification Escaping
189         * Section</a>
190         */
191        public static String unescape(String theValue) {
192                if (theValue == null) {
193                        return theValue;
194                }
195                if (theValue.indexOf('\\') == -1) {
196                        return theValue;
197                }
198
199                StringBuilder b = new StringBuilder();
200
201                for (int i = 0; i < theValue.length(); i++) {
202                        char next = theValue.charAt(i);
203                        if (next == '\\') {
204                                if (i == theValue.length() - 1) {
205                                        b.append(next);
206                                } else {
207                                        switch (theValue.charAt(i + 1)) {
208                                        case '$':
209                                        case ',':
210                                        case '|':
211                                        case '\\':
212                                                continue;
213                                        default:
214                                                b.append(next);
215                                        }
216                                }
217                        } else {
218                                b.append(next);
219                        }
220                }
221
222                return b.toString();
223        }
224
225}