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