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