001package ca.uhn.fhir.rest.param;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2020 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 ca.uhn.fhir.context.FhirContext;
024import ca.uhn.fhir.model.primitive.IdDt;
025import ca.uhn.fhir.parser.DataFormatException;
026import ca.uhn.fhir.util.CoverageIgnore;
027import org.apache.commons.lang3.builder.ToStringBuilder;
028import org.apache.commons.lang3.builder.ToStringStyle;
029import org.hl7.fhir.instance.model.api.IBaseResource;
030
031import java.math.BigDecimal;
032
033import static ca.uhn.fhir.model.primitive.IdDt.isValidLong;
034import static org.apache.commons.lang3.StringUtils.*;
035
036public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/ {
037
038        private String myChain;
039        private String myResourceType;
040        private String myBaseUrl;
041        private String myValue;
042        private String myIdPart;
043
044        /**
045         * Constructor
046         */
047        public ReferenceParam() {
048                super();
049        }
050
051        /**
052         * Constructor
053         */
054        public ReferenceParam(String theValue) {
055                setValueAsQueryToken(null, null, null, theValue);
056        }
057
058        /**
059         * Constructor
060         */
061        public ReferenceParam(String theChain, String theValue) {
062                setValueAsQueryToken(null, null, null, theValue);
063                setChain(theChain);
064        }
065
066        /**
067         * Constructor
068         */
069        public ReferenceParam(String theResourceType, String theChain, String theValue) {
070                String qualifier = "";
071                if (isNotBlank(theResourceType)) {
072                        qualifier = ":" + theResourceType;
073                }
074                if (isNotBlank(theChain)) {
075                        qualifier = qualifier + "." + theChain;
076                }
077
078                setValueAsQueryToken(null, null, qualifier, theValue);
079        }
080
081        @Override
082        String doGetQueryParameterQualifier() {
083                StringBuilder b = new StringBuilder();
084                if (isNotBlank(myChain)) {
085                        if (isNotBlank(getResourceType())) {
086                                b.append(':');
087                                b.append(getResourceType());
088                        }
089                        b.append('.');
090                        b.append(myChain);
091                }
092                if (b.length() != 0) {
093                        return b.toString();
094                }
095                return null;
096        }
097
098        @Override
099        String doGetValueAsQueryToken(FhirContext theContext) {
100                if (isBlank(getResourceType())) {
101                        return myValue; // e.g. urn:asdjd or 123 or cid:wieiuru or #1
102                } else {
103                        if (isBlank(getChain()) && isNotBlank(getResourceType())) {
104                                return getResourceType() + "/" + getIdPart();
105                        }
106                        return myValue;
107                }
108        }
109
110        @Override
111        void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
112                String q = theQualifier;
113                if (isNotBlank(q)) {
114                        if (q.startsWith(":")) {
115                                int nextIdx = q.indexOf('.');
116                                if (nextIdx != -1) {
117                                        myChain = q.substring(nextIdx + 1);
118                                        myResourceType = q.substring(1, nextIdx);
119                                } else {
120                                        myChain = null;
121                                        myResourceType = q.substring(1);
122                                }
123
124                                myValue = theValue;
125                                myIdPart = theValue;
126
127                                IdDt id = new IdDt(theValue);
128                                if (!id.hasBaseUrl() && id.hasIdPart() && id.hasResourceType()) {
129                                        if (id.getResourceType().equals(myResourceType)) {
130                                                myIdPart = id.getIdPart();
131                                        }
132                                }
133
134                        } else if (q.startsWith(".")) {
135                                myChain = q.substring(1);
136                                myResourceType = null;
137                                myValue = theValue;
138                                myIdPart = theValue;
139                        }
140                } else {
141                        myChain = null;
142                        myValue = theValue;
143                        IdDt id = new IdDt(theValue);
144                        myResourceType = id.getResourceType();
145                        myIdPart = id.getIdPart();
146                        myBaseUrl = id.getBaseUrl();
147                }
148
149        }
150
151
152        @CoverageIgnore
153        public String getBaseUrl() {
154                return myBaseUrl;
155        }
156
157
158        public String getChain() {
159                return myChain;
160        }
161
162        public ReferenceParam setChain(String theChain) {
163                myChain = theChain;
164                return this;
165        }
166
167        @CoverageIgnore
168        public String getIdPart() {
169                return myIdPart;
170        }
171
172        @CoverageIgnore
173        public BigDecimal getIdPartAsBigDecimal() {
174                return new IdDt(myValue).getIdPartAsBigDecimal();
175        }
176
177        @CoverageIgnore
178        public Long getIdPartAsLong() {
179                return new IdDt(myValue).getIdPartAsLong();
180        }
181
182        public String getResourceType() {
183                if (isNotBlank(myResourceType)) {
184                        return myResourceType;
185                }
186                if (isBlank(myChain)) {
187                        return new IdDt(myValue).getResourceType();
188                }
189                return null;
190        }
191
192        public Class<? extends IBaseResource> getResourceType(FhirContext theCtx) {
193                if (isBlank(getResourceType())) {
194                        return null;
195                }
196                return theCtx.getResourceDefinition(getResourceType()).getImplementingClass();
197        }
198
199        public String getValue() {
200                return myValue;
201        }
202
203        public ReferenceParam setValue(String theValue) {
204                IdDt id = new IdDt(theValue);
205                String qualifier= null;
206                if (id.hasResourceType()) {
207                        qualifier = ":" + id.getResourceType();
208                }
209                setValueAsQueryToken(null, null, qualifier, id.getIdPart());
210                return this;
211        }
212
213        public boolean hasResourceType() {
214                return isNotBlank(myResourceType);
215        }
216
217        @Override
218        protected boolean isSupportsChain() {
219                return true;
220        }
221
222        /**
223         * Returns a new param containing the same value as this param, but with the type copnverted
224         * to {@link DateParam}. This is useful if you are using reference parameters and want to handle
225         * chained parameters of different types in a single method.
226         * <p>
227         * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
228         * in the HAPI FHIR documentation for an example of how to use this method.
229         * </p>
230         */
231        public DateParam toDateParam(FhirContext theContext) {
232                DateParam retVal = new DateParam();
233                retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
234                return retVal;
235        }
236
237        /**
238         * Returns a new param containing the same value as this param, but with the type copnverted
239         * to {@link NumberParam}. This is useful if you are using reference parameters and want to handle
240         * chained parameters of different types in a single method.
241         * <p>
242         * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
243         * in the HAPI FHIR documentation for an example of how to use this method.
244         * </p>
245         */
246        public NumberParam toNumberParam(FhirContext theContext) {
247                NumberParam retVal = new NumberParam();
248                retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
249                return retVal;
250        }
251
252        /**
253         * Returns a new param containing the same value as this param, but with the type copnverted
254         * to {@link QuantityParam}. This is useful if you are using reference parameters and want to handle
255         * chained parameters of different types in a single method.
256         * <p>
257         * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
258         * in the HAPI FHIR documentation for an example of how to use this method.
259         * </p>
260         */
261        public QuantityParam toQuantityParam(FhirContext theContext) {
262                QuantityParam retVal = new QuantityParam();
263                retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
264                return retVal;
265        }
266
267        @Override
268        public String toString() {
269                ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
270                if (isNotBlank(myChain)) {
271                        b.append("chain", myChain);
272                }
273                b.append("value", getValue());
274                return b.build();
275        }
276
277        /**
278         * Returns a new param containing the same value as this param, but with the type copnverted
279         * to {@link StringParam}. This is useful if you are using reference parameters and want to handle
280         * chained parameters of different types in a single method.
281         * <p>
282         * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
283         * in the HAPI FHIR documentation for an example of how to use this method.
284         * </p>
285         */
286        public StringParam toStringParam(FhirContext theContext) {
287                StringParam retVal = new StringParam();
288                retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
289                return retVal;
290        }
291
292        /**
293         * Returns a new param containing the same value as this param, but with the type copnverted
294         * to {@link TokenParam}. This is useful if you are using reference parameters and want to handle
295         * chained parameters of different types in a single method.
296         * <p>
297         * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a>
298         * in the HAPI FHIR documentation for an example of how to use this method.
299         * </p>
300         */
301        public TokenParam toTokenParam(FhirContext theContext) {
302                TokenParam retVal = new TokenParam();
303                retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext));
304                return retVal;
305        }
306
307        public boolean isIdPartValidLong() {
308                return isValidLong(getIdPart());
309        }
310}