001package ca.uhn.fhir.rest.client.method;
002
003import ca.uhn.fhir.context.ConfigurationException;
004import ca.uhn.fhir.context.FhirContext;
005import ca.uhn.fhir.context.FhirVersionEnum;
006import ca.uhn.fhir.context.RuntimeResourceDefinition;
007import ca.uhn.fhir.model.api.IResource;
008import ca.uhn.fhir.model.api.Include;
009import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
010import ca.uhn.fhir.model.api.TagList;
011import ca.uhn.fhir.model.primitive.IdDt;
012import ca.uhn.fhir.model.primitive.InstantDt;
013import ca.uhn.fhir.parser.IParser;
014import ca.uhn.fhir.rest.annotation.*;
015import ca.uhn.fhir.rest.api.Constants;
016import ca.uhn.fhir.rest.api.EncodingEnum;
017import ca.uhn.fhir.rest.api.MethodOutcome;
018import ca.uhn.fhir.rest.api.PatchTypeEnum;
019import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
020import ca.uhn.fhir.rest.api.SummaryEnum;
021import ca.uhn.fhir.rest.api.ValidationModeEnum;
022import ca.uhn.fhir.rest.client.api.IHttpRequest;
023import ca.uhn.fhir.rest.client.method.OperationParameter.IOperationParamConverter;
024import ca.uhn.fhir.rest.param.ParameterUtil;
025import ca.uhn.fhir.rest.param.binder.CollectionBinder;
026import ca.uhn.fhir.util.DateUtils;
027import ca.uhn.fhir.util.ParametersUtil;
028import ca.uhn.fhir.util.ReflectionUtil;
029import ca.uhn.fhir.util.UrlUtil;
030import org.apache.commons.lang3.StringUtils;
031import org.hl7.fhir.instance.model.api.IAnyResource;
032import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
033import org.hl7.fhir.instance.model.api.IBaseResource;
034import org.hl7.fhir.instance.model.api.IIdType;
035
036import java.io.IOException;
037import java.io.InputStream;
038import java.io.PushbackInputStream;
039import java.lang.annotation.Annotation;
040import java.lang.reflect.Method;
041import java.util.ArrayList;
042import java.util.Collection;
043import java.util.Date;
044import java.util.List;
045import java.util.Map;
046import java.util.Map.Entry;
047
048import static org.apache.commons.lang3.StringUtils.isNotBlank;
049
050/*
051 * #%L
052 * HAPI FHIR - Client Framework
053 * %%
054 * Copyright (C) 2014 - 2021 Smile CDR, Inc.
055 * %%
056 * Licensed under the Apache License, Version 2.0 (the "License");
057 * you may not use this file except in compliance with the License.
058 * You may obtain a copy of the License at
059 *
060 * http://www.apache.org/licenses/LICENSE-2.0
061 *
062 * Unless required by applicable law or agreed to in writing, software
063 * distributed under the License is distributed on an "AS IS" BASIS,
064 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
065 * See the License for the specific language governing permissions and
066 * limitations under the License.
067 * #L%
068 */
069
070public class MethodUtil {
071
072        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
073
074        /** Non instantiable */
075        private MethodUtil() {
076                // nothing
077        }
078
079        public static void addAcceptHeaderToRequest(EncodingEnum theEncoding, IHttpRequest theHttpRequest,
080                        FhirContext theContext) {
081                if (theEncoding == null) {
082                        if (theContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU2_1) == false) {
083                                theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_LEGACY);
084                        } else {
085                                theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON_NON_LEGACY);
086                        }
087                } else if (theEncoding == EncodingEnum.JSON) {
088                        if (theContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU2_1) == false) {
089                                theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON);
090                        } else {
091                                theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_JSON_NON_LEGACY);
092                        }
093                } else if (theEncoding == EncodingEnum.XML) {
094                        if (theContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU2_1) == false) {
095                                theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_XML);
096                        } else {
097                                theHttpRequest.addHeader(Constants.HEADER_ACCEPT, Constants.HEADER_ACCEPT_VALUE_XML_NON_LEGACY);
098                        }
099                }
100
101        }
102
103        public static HttpGetClientInvocation createConformanceInvocation(FhirContext theContext) {
104                return new HttpGetClientInvocation(theContext, "metadata");
105        }
106
107        public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, FhirContext theContext) {
108                return createCreateInvocation(theResource, null, theContext);
109        }
110
111        public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, String theResourceBody,
112                        FhirContext theContext) {
113                RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource);
114                String resourceName = def.getName();
115
116                StringBuilder urlExtension = new StringBuilder();
117                urlExtension.append(resourceName);
118
119                HttpPostClientInvocation retVal;
120                if (StringUtils.isBlank(theResourceBody)) {
121                        retVal = new HttpPostClientInvocation(theContext, theResource, urlExtension.toString());
122                } else {
123                        retVal = new HttpPostClientInvocation(theContext, theResourceBody, false, urlExtension.toString());
124                }
125
126                retVal.setOmitResourceId(true);
127
128                return retVal;
129        }
130
131        public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, String theResourceBody,
132                        FhirContext theContext, Map<String, List<String>> theIfNoneExistParams) {
133                HttpPostClientInvocation retVal = createCreateInvocation(theResource, theResourceBody, theContext);
134                retVal.setIfNoneExistParams(theIfNoneExistParams);
135                return retVal;
136        }
137
138        public static HttpPostClientInvocation createCreateInvocation(IBaseResource theResource, String theResourceBody,
139                        FhirContext theContext, String theIfNoneExistUrl) {
140                HttpPostClientInvocation retVal = createCreateInvocation(theResource, theResourceBody, theContext);
141                retVal.setIfNoneExistString(theIfNoneExistUrl);
142                return retVal;
143        }
144
145        public static HttpPatchClientInvocation createPatchInvocation(FhirContext theContext, IIdType theId,
146                        PatchTypeEnum thePatchType, String theBody) {
147                return PatchMethodBinding.createPatchInvocation(theContext, theId, thePatchType, theBody);
148        }
149
150        public static HttpPatchClientInvocation createPatchInvocation(FhirContext theContext, PatchTypeEnum thePatchType,
151                        String theBody, String theResourceType, Map<String, List<String>> theMatchParams) {
152                return PatchMethodBinding.createPatchInvocation(theContext, thePatchType, theBody, theResourceType,
153                                theMatchParams);
154        }
155
156        public static HttpPatchClientInvocation createPatchInvocation(FhirContext theContext, String theUrl,
157                        PatchTypeEnum thePatchType, String theBody) {
158                return PatchMethodBinding.createPatchInvocation(theContext, theUrl, thePatchType, theBody);
159        }
160
161        public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IBaseResource theResource,
162                        String theResourceBody, Map<String, List<String>> theMatchParams) {
163                String resourceType = theContext.getResourceType(theResource);
164
165                StringBuilder b = createUrl(resourceType, theMatchParams);
166
167                HttpPutClientInvocation retVal;
168                if (StringUtils.isBlank(theResourceBody)) {
169                        retVal = new HttpPutClientInvocation(theContext, theResource, b.toString());
170                } else {
171                        retVal = new HttpPutClientInvocation(theContext, theResourceBody, false, b.toString());
172                }
173
174                return retVal;
175        }
176
177        public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IBaseResource theResource,
178                        String theResourceBody, String theMatchUrl) {
179                HttpPutClientInvocation retVal;
180                if (StringUtils.isBlank(theResourceBody)) {
181                        retVal = new HttpPutClientInvocation(theContext, theResource, theMatchUrl);
182                } else {
183                        retVal = new HttpPutClientInvocation(theContext, theResourceBody, false, theMatchUrl);
184                }
185
186                return retVal;
187        }
188
189        public static HttpPutClientInvocation createUpdateInvocation(IBaseResource theResource, String theResourceBody,
190                        IIdType theId, FhirContext theContext) {
191                String resourceName = theContext.getResourceType(theResource);
192                StringBuilder urlBuilder = new StringBuilder();
193                urlBuilder.append(resourceName);
194                urlBuilder.append('/');
195                urlBuilder.append(theId.getIdPart());
196                String urlExtension = urlBuilder.toString();
197
198                HttpPutClientInvocation retVal;
199                if (StringUtils.isBlank(theResourceBody)) {
200                        retVal = new HttpPutClientInvocation(theContext, theResource, urlExtension);
201                } else {
202                        retVal = new HttpPutClientInvocation(theContext, theResourceBody, false, urlExtension);
203                }
204
205                retVal.setForceResourceId(theId);
206
207                if (theId.hasVersionIdPart()) {
208                        retVal.addHeader(Constants.HEADER_IF_MATCH, '"' + theId.getVersionIdPart() + '"');
209                }
210
211                return retVal;
212        }
213
214        public static StringBuilder createUrl(String theResourceType, Map<String, List<String>> theMatchParams) {
215                StringBuilder b = new StringBuilder();
216
217                b.append(theResourceType);
218
219                boolean haveQuestionMark = false;
220                for (Entry<String, List<String>> nextEntry : theMatchParams.entrySet()) {
221                        for (String nextValue : nextEntry.getValue()) {
222                                b.append(haveQuestionMark ? '&' : '?');
223                                haveQuestionMark = true;
224                                b.append(UrlUtil.escapeUrlParam(nextEntry.getKey()));
225                                b.append('=');
226                                b.append(UrlUtil.escapeUrlParam(nextValue));
227                        }
228                }
229                return b;
230        }
231
232        @SuppressWarnings("unchecked")
233        public static List<IParameter> getResourceParameters(final FhirContext theContext, Method theMethod,
234                        Object theProvider, RestOperationTypeEnum theRestfulOperationTypeEnum) {
235                List<IParameter> parameters = new ArrayList<>();
236
237                Class<?>[] parameterTypes = theMethod.getParameterTypes();
238                int paramIndex = 0;
239                for (Annotation[] annotations : theMethod.getParameterAnnotations()) {
240
241                        IParameter param = null;
242                        Class<?> parameterType = parameterTypes[paramIndex];
243                        Class<? extends java.util.Collection<?>> outerCollectionType = null;
244                        Class<? extends java.util.Collection<?>> innerCollectionType = null;
245                        if (TagList.class.isAssignableFrom(parameterType)) {
246                                // TagList is handled directly within the method bindings
247                                param = new NullParameter();
248                        } else {
249                                if (Collection.class.isAssignableFrom(parameterType)) {
250                                        innerCollectionType = (Class<? extends java.util.Collection<?>>) parameterType;
251                                        parameterType = ReflectionUtil.getGenericCollectionTypeOfMethodParameter(theMethod, paramIndex);
252                                }
253                                if (Collection.class.isAssignableFrom(parameterType)) {
254                                        outerCollectionType = innerCollectionType;
255                                        innerCollectionType = (Class<? extends java.util.Collection<?>>) parameterType;
256                                        parameterType = ReflectionUtil.getGenericCollectionTypeOfMethodParameter(theMethod, paramIndex);
257                                }
258                                if (Collection.class.isAssignableFrom(parameterType)) {
259                                        throw new ConfigurationException("Argument #" + paramIndex + " of Method '" + theMethod.getName()
260                                                        + "' in type '" + theMethod.getDeclaringClass().getCanonicalName()
261                                                        + "' is of an invalid generic type (can not be a collection of a collection of a collection)");
262                                }
263                        }
264
265                        if (parameterType.equals(SummaryEnum.class)) {
266                                param = new SummaryEnumParameter();
267                        } else if (parameterType.equals(PatchTypeEnum.class)) {
268                                param = new PatchTypeParameter();
269                        } else {
270                                for (int i = 0; i < annotations.length && param == null; i++) {
271                                        Annotation nextAnnotation = annotations[i];
272
273                                        if (nextAnnotation instanceof RequiredParam) {
274                                                SearchParameter parameter = new SearchParameter();
275                                                parameter.setName(((RequiredParam) nextAnnotation).name());
276                                                parameter.setRequired(true);
277                                                parameter.setDeclaredTypes(((RequiredParam) nextAnnotation).targetTypes());
278                                                parameter.setCompositeTypes(((RequiredParam) nextAnnotation).compositeTypes());
279                                                parameter.setChainlists(((RequiredParam) nextAnnotation).chainWhitelist());
280                                                parameter.setType(theContext, parameterType, innerCollectionType, outerCollectionType);
281                                                param = parameter;
282                                        } else if (nextAnnotation instanceof OptionalParam) {
283                                                SearchParameter parameter = new SearchParameter();
284                                                parameter.setName(((OptionalParam) nextAnnotation).name());
285                                                parameter.setRequired(false);
286                                                parameter.setDeclaredTypes(((OptionalParam) nextAnnotation).targetTypes());
287                                                parameter.setCompositeTypes(((OptionalParam) nextAnnotation).compositeTypes());
288                                                parameter.setChainlists(((OptionalParam) nextAnnotation).chainWhitelist());
289                                                parameter.setType(theContext, parameterType, innerCollectionType, outerCollectionType);
290                                                param = parameter;
291                                        } else if (nextAnnotation instanceof RawParam) {
292                                                param = new RawParamsParmeter();
293                                        } else if (nextAnnotation instanceof IncludeParam) {
294                                                Class<? extends Collection<Include>> instantiableCollectionType;
295                                                Class<?> specType;
296
297                                                if (parameterType == String.class) {
298                                                        instantiableCollectionType = null;
299                                                        specType = String.class;
300                                                } else if ((parameterType != Include.class) || innerCollectionType == null
301                                                                || outerCollectionType != null) {
302                                                        throw new ConfigurationException("Method '" + theMethod.getName() + "' is annotated with @"
303                                                                        + IncludeParam.class.getSimpleName() + " but has a type other than Collection<"
304                                                                        + Include.class.getSimpleName() + ">");
305                                                } else {
306                                                        instantiableCollectionType = (Class<? extends Collection<Include>>) CollectionBinder
307                                                                        .getInstantiableCollectionType(innerCollectionType,
308                                                                                        "Method '" + theMethod.getName() + "'");
309                                                        specType = parameterType;
310                                                }
311
312                                                param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType,                                                         specType);
313                                        } else if (nextAnnotation instanceof ResourceParam) {
314                                                if (IBaseResource.class.isAssignableFrom(parameterType)) {
315                                                        // good
316                                                } else if (String.class.equals(parameterType)) {
317                                                        // good
318                                                } else {
319                                                        StringBuilder b = new StringBuilder();
320                                                        b.append("Method '");
321                                                        b.append(theMethod.getName());
322                                                        b.append("' is annotated with @");
323                                                        b.append(ResourceParam.class.getSimpleName());
324                                                        b.append(" but has a type that is not an implementation of ");
325                                                        b.append(IBaseResource.class.getCanonicalName());
326                                                        throw new ConfigurationException(b.toString());
327                                                }
328                                                param = new ResourceParameter(parameterType);
329                                        } else if (nextAnnotation instanceof IdParam) {
330                                                param = new NullParameter();
331                                        } else if (nextAnnotation instanceof Elements) {
332                                                param = new ElementsParameter();
333                                        } else if (nextAnnotation instanceof Since) {
334                                                param = new SinceParameter();
335                                                ((SinceParameter) param).setType(theContext, parameterType, innerCollectionType,
336                                                                outerCollectionType);
337                                        } else if (nextAnnotation instanceof At) {
338                                                param = new AtParameter();
339                                                ((AtParameter) param).setType(theContext, parameterType, innerCollectionType,
340                                                                outerCollectionType);
341                                        } else if (nextAnnotation instanceof Count) {
342                                                param = new CountParameter();
343                                        } else if (nextAnnotation instanceof Offset) {
344                                                param = new OffsetParameter();
345                                        } else if (nextAnnotation instanceof Sort) {
346                                                param = new SortParameter(theContext);
347                                        } else if (nextAnnotation instanceof TransactionParam) {
348                                                param = new TransactionParameter(theContext);
349                                        } else if (nextAnnotation instanceof ConditionalUrlParam) {
350                                                param = new ConditionalParamBinder(theRestfulOperationTypeEnum,
351                                                                ((ConditionalUrlParam) nextAnnotation).supportsMultiple());
352                                        } else if (nextAnnotation instanceof OperationParam) {
353                                                Operation op = theMethod.getAnnotation(Operation.class);
354                                                param = new OperationParameter(theContext, op.name(), ((OperationParam) nextAnnotation));
355                                        } else if (nextAnnotation instanceof Validate.Mode) {
356                                                if (parameterType.equals(ValidationModeEnum.class) == false) {
357                                                        throw new ConfigurationException("Parameter annotated with @"
358                                                                        + Validate.class.getSimpleName() + "." + Validate.Mode.class.getSimpleName()
359                                                                        + " must be of type " + ValidationModeEnum.class.getName());
360                                                }
361                                                param = new OperationParameter(theContext, Constants.EXTOP_VALIDATE,
362                                                                Constants.EXTOP_VALIDATE_MODE, 0, 1).setConverter(new IOperationParamConverter() {
363                                                                        @Override
364                                                                        public Object outgoingClient(Object theObject) {
365                                                                                return ParametersUtil.createString(theContext,
366                                                                                                ((ValidationModeEnum) theObject).getCode());
367                                                                        }
368                                                                });
369                                        } else if (nextAnnotation instanceof Validate.Profile) {
370                                                if (parameterType.equals(String.class) == false) {
371                                                        throw new ConfigurationException("Parameter annotated with @"
372                                                                        + Validate.class.getSimpleName() + "." + Validate.Profile.class.getSimpleName()
373                                                                        + " must be of type " + String.class.getName());
374                                                }
375                                                param = new OperationParameter(theContext, Constants.EXTOP_VALIDATE,
376                                                                Constants.EXTOP_VALIDATE_PROFILE, 0, 1).setConverter(new IOperationParamConverter() {
377
378                                                                        @Override
379                                                                        public Object outgoingClient(Object theObject) {
380                                                                                return ParametersUtil.createString(theContext, theObject.toString());
381                                                                        }
382                                                                });
383                                        } else {
384                                                continue;
385                                        }
386
387                                }
388
389                        }
390
391                        if (param == null) {
392                                throw new ConfigurationException("Parameter #" + ((paramIndex + 1)) + "/" + (parameterTypes.length)
393                                                + " of method '" + theMethod.getName() + "' on type '"
394                                                + theMethod.getDeclaringClass().getCanonicalName()
395                                                + "' has no recognized FHIR interface parameter annotations. Don't know how to handle this parameter");
396                        }
397
398                        param.initializeTypes(theMethod, outerCollectionType, innerCollectionType, parameterType);
399                        parameters.add(param);
400
401                        paramIndex++;
402                }
403                return parameters;
404        }
405
406        public static void parseClientRequestResourceHeaders(IIdType theRequestedId, Map<String, List<String>> theHeaders,
407                        IBaseResource resource) {
408                List<String> lmHeaders = theHeaders.get(Constants.HEADER_LAST_MODIFIED_LOWERCASE);
409                if (lmHeaders != null && lmHeaders.size() > 0 && StringUtils.isNotBlank(lmHeaders.get(0))) {
410                        String headerValue = lmHeaders.get(0);
411                        Date headerDateValue;
412                        try {
413                                headerDateValue = DateUtils.parseDate(headerValue);
414                                if (resource instanceof IResource) {
415                                        IResource iResource = (IResource) resource;
416                                        InstantDt existing = ResourceMetadataKeyEnum.UPDATED.get(iResource);
417                                        if (existing == null || existing.isEmpty()) {
418                                                InstantDt lmValue = new InstantDt(headerDateValue);
419                                                iResource.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, lmValue);
420                                        }
421                                } else if (resource instanceof IAnyResource) {
422                                        IAnyResource anyResource = (IAnyResource) resource;
423                                        if (anyResource.getMeta().getLastUpdated() == null) {
424                                                anyResource.getMeta().setLastUpdated(headerDateValue);
425                                        }
426                                }
427                        } catch (Exception e) {
428                                ourLog.warn("Unable to parse date string '{}'. Error is: {}", headerValue, e.toString());
429                        }
430                }
431
432                List<String> clHeaders = theHeaders.get(Constants.HEADER_CONTENT_LOCATION_LC);
433                if (clHeaders != null && clHeaders.size() > 0 && StringUtils.isNotBlank(clHeaders.get(0))) {
434                        String headerValue = clHeaders.get(0);
435                        if (isNotBlank(headerValue)) {
436                                new IdDt(headerValue).applyTo(resource);
437                        }
438                }
439
440                List<String> locationHeaders = theHeaders.get(Constants.HEADER_LOCATION_LC);
441                if (locationHeaders != null && locationHeaders.size() > 0 && StringUtils.isNotBlank(locationHeaders.get(0))) {
442                        String headerValue = locationHeaders.get(0);
443                        if (isNotBlank(headerValue)) {
444                                new IdDt(headerValue).applyTo(resource);
445                        }
446                }
447
448                IdDt existing = IdDt.of(resource);
449
450                List<String> eTagHeaders = theHeaders.get(Constants.HEADER_ETAG_LC);
451                String eTagVersion = null;
452                if (eTagHeaders != null && eTagHeaders.size() > 0) {
453                        eTagVersion = ParameterUtil.parseETagValue(eTagHeaders.get(0));
454                }
455                if (isNotBlank(eTagVersion)) {
456                        if (existing == null || existing.isEmpty()) {
457                                if (theRequestedId != null) {
458                                        theRequestedId.withVersion(eTagVersion).applyTo(resource);
459                                }
460                        } else if (existing.hasVersionIdPart() == false) {
461                                existing.withVersion(eTagVersion).applyTo(resource);
462                        }
463                } else if (existing == null || existing.isEmpty()) {
464                        if (theRequestedId != null) {
465                                theRequestedId.applyTo(resource);
466                        }
467                }
468
469        }
470
471        public static MethodOutcome process2xxResponse(FhirContext theContext, int theResponseStatusCode,
472                        String theResponseMimeType, InputStream theResponseReader, Map<String, List<String>> theHeaders) {
473                List<String> locationHeaders = new ArrayList<>();
474                List<String> lh = theHeaders.get(Constants.HEADER_LOCATION_LC);
475                if (lh != null) {
476                        locationHeaders.addAll(lh);
477                }
478                List<String> clh = theHeaders.get(Constants.HEADER_CONTENT_LOCATION_LC);
479                if (clh != null) {
480                        locationHeaders.addAll(clh);
481                }
482
483                MethodOutcome retVal = new MethodOutcome();
484                if (locationHeaders.size() > 0) {
485                        String locationHeader = locationHeaders.get(0);
486                        BaseOutcomeReturningMethodBinding.parseContentLocation(theContext, retVal, locationHeader);
487                }
488                if (theResponseStatusCode != Constants.STATUS_HTTP_204_NO_CONTENT) {
489                        EncodingEnum ct = EncodingEnum.forContentType(theResponseMimeType);
490                        if (ct != null) {
491                                PushbackInputStream reader = new PushbackInputStream(theResponseReader);
492
493                                try {
494                                        int firstByte = reader.read();
495                                        if (firstByte == -1) {
496                                                BaseOutcomeReturningMethodBinding.ourLog.debug("No content in response, not going to read");
497                                                reader = null;
498                                        } else {
499                                                reader.unread(firstByte);
500                                        }
501                                } catch (IOException e) {
502                                        BaseOutcomeReturningMethodBinding.ourLog.debug("No content in response, not going to read", e);
503                                        reader = null;
504                                }
505
506                                if (reader != null) {
507                                        IParser parser = ct.newParser(theContext);
508                                        IBaseResource outcome = parser.parseResource(reader);
509                                        if (outcome instanceof IBaseOperationOutcome) {
510                                                retVal.setOperationOutcome((IBaseOperationOutcome) outcome);
511                                        } else {
512                                                retVal.setResource(outcome);
513                                        }
514                                }
515
516                        } else {
517                                BaseOutcomeReturningMethodBinding.ourLog.debug("Ignoring response content of type: {}",
518                                                theResponseMimeType);
519                        }
520                }
521                return retVal;
522        }
523
524}