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