001package ca.uhn.fhir.context;
002
003import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
004import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
005import org.apache.commons.lang3.builder.EqualsBuilder;
006import org.apache.commons.lang3.builder.HashCodeBuilder;
007import org.apache.commons.lang3.builder.ToStringBuilder;
008import org.apache.commons.lang3.builder.ToStringStyle;
009import org.hl7.fhir.instance.model.api.IBaseExtension;
010import org.hl7.fhir.instance.model.api.IIdType;
011
012import javax.annotation.Nonnull;
013import javax.annotation.Nullable;
014import java.util.ArrayList;
015import java.util.Collection;
016import java.util.Collections;
017import java.util.HashMap;
018import java.util.HashSet;
019import java.util.List;
020import java.util.Map;
021import java.util.Set;
022import java.util.StringTokenizer;
023
024import static org.apache.commons.lang3.StringUtils.isNotBlank;
025import static org.apache.commons.lang3.StringUtils.trim;
026
027/*
028 * #%L
029 * HAPI FHIR - Core Library
030 * %%
031 * Copyright (C) 2014 - 2021 Smile CDR, Inc.
032 * %%
033 * Licensed under the Apache License, Version 2.0 (the "License");
034 * you may not use this file except in compliance with the License.
035 * You may obtain a copy of the License at
036 *
037 *      http://www.apache.org/licenses/LICENSE-2.0
038 *
039 * Unless required by applicable law or agreed to in writing, software
040 * distributed under the License is distributed on an "AS IS" BASIS,
041 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
042 * See the License for the specific language governing permissions and
043 * limitations under the License.
044 * #L%
045 */
046
047public class RuntimeSearchParam {
048        private final IIdType myId;
049        private final Set<String> myBase;
050        private final String myDescription;
051        private final String myName;
052        private final RestSearchParameterTypeEnum myParamType;
053        private final String myPath;
054        private final Set<String> myTargets;
055        private final Set<String> myProvidesMembershipInCompartments;
056        private final RuntimeSearchParamStatusEnum myStatus;
057        private final String myUri;
058        private final Map<String, List<IBaseExtension<?, ?>>> myExtensions = new HashMap<>();
059        private final ComboSearchParamType myComboSearchParamType;
060        private final List<Component> myComponents;
061        private IPhoneticEncoder myPhoneticEncoder;
062
063        /**
064         * Constructor
065         */
066        public RuntimeSearchParam(IIdType theId, String theUri, String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType,
067                                                                          Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus, Collection<String> theBase) {
068                this(theId, theUri, theName, theDescription, thePath, theParamType, theProvidesMembershipInCompartments, theTargets, theStatus, null, Collections.emptyList(), theBase);
069        }
070
071        /**
072         * Copy constructor
073         */
074        public RuntimeSearchParam(RuntimeSearchParam theSp) {
075                this(theSp.getId(), theSp.getUri(), theSp.getName(), theSp.getDescription(), theSp.getPath(), theSp.getParamType(), theSp.getProvidesMembershipInCompartments(), theSp.getTargets(), theSp.getStatus(), theSp.getComboSearchParamType(), theSp.getComponents(), theSp.getBase());
076        }
077
078        /**
079         * Constructor
080         */
081        public RuntimeSearchParam(IIdType theId, String theUri, String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus, ComboSearchParamType theComboSearchParamType, List<Component> theComponents, Collection<String> theBase) {
082                super();
083
084                myId = theId;
085                myUri = theUri;
086                myName = theName;
087                myDescription = theDescription;
088                myPath = thePath;
089                myParamType = theParamType;
090                myStatus = theStatus;
091                if (theProvidesMembershipInCompartments != null && !theProvidesMembershipInCompartments.isEmpty()) {
092                        myProvidesMembershipInCompartments = Collections.unmodifiableSet(theProvidesMembershipInCompartments);
093                } else {
094                        myProvidesMembershipInCompartments = null;
095                }
096                if (theTargets != null && theTargets.isEmpty() == false) {
097                        myTargets = Collections.unmodifiableSet(theTargets);
098                } else {
099                        myTargets = Collections.emptySet();
100                }
101
102                if (theBase == null || theBase.isEmpty()) {
103                        HashSet<String> base = new HashSet<>();
104                        if (isNotBlank(thePath)) {
105                                int indexOf = thePath.indexOf('.');
106                                if (indexOf != -1) {
107                                        base.add(trim(thePath.substring(0, indexOf)));
108                                }
109                        }
110                        myBase = Collections.unmodifiableSet(base);
111                } else {
112                        myBase = Collections.unmodifiableSet(new HashSet<>(theBase));
113                }
114                myComboSearchParamType = theComboSearchParamType;
115                if (theComponents != null) {
116                        myComponents = Collections.unmodifiableList(theComponents);
117                } else {
118                        myComponents = Collections.emptyList();
119                }
120        }
121
122        public List<Component> getComponents() {
123                return myComponents;
124        }
125
126        /**
127         * Returns <code>null</code> if this is not a combo search param type
128         */
129        @Nullable
130        public ComboSearchParamType getComboSearchParamType() {
131                return myComboSearchParamType;
132        }
133
134        /**
135         * Retrieve user data - This can be used to store any application-specific data
136         */
137        @Nonnull
138        public List<IBaseExtension<?, ?>> getExtensions(String theKey) {
139                List<IBaseExtension<?, ?>> retVal = myExtensions.get(theKey);
140                if (retVal != null) {
141                        retVal = Collections.unmodifiableList(retVal);
142                } else {
143                        retVal = Collections.emptyList();
144                }
145                return retVal;
146        }
147
148        /**
149         * Sets user data - This can be used to store any application-specific data
150         */
151        public RuntimeSearchParam addExtension(String theKey, IBaseExtension theValue) {
152                List<IBaseExtension<?, ?>> valuesList = myExtensions.computeIfAbsent(theKey, k -> new ArrayList<>());
153                valuesList.add(theValue);
154                return this;
155        }
156
157        @Override
158        public String toString() {
159                return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
160                        .append("base", myBase)
161                        .append("name", myName)
162                        .append("path", myPath)
163                        .append("id", myId)
164                        .append("uri", myUri)
165                        .toString();
166        }
167
168        public IIdType getId() {
169                return myId;
170        }
171
172        public String getUri() {
173                return myUri;
174        }
175
176        @Override
177        public boolean equals(Object theO) {
178                if (this == theO) return true;
179
180                if (theO == null || getClass() != theO.getClass()) return false;
181
182                RuntimeSearchParam that = (RuntimeSearchParam) theO;
183
184                return new EqualsBuilder()
185                        .append(getId(), that.getId())
186                        .append(getName(), that.getName())
187                        .append(getPath(), that.getPath())
188                        .append(getUri(), that.getUri())
189                        .isEquals();
190        }
191
192        @Override
193        public int hashCode() {
194                return new HashCodeBuilder(17, 37)
195                        .append(getId())
196                        .append(getName())
197                        .append(getPath())
198                        .append(getUri())
199                        .toHashCode();
200        }
201
202        public Set<String> getBase() {
203                return myBase;
204        }
205
206        @Nonnull
207        public Set<String> getTargets() {
208                return myTargets;
209        }
210
211        public boolean hasTargets() {
212                return !myTargets.isEmpty();
213        }
214
215        public RuntimeSearchParamStatusEnum getStatus() {
216                return myStatus;
217        }
218
219        public String getDescription() {
220                return myDescription;
221        }
222
223        public String getName() {
224                return myName;
225        }
226
227        public RestSearchParameterTypeEnum getParamType() {
228                return myParamType;
229        }
230
231        public String getPath() {
232                return myPath;
233        }
234
235        public List<String> getPathsSplit() {
236                String path = getPath();
237                if (path.indexOf('|') == -1) {
238                        return Collections.singletonList(path);
239                }
240
241                List<String> retVal = new ArrayList<>();
242                StringTokenizer tok = new StringTokenizer(path, "|");
243                while (tok.hasMoreElements()) {
244                        String nextPath = tok.nextToken().trim();
245                        retVal.add(nextPath.trim());
246                }
247                return retVal;
248        }
249
250        /**
251         * Can return null
252         */
253        public Set<String> getProvidesMembershipInCompartments() {
254                return myProvidesMembershipInCompartments;
255        }
256
257        public RuntimeSearchParam setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
258                myPhoneticEncoder = thePhoneticEncoder;
259                return this;
260        }
261
262        public String encode(String theString) {
263                if (myPhoneticEncoder == null || theString == null) {
264                        return theString;
265                }
266                return myPhoneticEncoder.encode(theString);
267        }
268
269        public enum RuntimeSearchParamStatusEnum {
270                ACTIVE,
271                DRAFT,
272                RETIRED,
273                UNKNOWN
274        }
275
276        public static class Component {
277                private final String myExpression;
278                private final String myReference;
279
280                /**
281                 * Constructor
282                 */
283                public Component(String theExpression, String theReference) {
284                        myExpression = theExpression;
285                        myReference = theReference;
286
287                }
288
289                @Override
290                public String toString() {
291                        return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
292                                .append("expression", myExpression)
293                                .append("reference", myReference)
294                                .toString();
295                }
296
297                public String getExpression() {
298                        return myExpression;
299                }
300
301                public String getReference() {
302                        return myReference;
303                }
304        }
305
306}