fix up processing of server responses

This commit is contained in:
Grahame Grieve 2024-10-09 23:10:09 +08:00
parent c030740d9e
commit cacce9b05e
7 changed files with 244 additions and 177 deletions

View File

@ -31,11 +31,14 @@ package org.hl7.fhir.r4.utils;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.IntegerType; import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r4.model.OperationOutcome.IssueType; import org.hl7.fhir.r4.model.OperationOutcome.IssueType;
import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class OperationOutcomeUtilities { public class OperationOutcomeUtilities {
@ -142,4 +145,18 @@ public class OperationOutcomeUtilities {
} }
return IssueType.NULL; return IssueType.NULL;
} }
public static OperationOutcome outcomeFromTextError(String text) {
OperationOutcome oo = new OperationOutcome();
oo.getText().setStatus(NarrativeStatus.GENERATED);
oo.getText().setDiv(new XhtmlNode(NodeType.Element, "div"));
oo.getText().getDiv().tx(text);
OperationOutcomeIssueComponent issue = oo.addIssue();
issue.setSeverity(IssueSeverity.ERROR);
issue.setCode(IssueType.EXCEPTION);
issue.getDetails().setText(text);
return oo;
}
} }

View File

@ -1,5 +1,7 @@
package org.hl7.fhir.r4.utils.client.network; package org.hl7.fhir.r4.utils.client.network;
import static org.hl7.fhir.r4.utils.OperationOutcomeUtilities.outcomeFromTextError;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -15,20 +17,19 @@ import org.hl7.fhir.r4.formats.XmlParser;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.utils.OperationOutcomeUtilities;
import org.hl7.fhir.r4.utils.ResourceUtilities; import org.hl7.fhir.r4.utils.ResourceUtilities;
import org.hl7.fhir.r4.utils.client.EFhirClientException; import org.hl7.fhir.r4.utils.client.EFhirClientException;
import org.hl7.fhir.r4.utils.client.ResourceFormat; import org.hl7.fhir.r4.utils.client.ResourceFormat;
import org.hl7.fhir.utilities.MimeType; import org.hl7.fhir.utilities.MimeType;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.settings.FhirSettings;
import org.hl7.fhir.utilities.xhtml.XhtmlUtils;
import okhttp3.Authenticator; import okhttp3.Authenticator;
import okhttp3.Credentials; import okhttp3.Credentials;
import okhttp3.Headers; import okhttp3.Headers;
import okhttp3.Headers.Builder;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
public class FhirRequestBuilder { public class FhirRequestBuilder {
@ -242,7 +243,7 @@ public class FhirRequestBuilder {
public <T extends Resource> ResourceRequest<T> execute() throws IOException { public <T extends Resource> ResourceRequest<T> execute() throws IOException {
formatHeaders(httpRequest, resourceFormat, headers); formatHeaders(httpRequest, resourceFormat, headers);
Response response = getHttpClient().newCall(httpRequest.build()).execute(); Response response = getHttpClient().newCall(httpRequest.build()).execute();
T resource = unmarshalReference(response, resourceFormat); T resource = unmarshalReference(response, resourceFormat, null);
return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers())); return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers()));
} }
@ -256,80 +257,64 @@ public class FhirRequestBuilder {
* Unmarshalls a resource from the response stream. * Unmarshalls a resource from the response stream.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T extends Resource> T unmarshalReference(Response response, String format) { protected <T extends Resource> T unmarshalReference(Response response, String format, String resourceType) {
T resource = null; if (response.body() == null) {
OperationOutcome error = null; return null;
byte[] body = null; }
Resource resource = null;
if (response.body() != null) { try {
try { String ct = response.header("Content-Type");
body = response.body().bytes(); if (ct == null) {
resource = (T) getParser(format).parse(body); resource = getParser(format).parse(response.body().bytes());
if (resource instanceof OperationOutcome && hasError((OperationOutcome) resource)) { } else {
error = (OperationOutcome) resource; switch (ct) {
case "application/json":
case "application/fhir+json":
resource = getParser(ResourceFormat.RESOURCE_JSON.getHeader()).parse(response.body().bytes());
break;
case "application/xml":
case "application/fhir+xml":
case "text/xml":
resource = getParser(ResourceFormat.RESOURCE_JSON.getHeader()).parse(response.body().bytes());
break;
case "text/plain":
resource = outcomeFromTextError(response.body().string());
break;
case "text/html" :
resource = OperationOutcomeUtilities.outcomeFromTextError(XhtmlUtils.convertHtmlToText(response.body().string()));
break;
default: // not sure what else to do?
System.out.println("Got content-type '"+ct+"' from "+source);
resource = OperationOutcomeUtilities.outcomeFromTextError(response.body().string());
} }
} catch (IOException ioe) { }
throw new EFhirClientException("Error reading Http Response from "+source+": " + ioe.getMessage(), ioe); } catch (IOException ioe) {
} catch (Exception e) { throw new EFhirClientException("Error reading Http Response from "+source+":"+ioe.getMessage(), ioe);
throw new EFhirClientException("Error parsing response message from "+source+": " + e.getMessage(), e); } catch (Exception e) {
throw new EFhirClientException("Error parsing response message from "+source+": "+e.getMessage(), e);
}
if (resource instanceof OperationOutcome && !"OperationOutcome".equals(resourceType)) {
OperationOutcome error = (OperationOutcome) resource;
if (hasError((OperationOutcome) resource)) {
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} else {
// umm, weird...
} }
} }
if (resource == null) {
if (error != null) { return null; // shouldn't get here?
String s = ResourceUtilities.getErrorDescription(error);
String reqid = response.header("x-request-id");
if (reqid == null) {
reqid = response.header("X-Request-Id");
}
if (reqid != null) {
s = s + " [x-request-id: "+reqid+"]";
}
System.out.println("Error from "+source+": " + s);
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} }
if (resourceType != null && !resource.fhirType().equals(resourceType)) {
return resource; throw new EFhirClientException("Error parsing response message from "+source+": Found an "+resource.fhirType()+" looking for a "+resourceType);
}
return (T) resource;
} }
/** /**
* Unmarshalls Bundle from response stream. * Unmarshalls Bundle from response stream.
*/ */
protected Bundle unmarshalFeed(Response response, String format) { protected Bundle unmarshalFeed(Response response, String format) {
Bundle feed = null; return unmarshalReference(response, format, "Bundle");
OperationOutcome error = null;
try {
byte[] body = response.body().bytes();
String contentType = response.header("Content-Type");
if (body != null) {
if (contentType.contains(ResourceFormat.RESOURCE_XML.getHeader())
|| contentType.contains(ResourceFormat.RESOURCE_JSON.getHeader())
|| contentType.contains("text/xml+fhir")) {
Resource rf = getParser(format).parse(body);
if (rf instanceof Bundle)
feed = (Bundle) rf;
else if (rf instanceof OperationOutcome && hasError((OperationOutcome) rf)) {
error = (OperationOutcome) rf;
} else {
throw new EFhirClientException("Error reading server response from "+source+": a resource was returned instead");
}
}
}
if (!response.isSuccessful() && feed == null && error == null) {
String text = TextFile.bytesToString(body);
throw new EFhirClientException("Error from "+source+": " + text);
}
} catch (EFhirClientException e) {
throw e;
} catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response from "+source+":"+ioe.getMessage(), ioe);
} catch (Exception e) {
throw new EFhirClientException("Error parsing response message from "+source+":"+e.getMessage(), e);
}
if (error != null) {
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
}
return feed;
} }
/** /**

View File

@ -33,11 +33,14 @@ import java.util.List;
import org.hl7.fhir.r4b.model.CodeableConcept; import org.hl7.fhir.r4b.model.CodeableConcept;
import org.hl7.fhir.r4b.model.IntegerType; import org.hl7.fhir.r4b.model.IntegerType;
import org.hl7.fhir.r4b.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r4b.model.OperationOutcome; import org.hl7.fhir.r4b.model.OperationOutcome;
import org.hl7.fhir.r4b.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.r4b.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r4b.model.OperationOutcome.IssueType; import org.hl7.fhir.r4b.model.OperationOutcome.IssueType;
import org.hl7.fhir.r4b.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.r4b.model.OperationOutcome.OperationOutcomeIssueComponent;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class OperationOutcomeUtilities { public class OperationOutcomeUtilities {
@ -154,4 +157,16 @@ public class OperationOutcomeUtilities {
} }
return res; return res;
} }
public static OperationOutcome outcomeFromTextError(String text) {
OperationOutcome oo = new OperationOutcome();
oo.getText().setStatus(NarrativeStatus.GENERATED);
oo.getText().setDiv(new XhtmlNode(NodeType.Element, "div"));
oo.getText().getDiv().tx(text);
OperationOutcomeIssueComponent issue = oo.addIssue();
issue.setSeverity(IssueSeverity.ERROR);
issue.setCode(IssueType.EXCEPTION);
issue.getDetails().setText(text);
return oo;
}
} }

View File

@ -1,6 +1,12 @@
package org.hl7.fhir.r4b.utils.client.network; package org.hl7.fhir.r4b.utils.client.network;
import okhttp3.*; import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r4b.formats.IParser; import org.hl7.fhir.r4b.formats.IParser;
import org.hl7.fhir.r4b.formats.JsonParser; import org.hl7.fhir.r4b.formats.JsonParser;
@ -8,18 +14,18 @@ import org.hl7.fhir.r4b.formats.XmlParser;
import org.hl7.fhir.r4b.model.Bundle; import org.hl7.fhir.r4b.model.Bundle;
import org.hl7.fhir.r4b.model.OperationOutcome; import org.hl7.fhir.r4b.model.OperationOutcome;
import org.hl7.fhir.r4b.model.Resource; import org.hl7.fhir.r4b.model.Resource;
import org.hl7.fhir.r4b.utils.OperationOutcomeUtilities;
import org.hl7.fhir.r4b.utils.ResourceUtilities; import org.hl7.fhir.r4b.utils.ResourceUtilities;
import org.hl7.fhir.r4b.utils.client.EFhirClientException; import org.hl7.fhir.r4b.utils.client.EFhirClientException;
import org.hl7.fhir.r4b.utils.client.ResourceFormat; import org.hl7.fhir.r4b.utils.client.ResourceFormat;
import org.hl7.fhir.utilities.ToolingClientLogger; import org.hl7.fhir.utilities.xhtml.XhtmlUtils;
import javax.annotation.Nonnull; import okhttp3.Authenticator;
import java.io.IOException; import okhttp3.Credentials;
import java.util.ArrayList; import okhttp3.Headers;
import java.util.Collections; import okhttp3.OkHttpClient;
import java.util.List; import okhttp3.Request;
import java.util.Map; import okhttp3.Response;
import java.util.concurrent.TimeUnit;
public class FhirRequestBuilder { public class FhirRequestBuilder {
@ -227,7 +233,7 @@ public class FhirRequestBuilder {
public <T extends Resource> ResourceRequest<T> execute() throws IOException { public <T extends Resource> ResourceRequest<T> execute() throws IOException {
formatHeaders(httpRequest, resourceFormat, headers); formatHeaders(httpRequest, resourceFormat, headers);
Response response = getHttpClient().newCall(httpRequest.build()).execute(); Response response = getHttpClient().newCall(httpRequest.build()).execute();
T resource = unmarshalReference(response, resourceFormat); T resource = unmarshalReference(response, resourceFormat, null);
return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers())); return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers()));
} }
@ -241,63 +247,64 @@ public class FhirRequestBuilder {
* Unmarshalls a resource from the response stream. * Unmarshalls a resource from the response stream.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T extends Resource> T unmarshalReference(Response response, String format) { protected <T extends Resource> T unmarshalReference(Response response, String format, String resourceType) {
T resource = null; if (response.body() == null) {
OperationOutcome error = null; return null;
}
if (response.body() != null) { Resource resource = null;
try { try {
byte[] body = response.body().bytes(); String ct = response.header("Content-Type");
resource = (T) getParser(format).parse(body); if (ct == null) {
if (resource instanceof OperationOutcome && hasError((OperationOutcome) resource)) { resource = getParser(format).parse(response.body().bytes());
error = (OperationOutcome) resource; } else {
switch (ct) {
case "application/json":
case "application/fhir+json":
resource = getParser(ResourceFormat.RESOURCE_JSON.getHeader()).parse(response.body().bytes());
break;
case "application/xml":
case "application/fhir+xml":
case "text/xml":
resource = getParser(ResourceFormat.RESOURCE_JSON.getHeader()).parse(response.body().bytes());
break;
case "text/plain":
resource = OperationOutcomeUtilities.outcomeFromTextError(response.body().string());
break;
case "text/html" :
resource = OperationOutcomeUtilities.outcomeFromTextError(XhtmlUtils.convertHtmlToText(response.body().string()));
break;
default: // not sure what else to do?
System.out.println("Got content-type '"+ct+"' from "+source);
resource = OperationOutcomeUtilities.outcomeFromTextError(response.body().string());
} }
} catch (IOException ioe) { }
throw new EFhirClientException("Error reading Http Response from "+source+": " + ioe.getMessage(), ioe); } catch (IOException ioe) {
} catch (Exception e) { throw new EFhirClientException("Error reading Http Response from "+source+":"+ioe.getMessage(), ioe);
throw new EFhirClientException("Error parsing response message from "+source+": " + e.getMessage(), e); } catch (Exception e) {
throw new EFhirClientException("Error parsing response message from "+source+": "+e.getMessage(), e);
}
if (resource instanceof OperationOutcome && !"OperationOutcome".equals(resourceType)) {
OperationOutcome error = (OperationOutcome) resource;
if (hasError((OperationOutcome) resource)) {
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} else {
// umm, weird...
} }
} }
if (resource == null) {
if (error != null) { return null; // shouldn't get here?
throw new EFhirClientException("Error from server: " + ResourceUtilities.getErrorDescription(error), error);
} }
if (resourceType != null && !resource.fhirType().equals(resourceType)) {
return resource; throw new EFhirClientException("Error parsing response message from "+source+": Found an "+resource.fhirType()+" looking for a "+resourceType);
}
return (T) resource;
} }
/** /**
* Unmarshalls Bundle from response stream. * Unmarshalls Bundle from response stream.
*/ */
protected Bundle unmarshalFeed(Response response, String format) { protected Bundle unmarshalFeed(Response response, String format) {
Bundle feed = null; return unmarshalReference(response, format, "Bundle");
OperationOutcome error = null;
try {
byte[] body = response.body().bytes();
String contentType = response.header("Content-Type");
if (body != null) {
if (contentType.contains(ResourceFormat.RESOURCE_XML.getHeader())
|| contentType.contains(ResourceFormat.RESOURCE_JSON.getHeader())
|| contentType.contains("text/xml+fhir")) {
Resource rf = getParser(format).parse(body);
if (rf instanceof Bundle)
feed = (Bundle) rf;
else if (rf instanceof OperationOutcome && hasError((OperationOutcome) rf)) {
error = (OperationOutcome) rf;
} else {
throw new EFhirClientException("Error reading server response: a resource was returned instead");
}
}
}
} catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response from "+source+": "+ioe.getMessage(), ioe);
} catch (Exception e) {
throw new EFhirClientException("Error parsing response message from "+source+": "+e.getMessage(), e);
}
if (error != null) {
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
}
return feed;
} }
/** /**

View File

@ -35,6 +35,7 @@ import java.util.List;
import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.IntegerType;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.r5.model.OperationOutcome.IssueType; import org.hl7.fhir.r5.model.OperationOutcome.IssueType;
@ -43,6 +44,8 @@ import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.UrlType; import org.hl7.fhir.r5.model.UrlType;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class OperationOutcomeUtilities { public class OperationOutcomeUtilities {
@ -180,4 +183,16 @@ public class OperationOutcomeUtilities {
return res; return res;
} }
public static OperationOutcome outcomeFromTextError(String text) {
OperationOutcome oo = new OperationOutcome();
oo.getText().setStatus(NarrativeStatus.GENERATED);
oo.getText().setDiv(new XhtmlNode(NodeType.Element, "div"));
oo.getText().getDiv().tx(text);
OperationOutcomeIssueComponent issue = oo.addIssue();
issue.setSeverity(IssueSeverity.ERROR);
issue.setCode(IssueType.EXCEPTION);
issue.getDetails().setText(text);
return oo;
}
} }

View File

@ -1,6 +1,12 @@
package org.hl7.fhir.r5.utils.client.network; package org.hl7.fhir.r5.utils.client.network;
import okhttp3.*; import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.formats.IParser; import org.hl7.fhir.r5.formats.IParser;
@ -9,18 +15,21 @@ import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.utils.OperationOutcomeUtilities;
import org.hl7.fhir.r5.utils.ResourceUtilities; import org.hl7.fhir.r5.utils.ResourceUtilities;
import org.hl7.fhir.r5.utils.client.EFhirClientException; import org.hl7.fhir.r5.utils.client.EFhirClientException;
import org.hl7.fhir.r5.utils.client.ResourceFormat; import org.hl7.fhir.r5.utils.client.ResourceFormat;
import org.hl7.fhir.utilities.MimeType; import org.hl7.fhir.utilities.MimeType;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.settings.FhirSettings;
import org.hl7.fhir.utilities.xhtml.XhtmlUtils;
import javax.annotation.Nonnull; import okhttp3.Authenticator;
import java.io.IOException; import okhttp3.Credentials;
import java.util.List; import okhttp3.Headers;
import java.util.Map; import okhttp3.OkHttpClient;
import java.util.concurrent.TimeUnit; import okhttp3.Request;
import okhttp3.Response;
public class FhirRequestBuilder { public class FhirRequestBuilder {
@ -227,7 +236,7 @@ public class FhirRequestBuilder {
public <T extends Resource> ResourceRequest<T> execute() throws IOException { public <T extends Resource> ResourceRequest<T> execute() throws IOException {
formatHeaders(httpRequest, resourceFormat, headers); formatHeaders(httpRequest, resourceFormat, headers);
Response response = getHttpClient().newCall(httpRequest.build()).execute(); Response response = getHttpClient().newCall(httpRequest.build()).execute();
T resource = unmarshalReference(response, resourceFormat); T resource = unmarshalReference(response, resourceFormat, null);
return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers())); return new ResourceRequest<T>(resource, response.code(), getLocationHeader(response.headers()));
} }
@ -241,50 +250,35 @@ public class FhirRequestBuilder {
* Unmarshalls a resource from the response stream. * Unmarshalls a resource from the response stream.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T extends Resource> T unmarshalReference(Response response, String format) { protected <T extends Resource> T unmarshalReference(Response response, String format, String resourceType) {
T resource = null; if (response.body() == null) {
OperationOutcome error = null; return null;
if (response.body() != null) {
try {
byte[] body = response.body().bytes();
resource = (T) getParser(format).parse(body);
if (resource instanceof OperationOutcome && hasError((OperationOutcome) resource)) {
error = (OperationOutcome) resource;
}
} catch (IOException ioe) {
throw new EFhirClientException("Error reading Http Response from "+source+": " + ioe.getMessage(), ioe);
} catch (Exception e) {
throw new EFhirClientException("Error parsing response message from "+source+": " + e.getMessage(), e);
}
} }
Resource resource = null;
if (error != null) {
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
}
return resource;
}
/**
* Unmarshalls Bundle from response stream.
*/
protected Bundle unmarshalFeed(Response response, String format) {
Bundle feed = null;
OperationOutcome error = null;
try { try {
byte[] body = response.body().bytes(); String ct = response.header("Content-Type");
String contentType = response.header("Content-Type"); if (ct == null) {
if (body != null) { resource = getParser(format).parse(response.body().bytes());
if (contentType.contains(ResourceFormat.RESOURCE_XML.getHeader()) || contentType.contains(ResourceFormat.RESOURCE_JSON.getHeader()) || contentType.contains("text/xml+fhir")) { } else {
Resource rf = getParser(format).parse(body); switch (ct) {
if (rf instanceof Bundle) case "application/json":
feed = (Bundle) rf; case "application/fhir+json":
else if (rf instanceof OperationOutcome && hasError((OperationOutcome) rf)) { resource = getParser(ResourceFormat.RESOURCE_JSON.getHeader()).parse(response.body().bytes());
error = (OperationOutcome) rf; break;
} else { case "application/xml":
throw new EFhirClientException("Error reading server response: a resource was returned instead"); case "application/fhir+xml":
} case "text/xml":
resource = getParser(ResourceFormat.RESOURCE_JSON.getHeader()).parse(response.body().bytes());
break;
case "text/plain":
resource = OperationOutcomeUtilities.outcomeFromTextError(response.body().string());
break;
case "text/html" :
resource = OperationOutcomeUtilities.outcomeFromTextError(XhtmlUtils.convertHtmlToText(response.body().string()));
break;
default: // not sure what else to do?
System.out.println("Got content-type '"+ct+"' from "+source);
resource = OperationOutcomeUtilities.outcomeFromTextError(response.body().string());
} }
} }
} catch (IOException ioe) { } catch (IOException ioe) {
@ -292,10 +286,28 @@ public class FhirRequestBuilder {
} catch (Exception e) { } catch (Exception e) {
throw new EFhirClientException("Error parsing response message from "+source+": "+e.getMessage(), e); throw new EFhirClientException("Error parsing response message from "+source+": "+e.getMessage(), e);
} }
if (error != null) { if (resource instanceof OperationOutcome && !"OperationOutcome".equals(resourceType)) {
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error); OperationOutcome error = (OperationOutcome) resource;
if (hasError((OperationOutcome) resource)) {
throw new EFhirClientException("Error from "+source+": " + ResourceUtilities.getErrorDescription(error), error);
} else {
// umm, weird...
}
} }
return feed; if (resource == null) {
return null; // shouldn't get here?
}
if (resourceType != null && !resource.fhirType().equals(resourceType)) {
throw new EFhirClientException("Error parsing response message from "+source+": Found an "+resource.fhirType()+" looking for a "+resourceType);
}
return (T) resource;
}
/**
* Unmarshalls Bundle from response stream.
*/
protected Bundle unmarshalFeed(Response response, String format) {
return unmarshalReference(response, format, "Bundle");
} }
/** /**

View File

@ -0,0 +1,16 @@
package org.hl7.fhir.utilities.xhtml;
public class XhtmlUtils {
public static String convertHtmlToText(String source) {
try {
XhtmlDocument doc = new XhtmlParser().parse(source, "html");
return doc.getDocumentElement().allText();
} catch (Exception e) {
e.printStackTrace();
// todo - should we try another way?
return "Unparseable HTML";
}
}
}