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