fix up processing of server responses
This commit is contained in:
parent
c030740d9e
commit
cacce9b05e
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue