001package ca.uhn.fhir.rest.param;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
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 ca.uhn.fhir.context.FhirContext;
024import ca.uhn.fhir.model.base.composite.BaseCodingDt;
025import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
026import ca.uhn.fhir.model.primitive.UriDt;
027import org.apache.commons.lang3.StringUtils;
028import org.apache.commons.lang3.builder.EqualsBuilder;
029import org.apache.commons.lang3.builder.HashCodeBuilder;
030import org.apache.commons.lang3.builder.ToStringBuilder;
031import org.apache.commons.lang3.builder.ToStringStyle;
032import org.hl7.fhir.instance.model.api.IBaseCoding;
033
034import static org.apache.commons.lang3.StringUtils.defaultString;
035import static org.apache.commons.lang3.StringUtils.isNotBlank;
036
037public class TokenParam extends BaseParam /*implements IQueryParameterType*/ {
038
039        private TokenParamModifier myModifier;
040        private String mySystem;
041        private String myValue;
042
043        private Boolean myMdmExpand;
044
045        /**
046         * Constructor
047         */
048        public TokenParam() {
049                super();
050        }
051
052        /**
053         * Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and
054         * {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a parameter
055         *
056         * @param theCodingDt The coding
057         */
058        public TokenParam(BaseCodingDt theCodingDt) {
059                this(toSystemValue(theCodingDt.getSystemElement()), theCodingDt.getCodeElement().getValue());
060        }
061
062        /**
063         * Constructor which copies the {@link BaseIdentifierDt#getSystemElement() system} and
064         * {@link BaseIdentifierDt#getValueElement() value} from a {@link BaseIdentifierDt} instance and adds it as a
065         * parameter
066         *
067         * @param theIdentifierDt The identifier
068         */
069        public TokenParam(BaseIdentifierDt theIdentifierDt) {
070                this(toSystemValue(theIdentifierDt.getSystemElement()), theIdentifierDt.getValueElement().getValue());
071        }
072
073        /**
074         * Construct a {@link TokenParam} from the {@link IBaseCoding#getSystem()} () system} and
075         * {@link IBaseCoding#getCode()} () code} of a {@link IBaseCoding} instance.
076         *
077         * @param theCoding The coding
078         */
079        public TokenParam(IBaseCoding theCoding) {
080                this(theCoding.getSystem(), theCoding.getCode());
081        }
082
083        public TokenParam(String theSystem, String theValue) {
084                setSystem(theSystem);
085                setValue(theValue);
086        }
087
088        public TokenParam(String theSystem, String theValue, boolean theText) {
089                if (theText && isNotBlank(theSystem)) {
090                        throw new IllegalArgumentException("theSystem can not be non-blank if theText is true (:text searches do not include a system). In other words, set the first parameter to null for a text search");
091                }
092                setSystem(theSystem);
093                setValue(theValue);
094                setText(theText);
095        }
096
097        /**
098         * Constructor that takes a code but no system
099         */
100        public TokenParam(String theCode) {
101                this(null, theCode);
102        }
103
104        public boolean isMdmExpand() {
105                return myMdmExpand != null && myMdmExpand;
106        }
107
108        public TokenParam setMdmExpand(boolean theMdmExpand) {
109                myMdmExpand = theMdmExpand;
110                return this;
111        }
112
113        @Override
114        String doGetQueryParameterQualifier() {
115                if (getModifier() != null) {
116                        return getModifier().getValue();
117                }
118                return null;
119        }
120
121        /**
122         * {@inheritDoc}
123         */
124        @Override
125        String doGetValueAsQueryToken(FhirContext theContext) {
126                if (getSystem() != null) {
127                        if (getValue() != null) {
128                                return ParameterUtil.escape(StringUtils.defaultString(getSystem())) + '|' + ParameterUtil.escape(getValue());
129                        } else {
130                                return ParameterUtil.escape(StringUtils.defaultString(getSystem())) + '|';
131                        }
132                }
133                return ParameterUtil.escape(getValue());
134        }
135
136        /**
137         * {@inheritDoc}
138         */
139        @Override
140        void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theParameter) {
141                setModifier(null);
142                if (theQualifier != null) {
143                        TokenParamModifier modifier = TokenParamModifier.forValue(theQualifier);
144                        setModifier(modifier);
145
146                        if (modifier == TokenParamModifier.TEXT) {
147                                setSystem(null);
148                                setValue(ParameterUtil.unescape(theParameter));
149                                return;
150                        }
151                }
152
153                setSystem(null);
154                if (theParameter == null) {
155                        setValue(null);
156                } else {
157                        int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
158                        if (barIndex != -1) {
159                                setSystem(theParameter.substring(0, barIndex));
160                                setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1)));
161                        } else {
162                                setValue(ParameterUtil.unescape(theParameter));
163                        }
164                }
165        }
166
167        /**
168         * Returns the modifier for this token
169         */
170        public TokenParamModifier getModifier() {
171                return myModifier;
172        }
173
174        public TokenParam setModifier(TokenParamModifier theModifier) {
175                myModifier = theModifier;
176                return this;
177        }
178
179        /**
180         * Returns the system for this token. Note that if a {@link #getModifier()} is being used, the entire value of the
181         * parameter will be placed in {@link #getValue() value} and this method will return <code>null</code>.
182         * <p
183         * Also note that this value may be <code>null</code> or <code>""</code> (empty string) and that
184         * each of these have a different meaning. When a token is passed on a URL and it has no
185         * vertical bar (often meaning "return values that match the given code in any codesystem")
186         * this method will return <code>null</code>. When a token is passed on a URL and it has
187         * a vetical bar but nothing before the bar (often meaning "return values that match the
188         * given code but that have no codesystem) this method will return <code>""</code>
189         * </p>
190         */
191        public String getSystem() {
192                return mySystem;
193        }
194
195        public TokenParam setSystem(String theSystem) {
196                mySystem = theSystem;
197                return this;
198        }
199
200        /**
201         * Returns the value for the token (generally the value to the right of the
202         * vertical bar on the URL)
203         */
204        public String getValue() {
205                return myValue;
206        }
207
208        public TokenParam setValue(String theValue) {
209                myValue = theValue;
210                return this;
211        }
212
213        public InternalCodingDt getValueAsCoding() {
214                return new InternalCodingDt(mySystem, myValue);
215        }
216
217        public String getValueNotNull() {
218                return defaultString(myValue);
219        }
220
221        public boolean isEmpty() {
222                return StringUtils.isBlank(mySystem) && StringUtils.isBlank(myValue) && getMissing() == null;
223        }
224
225        /**
226         * Returns true if {@link #getModifier()} returns {@link TokenParamModifier#TEXT}
227         */
228        public boolean isText() {
229                return myModifier == TokenParamModifier.TEXT;
230        }
231
232        /**
233         * @deprecated Use {@link #setModifier(TokenParamModifier)} instead
234         */
235        @Deprecated
236        public TokenParam setText(boolean theText) {
237                if (theText) {
238                        myModifier = TokenParamModifier.TEXT;
239                } else {
240                        myModifier = null;
241                }
242                return this;
243        }
244
245
246        @Override
247        public String toString() {
248                ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
249                builder.append("system", defaultString(getSystem()));
250                if (myModifier != null) {
251                        builder.append(":" + myModifier.getValue());
252                }
253                builder.append("value", getValue());
254                if (getMissing() != null) {
255                        builder.append(":missing", getMissing());
256                }
257                return builder.toString();
258        }
259
260        @Override
261        public boolean equals(Object theO) {
262                if (this == theO) {
263                        return true;
264                }
265
266                if (theO == null || getClass() != theO.getClass()) {
267                        return false;
268                }
269
270                TokenParam that = (TokenParam) theO;
271
272                EqualsBuilder b = new EqualsBuilder();
273                b.append(myModifier, that.myModifier);
274                b.append(mySystem, that.mySystem);
275                b.append(myValue, that.myValue);
276                return b.isEquals();
277        }
278
279        @Override
280        public int hashCode() {
281                HashCodeBuilder b = new HashCodeBuilder(17, 37);
282                b.append(myModifier);
283                b.append(mySystem);
284                b.append(myValue);
285                return b.toHashCode();
286        }
287
288        private static String toSystemValue(UriDt theSystem) {
289                return theSystem.getValueAsString();
290        }
291
292}