Fix connectathon discovered issues
This commit is contained in:
parent
c666b9c196
commit
48d56b4722
|
@ -50,11 +50,6 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return super.isBaseEmpty() && (getValue() == null || getValue().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which accepts a string code
|
||||
*
|
||||
|
@ -65,27 +60,25 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
setValueAsString(theTextDiv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a textual DIV and parses it into XHTML events which are stored internally.
|
||||
* <p>
|
||||
* <b>Formatting note:</b> The text will be trimmed {@link String#trim()}. If the text does not start with an HTML tag (generally this would be a div tag), a div tag will be automatically placed
|
||||
* surrounding the text.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also note that if the parsed text contains any entities (&foo;) which are not a part of the entities defined in core XML (e.g. &sect; which
|
||||
* is valid in XHTML 1.0 but not in XML 1.0) they will be parsed and converted to their equivalent unicode character.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void setValueAsString(String theValue) throws DataFormatException {
|
||||
if (theValue == null || theValue.isEmpty()) {
|
||||
super.setValueAsString(null);
|
||||
} else {
|
||||
String value = theValue.trim();
|
||||
if (value.charAt(0) != '<') {
|
||||
value = "<div>" + value + "</div>";
|
||||
protected String encode(List<XMLEvent> theValue) {
|
||||
try {
|
||||
StringWriter w = new StringWriter();
|
||||
XMLEventWriter ew = XmlUtil.createXmlFragmentWriter(w);
|
||||
|
||||
for (XMLEvent next : getValue()) {
|
||||
if (next.isCharacters()) {
|
||||
ew.add(next);
|
||||
} else {
|
||||
ew.add(next);
|
||||
}
|
||||
}
|
||||
super.setValueAsString(value);
|
||||
ew.close();
|
||||
return w.toString();
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("Problem with the contained XML events", e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,6 +86,11 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
return getValue() != null && getValue().size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return super.isBaseEmpty() && (getValue() == null || getValue().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLEvent> parse(String theValue) {
|
||||
String val = theValue.trim();
|
||||
|
@ -128,24 +126,27 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a textual DIV and parses it into XHTML events which are stored internally.
|
||||
* <p>
|
||||
* <b>Formatting note:</b> The text will be trimmed {@link String#trim()}. If the text does not start with an HTML tag (generally this would be a div tag), a div tag will be automatically placed
|
||||
* surrounding the text.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also note that if the parsed text contains any entities (&foo;) which are not a part of the entities defined in core XML (e.g. &sect; which is valid in XHTML 1.0 but not in XML 1.0) they
|
||||
* will be parsed and converted to their equivalent unicode character.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
protected String encode(List<XMLEvent> theValue) {
|
||||
try {
|
||||
StringWriter w = new StringWriter();
|
||||
XMLEventWriter ew = XmlUtil.createXmlWriter(w);
|
||||
for (XMLEvent next : getValue()) {
|
||||
if (next.isCharacters()) {
|
||||
ew.add(next);
|
||||
} else {
|
||||
ew.add(next);
|
||||
}
|
||||
public void setValueAsString(String theValue) throws DataFormatException {
|
||||
if (theValue == null || theValue.isEmpty()) {
|
||||
super.setValueAsString(null);
|
||||
} else {
|
||||
String value = theValue.trim();
|
||||
if (value.charAt(0) != '<') {
|
||||
value = "<div>" + value + "</div>";
|
||||
}
|
||||
ew.close();
|
||||
return w.toString();
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("Problem with the contained XML events", e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
super.setValueAsString(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,11 +43,13 @@ import ca.uhn.fhir.util.OperationOutcomeUtil;
|
|||
|
||||
public class ExceptionHandlingInterceptor extends InterceptorAdapter {
|
||||
|
||||
public static final String PROCESSING = "processing";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExceptionHandlingInterceptor.class);
|
||||
private Class<?>[] myReturnStackTracesForExceptionTypes;
|
||||
|
||||
@Override
|
||||
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
|
||||
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theRequest, HttpServletResponse theResponse)
|
||||
throws ServletException, IOException {
|
||||
|
||||
FhirContext ctx = theRequestDetails.getServer().getFhirContext();
|
||||
|
||||
|
@ -116,12 +118,20 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
|
|||
ourLog.error("Failure during REST processing", theException);
|
||||
populateDetails(ctx, theException, oo);
|
||||
} else if (theException instanceof BaseServerResponseException) {
|
||||
ourLog.warn("Failure during REST processing: {}", theException);
|
||||
int statusCode = ((BaseServerResponseException) theException).getStatusCode();
|
||||
|
||||
// No stack traces for non-server internal errors
|
||||
if (statusCode < 500) {
|
||||
ourLog.warn("Failure during REST processing: {}", theException.toString());
|
||||
} else {
|
||||
ourLog.warn("Failure during REST processing: {}", theException);
|
||||
}
|
||||
|
||||
BaseServerResponseException baseServerResponseException = (BaseServerResponseException) theException;
|
||||
populateDetails(ctx, theException, oo);
|
||||
if (baseServerResponseException.getAdditionalMessages() != null) {
|
||||
for (String next : baseServerResponseException.getAdditionalMessages()) {
|
||||
OperationOutcomeUtil.addIssue(ctx, oo, "error", next);
|
||||
OperationOutcomeUtil.addIssue(ctx, oo, "error", next, null, PROCESSING);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -143,19 +153,18 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
|
|||
for (Class<?> next : myReturnStackTracesForExceptionTypes) {
|
||||
if (next.isAssignableFrom(theException.getClass())) {
|
||||
String detailsValue = theException.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(theException);
|
||||
OperationOutcomeUtil.addIssue(theCtx, theOo, "error", detailsValue);
|
||||
OperationOutcomeUtil.addIssue(theCtx, theOo, "error", detailsValue, null, PROCESSING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OperationOutcomeUtil.addIssue(theCtx, theOo, "error", theException.getMessage());
|
||||
OperationOutcomeUtil.addIssue(theCtx, theOo, "error", theException.getMessage(), null, PROCESSING);
|
||||
}
|
||||
|
||||
/**
|
||||
* If any server methods throw an exception which extends any of the given exception types, the exception stack trace
|
||||
* will be returned to the user. This can be useful for helping to diagnose issues, but may not be desirable for
|
||||
* production situations.
|
||||
* If any server methods throw an exception which extends any of the given exception types, the exception stack trace will be returned to the user. This can be useful for helping to diagnose
|
||||
* issues, but may not be desirable for production situations.
|
||||
*
|
||||
* @param theExceptionTypes
|
||||
* The exception types for which to return the stack trace to the user.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -24,6 +26,7 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -38,6 +41,7 @@ import ca.uhn.fhir.rest.method.RequestDetails;
|
|||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
|
||||
/**
|
||||
* Server interceptor which logs each request using a defined format
|
||||
|
@ -67,8 +71,8 @@ import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
|||
* </tr>
|
||||
* <tr>
|
||||
* <td>${requestHeader.XXXX}</td>
|
||||
* <td>The value of the HTTP request header named XXXX. For example, a substitution variable named
|
||||
* "${requestHeader.x-forwarded-for} will yield the value of the first header named "x-forwarded-for", or "" if none.</td>
|
||||
* <td>The value of the HTTP request header named XXXX. For example, a substitution variable named "${requestHeader.x-forwarded-for} will yield the value of the first header named "x-forwarded-for
|
||||
* ", or "" if none.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>${requestParameters}</td>
|
||||
|
@ -82,15 +86,52 @@ import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
|||
* <td>${servletPath}</td>
|
||||
* <td>The part of thre requesting URL that corresponds to the particular Servlet being called (see {@link HttpServletRequest#getServletPath()})</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>${requestUrl}</td>
|
||||
* <td>The complete URL of the request</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>${requestVerb}</td>
|
||||
* <td>The HTTP verb of the request</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>${exceptionMessage}</td>
|
||||
* <td>Applies only to an error message: The message from {@link Exception#getMessage()}</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public class LoggingInterceptor extends InterceptorAdapter {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LoggingInterceptor.class);
|
||||
|
||||
private String myErrorMessageFormat = "ERROR - ${idOrResourceName}";
|
||||
private boolean myLogExceptions;
|
||||
private Logger myLogger = ourLog;
|
||||
private String myMessageFormat = "${operationType} - ${idOrResourceName}";
|
||||
|
||||
/**
|
||||
* Get the log message format to be used when logging exceptions
|
||||
*/
|
||||
public String getErrorMessageFormat() {
|
||||
return myErrorMessageFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
|
||||
throws ServletException, IOException {
|
||||
if (myLogExceptions) {
|
||||
// Perform any string substitutions from the message format
|
||||
StrLookup<?> lookup = new MyLookup(theServletRequest, theException, theRequestDetails);
|
||||
StrSubstitutor subs = new StrSubstitutor(lookup, "${", "}", '\\');
|
||||
|
||||
// Actuall log the line
|
||||
String line = subs.replace(myErrorMessageFormat);
|
||||
myLogger.info(line);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean incomingRequestPostProcessed(final RequestDetails theRequestDetails, final HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException {
|
||||
|
||||
|
@ -105,6 +146,28 @@ public class LoggingInterceptor extends InterceptorAdapter {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should exceptions be logged by this logger
|
||||
*/
|
||||
public boolean isLogExceptions() {
|
||||
return myLogExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the log message format to be used when logging exceptions
|
||||
*/
|
||||
public void setErrorMessageFormat(String theErrorMessageFormat) {
|
||||
Validate.notBlank(theErrorMessageFormat, "Message format can not be null/empty");
|
||||
myErrorMessageFormat = theErrorMessageFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should exceptions be logged by this logger
|
||||
*/
|
||||
public void setLogExceptions(boolean theLogExceptions) {
|
||||
myLogExceptions = theLogExceptions;
|
||||
}
|
||||
|
||||
public void setLogger(Logger theLogger) {
|
||||
Validate.notNull(theLogger, "Logger can not be null");
|
||||
myLogger = theLogger;
|
||||
|
@ -125,12 +188,20 @@ public class LoggingInterceptor extends InterceptorAdapter {
|
|||
}
|
||||
|
||||
private static final class MyLookup extends StrLookup<String> {
|
||||
private final Throwable myException;
|
||||
private final HttpServletRequest myRequest;
|
||||
private final RequestDetails myRequestDetails;
|
||||
|
||||
private MyLookup(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
|
||||
myRequest = theRequest;
|
||||
myRequestDetails = theRequestDetails;
|
||||
myException = null;
|
||||
}
|
||||
|
||||
public MyLookup(HttpServletRequest theServletRequest, BaseServerResponseException theException, RequestDetails theRequestDetails) {
|
||||
myException = theException;
|
||||
myRequestDetails = theRequestDetails;
|
||||
myRequest = theServletRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -204,6 +275,12 @@ public class LoggingInterceptor extends InterceptorAdapter {
|
|||
} else {
|
||||
return "";
|
||||
}
|
||||
} else if (theKey.equals("exceptionMessage")) {
|
||||
return myException != null ? myException.getMessage() : null;
|
||||
} else if (theKey.equals("requestUrl")) {
|
||||
return myRequest.getRequestURL().toString();
|
||||
} else if (theKey.equals("requestVerb")) {
|
||||
return myRequest.getMethod();
|
||||
}
|
||||
|
||||
return "!VAL!";
|
||||
|
|
|
@ -42,22 +42,23 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|||
*/
|
||||
public class OperationOutcomeUtil {
|
||||
|
||||
/**
|
||||
* Add an issue to an OperationOutcome
|
||||
*
|
||||
* @param theCtx
|
||||
* The fhir context
|
||||
* @param theOperationOutcome
|
||||
* The OO resource to add to
|
||||
* @param theSeverity
|
||||
* The severity (e.g. "error")
|
||||
* @param theDetails
|
||||
* The details string
|
||||
*/
|
||||
public static void addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails) {
|
||||
IBase issue = createIssue(theCtx, theOperationOutcome);
|
||||
populateDetails(theCtx, issue, theSeverity, theDetails, null);
|
||||
}
|
||||
// /**
|
||||
// * Add an issue to an OperationOutcome
|
||||
// *
|
||||
// * @param theCtx
|
||||
// * The fhir context
|
||||
// * @param theOperationOutcome
|
||||
// * The OO resource to add to
|
||||
// * @param theSeverity
|
||||
// * The severity (e.g. "error")
|
||||
// * @param theDetails
|
||||
// * The details string
|
||||
// * @param theCode
|
||||
// */
|
||||
// public static void addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails, String theCode) {
|
||||
// IBase issue = createIssue(theCtx, theOperationOutcome);
|
||||
// populateDetails(theCtx, issue, theSeverity, theDetails, null, theCode);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Add an issue to an OperationOutcome
|
||||
|
@ -70,10 +71,11 @@ public class OperationOutcomeUtil {
|
|||
* The severity (e.g. "error")
|
||||
* @param theDetails
|
||||
* The details string
|
||||
* @param theCode
|
||||
*/
|
||||
public static void addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails, String theLocation) {
|
||||
public static void addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails, String theLocation, String theCode) {
|
||||
IBase issue = createIssue(theCtx, theOperationOutcome);
|
||||
populateDetails(theCtx, issue, theSeverity, theDetails, theLocation);
|
||||
populateDetails(theCtx, issue, theSeverity, theDetails, theLocation, theCode);
|
||||
}
|
||||
|
||||
private static IBase createIssue(FhirContext theCtx, IBaseResource theOutcome) {
|
||||
|
@ -145,11 +147,16 @@ public class OperationOutcomeUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private static void populateDetails(FhirContext theCtx, IBase theIssue, String theSeverity, String theDetails, String theLocation) {
|
||||
private static void populateDetails(FhirContext theCtx, IBase theIssue, String theSeverity, String theDetails, String theLocation, String theCode) {
|
||||
BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(theIssue.getClass());
|
||||
BaseRuntimeChildDefinition detailsChild;
|
||||
if (theCtx.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
||||
detailsChild = issueElement.getChildByName("diagnostics");
|
||||
|
||||
BaseRuntimeChildDefinition codeChild = issueElement.getChildByName("code");
|
||||
IPrimitiveType<?> codeElem = (IPrimitiveType<?>) codeChild.getChildByName("code").newInstance(codeChild.getInstanceConstructorArguments());
|
||||
codeElem.setValueAsString(theCode);
|
||||
codeChild.getMutator().addValue(theIssue, codeElem);
|
||||
} else {
|
||||
detailsChild = issueElement.getChildByName("details");
|
||||
}
|
||||
|
|
|
@ -173,17 +173,22 @@ public class UrlUtil {
|
|||
*/
|
||||
//@formatter:on
|
||||
public static UrlParts parseUrl(String theUrl) {
|
||||
String url = theUrl;
|
||||
if (url.matches("\\/[a-zA-Z]+\\?.*")) {
|
||||
url = url.substring(1);
|
||||
}
|
||||
|
||||
UrlParts retVal = new UrlParts();
|
||||
|
||||
int nextStart = 0;
|
||||
boolean nextIsHistory = false;
|
||||
|
||||
for (int idx = 0; idx < theUrl.length(); idx++) {
|
||||
char nextChar = theUrl.charAt(idx);
|
||||
boolean atEnd = (idx + 1) == theUrl.length();
|
||||
for (int idx = 0; idx < url.length(); idx++) {
|
||||
char nextChar = url.charAt(idx);
|
||||
boolean atEnd = (idx + 1) == url.length();
|
||||
if (nextChar == '?' || nextChar == '/' || atEnd) {
|
||||
int endIdx = atEnd ? idx + 1 : idx;
|
||||
String nextSubstring = theUrl.substring(nextStart, endIdx);
|
||||
String nextSubstring = url.substring(nextStart, endIdx);
|
||||
if (retVal.getResourceType() == null) {
|
||||
retVal.setResourceType(nextSubstring);
|
||||
} else if (retVal.getResourceId() == null) {
|
||||
|
@ -194,12 +199,12 @@ public class UrlUtil {
|
|||
if (nextSubstring.equals(Constants.URL_TOKEN_HISTORY)) {
|
||||
nextIsHistory = true;
|
||||
} else {
|
||||
throw new InvalidRequestException("Invalid FHIR resource URL: " + theUrl);
|
||||
throw new InvalidRequestException("Invalid FHIR resource URL: " + url);
|
||||
}
|
||||
}
|
||||
if (nextChar == '?') {
|
||||
if (theUrl.length() > idx + 1) {
|
||||
retVal.setParams(theUrl.substring(idx + 1, theUrl.length()));
|
||||
if (url.length() > idx + 1) {
|
||||
retVal.setParams(url.substring(idx + 1, url.length()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ public class XmlUtil {
|
|||
private static volatile XMLInputFactory ourInputFactory;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class);
|
||||
private static volatile XMLOutputFactory ourOutputFactory;
|
||||
private static XMLOutputFactory ourFragmentOutputFactory;
|
||||
private static final Map<String, Integer> VALID_ENTITY_NAMES;
|
||||
private static final ExtendedEntityReplacingXmlResolver XML_RESOLVER = new ExtendedEntityReplacingXmlResolver();
|
||||
|
||||
|
@ -1539,6 +1540,12 @@ public class XmlUtil {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public static XMLEventWriter createXmlFragmentWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException {
|
||||
XMLOutputFactory outputFactory = getOrCreateFragmentOutputFactory();
|
||||
XMLEventWriter retVal = outputFactory.createXMLEventWriter(theWriter);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static XMLEventWriter createXmlWriter(Writer theWriter) throws FactoryConfigurationError, XMLStreamException {
|
||||
XMLOutputFactory outputFactory = getOrCreateOutputFactory();
|
||||
XMLEventWriter retVal = outputFactory.createXMLEventWriter(theWriter);
|
||||
|
@ -1589,40 +1596,55 @@ public class XmlUtil {
|
|||
return ourInputFactory;
|
||||
}
|
||||
|
||||
private static XMLOutputFactory getOrCreateFragmentOutputFactory() throws FactoryConfigurationError {
|
||||
XMLOutputFactory retVal = ourFragmentOutputFactory;
|
||||
if (retVal == null) {
|
||||
retVal = createOutputFactory();
|
||||
retVal.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE);
|
||||
ourFragmentOutputFactory = retVal;
|
||||
return retVal;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private static XMLOutputFactory getOrCreateOutputFactory() throws FactoryConfigurationError {
|
||||
if (ourOutputFactory == null) {
|
||||
|
||||
try {
|
||||
// Detect if we're running with the Android lib, and force repackaged Woodstox to be used
|
||||
Class.forName("ca.uhn.fhir.repackage.javax.xml.stream.XMLOutputFactory");
|
||||
System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ok
|
||||
}
|
||||
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
|
||||
if (!ourHaveLoggedStaxImplementation) {
|
||||
logStaxImplementation(outputFactory.getClass());
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that these properties are Woodstox specific and they cause a crash in environments where SJSXP is
|
||||
* being used (e.g. glassfish) so we don't set them there.
|
||||
*/
|
||||
try {
|
||||
Class.forName("com.ctc.wstx.stax.WstxOutputFactory");
|
||||
if (outputFactory instanceof WstxOutputFactory) {
|
||||
outputFactory.setProperty(XMLOutputFactory2.P_TEXT_ESCAPER, new MyEscaper());
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
ourLog.debug("WstxOutputFactory (Woodstox) not found on classpath");
|
||||
}
|
||||
ourOutputFactory = outputFactory;
|
||||
ourOutputFactory = createOutputFactory();
|
||||
}
|
||||
return ourOutputFactory;
|
||||
}
|
||||
|
||||
private static XMLOutputFactory createOutputFactory() throws FactoryConfigurationError {
|
||||
try {
|
||||
// Detect if we're running with the Android lib, and force repackaged Woodstox to be used
|
||||
Class.forName("ca.uhn.fhir.repackage.javax.xml.stream.XMLOutputFactory");
|
||||
System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ok
|
||||
}
|
||||
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
|
||||
if (!ourHaveLoggedStaxImplementation) {
|
||||
logStaxImplementation(outputFactory.getClass());
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that these properties are Woodstox specific and they cause a crash in environments where SJSXP is
|
||||
* being used (e.g. glassfish) so we don't set them there.
|
||||
*/
|
||||
try {
|
||||
Class.forName("com.ctc.wstx.stax.WstxOutputFactory");
|
||||
if (outputFactory instanceof WstxOutputFactory) {
|
||||
outputFactory.setProperty(XMLOutputFactory2.P_TEXT_ESCAPER, new MyEscaper());
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
ourLog.debug("WstxOutputFactory (Woodstox) not found on classpath");
|
||||
}
|
||||
return outputFactory;
|
||||
}
|
||||
|
||||
private static URL getRootUrlForClass(Class<?> cls) {
|
||||
ClassLoader classLoader = cls.getClassLoader();
|
||||
String resource = cls.getName().replace('.', '/') + ".class";
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.List;
|
|||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
|
||||
import ca.uhn.fhir.util.OperationOutcomeUtil;
|
||||
|
||||
/**
|
||||
|
@ -107,7 +108,7 @@ public class ValidationResult {
|
|||
location = null;
|
||||
}
|
||||
String severity = next.getSeverity() != null ? next.getSeverity().getCode() : null;
|
||||
OperationOutcomeUtil.addIssue(myCtx, oo, severity, next.getMessage(), location);
|
||||
OperationOutcomeUtil.addIssue(myCtx, oo, severity, next.getMessage(), location, ExceptionHandlingInterceptor.PROCESSING);
|
||||
}
|
||||
|
||||
return oo;
|
||||
|
|
|
@ -222,11 +222,16 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
|
|||
if (res != null) {
|
||||
|
||||
nextResourceId = res.getId();
|
||||
|
||||
if (nextResourceId.hasIdPart() == false) {
|
||||
if (isNotBlank(nextEntry.getFullUrl())) {
|
||||
nextResourceId = new IdDt(nextEntry.getFullUrl());
|
||||
}
|
||||
}
|
||||
|
||||
if (nextResourceId.hasIdPart() && nextResourceId.getIdPart().matches("[a-zA-Z]+\\:.*") && !isPlaceholder(nextResourceId)) {
|
||||
throw new InvalidRequestException("Invalid placeholder ID found: " + nextResourceId.getIdPart() + " - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'");
|
||||
}
|
||||
|
||||
if (nextResourceId.hasIdPart() && !nextResourceId.hasResourceType() && !isPlaceholder(nextResourceId)) {
|
||||
nextResourceId = new IdDt(toResourceName(res.getClass()), nextResourceId.getIdPart());
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
@ -26,9 +27,11 @@ import ca.uhn.fhir.model.dstu.resource.Patient;
|
|||
import ca.uhn.fhir.model.dstu.resource.Questionnaire;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.OperationDefinition;
|
||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class SystemProviderDstu2Test extends BaseJpaTest {
|
||||
|
||||
|
@ -38,6 +41,36 @@ public class SystemProviderDstu2Test extends BaseJpaTest {
|
|||
private static FhirContext ourCtx;
|
||||
private static IGenericClient ourClient;
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle4() throws Exception {
|
||||
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle.xml");
|
||||
String bundle = IOUtils.toString(bundleRes);
|
||||
String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
ourLog.info(response);
|
||||
Bundle bundleResp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
IdDt id = new IdDt(bundleResp.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals("Patient", id.getResourceType());
|
||||
assertTrue(id.hasIdPart());
|
||||
assertTrue(id.isIdPartValidLong());
|
||||
assertTrue(id.hasVersionIdPart());
|
||||
assertTrue(id.isVersionIdPartValidLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle5() throws Exception {
|
||||
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/simone_bundle2.xml");
|
||||
String bundle = IOUtils.toString(bundleRes);
|
||||
try {
|
||||
ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
|
||||
assertEquals("Invalid placeholder ID found: uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'", oo.getIssue().get(0).getDiagnostics());
|
||||
assertEquals("processing", oo.getIssue().get(0).getCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle() throws Exception {
|
||||
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/transaction_link_patient_eve.xml");
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<Bundle xmlns="http://hl7.org/fhir">
|
||||
<id value="20151003220331"/>
|
||||
<type value="transaction"/>
|
||||
<entry>
|
||||
<fullUrl value="urn:uuid:abd7a623-699e-46b5-5f5f-8d1d79fa33e6"/>
|
||||
<resource>
|
||||
<Patient>
|
||||
<identifier>
|
||||
<use value="usual"/>
|
||||
<type>
|
||||
<coding>
|
||||
<system value="http://hl7.org/fhir/identifier-type"/>
|
||||
<code value="NH"/>
|
||||
</coding>
|
||||
</type>
|
||||
<system value="urn:oid:2.16.840.1.113883.2.1.4.1"/>
|
||||
<value value="23455457476474754545"/>
|
||||
<assigner>
|
||||
<display value="NHS"/>
|
||||
</assigner>
|
||||
</identifier>
|
||||
<identifier>
|
||||
<use value="usual"/>
|
||||
<type>
|
||||
<coding>
|
||||
<system value="http://hl7.org/fhir/identifier-type"/>
|
||||
<code value="MR"/>
|
||||
</coding>
|
||||
</type>
|
||||
<system value="http://www.ghh.org/identifiers/"/>
|
||||
<value value="4567567567"/>
|
||||
<assigner>
|
||||
<display value="TCPAS"/>
|
||||
</assigner>
|
||||
</identifier>
|
||||
<name>
|
||||
<use value="official"/>
|
||||
<family value="Connectathon"/>
|
||||
<given value="Ann"/>
|
||||
</name>
|
||||
<telecom>
|
||||
<system value="phone"/>
|
||||
<value value="277543"/>
|
||||
<use value="home"/>
|
||||
</telecom>
|
||||
<gender value="female"/>
|
||||
<birthDate value="1928-05-24"/>
|
||||
<address>
|
||||
<line value="22 Stable Road"/>
|
||||
<city value="Whitstable"/>
|
||||
<state value="Kent"/>
|
||||
<country value="CR5 1EL"/>
|
||||
</address>
|
||||
<contact>
|
||||
<relationship>
|
||||
<coding>
|
||||
<system value="http://hl7.org/fhir/patient-contact-relationship"/>
|
||||
<code value="parent"/>
|
||||
</coding>
|
||||
</relationship>
|
||||
<name>
|
||||
<family value="Connectathon"/>
|
||||
<given value="Joe"/>
|
||||
</name>
|
||||
</contact>
|
||||
</Patient>
|
||||
</resource>
|
||||
<request>
|
||||
<method value="PUT"/>
|
||||
<url value="/Patient?identifier=http://www.ghh.org/identifiers/|4567567567"/>
|
||||
</request>
|
||||
</entry>
|
||||
<entry>
|
||||
<fullUrl value="urn:uuid:491aabbf-fcff-4697-5bb2-84e856d5786b"/>
|
||||
<resource>
|
||||
<Encounter>
|
||||
<identifier>
|
||||
<use value="usual"/>
|
||||
<type>
|
||||
<coding>
|
||||
<system value="http://hl7.org/fhir/identifier-type"/>
|
||||
<code value="MR"/>
|
||||
</coding>
|
||||
</type>
|
||||
<system value="http://general-hospital.co.uk/Identifiers/"/>
|
||||
<value value="123447878787866666"/>
|
||||
<assigner>
|
||||
<display value="GENHOS"/>
|
||||
</assigner>
|
||||
</identifier>
|
||||
<status value="in-progress"/>
|
||||
<class value="inpatient"/>
|
||||
<patient>
|
||||
<reference value="urn:uuid:abd7a623-699e-46b5-5f5f-8d1d79fa33e6"/>
|
||||
<display value="Connectathon, Ann(*24.05.1928)"/>
|
||||
</patient>
|
||||
<period>
|
||||
<start value="2015-05-02T09:00:00+01:00"/>
|
||||
</period>
|
||||
</Encounter>
|
||||
</resource>
|
||||
<request>
|
||||
<method value="PUT"/>
|
||||
<url value="/Encounter?identifier=http://general-hospital.co.uk/Identifiers/|123447878787866666"/>
|
||||
</request>
|
||||
</entry>
|
||||
</Bundle>
|
|
@ -0,0 +1,73 @@
|
|||
<Bundle xmlns="http://hl7.org/fhir" xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<type value="transaction"/>
|
||||
<entry>
|
||||
<fullUrl value="uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d"/>
|
||||
<resource>
|
||||
<Patient>
|
||||
<text>
|
||||
<status value="generated"/>
|
||||
<xhtml:div>
|
||||
<xhtml:img src="http://pbs.twimg.com/profile_images/544507893991485440/r_vo3uj2_bigger.png" alt="Twitter Avatar"/>
|
||||
@fhirabend
|
||||
</xhtml:div>
|
||||
</text>
|
||||
<identifier>
|
||||
<use value="secondary"/>
|
||||
<system value="http://twitter.com"/>
|
||||
<value value="2922960201"/>
|
||||
</identifier>
|
||||
<name>
|
||||
<family value="fhirabend"/>
|
||||
</name>
|
||||
<photo>
|
||||
<url value="http://pbs.twimg.com/profile_images/544507893991485440/r_vo3uj2_bigger.png"/>
|
||||
</photo>
|
||||
</Patient>
|
||||
</resource>
|
||||
<request>
|
||||
<method value="PUT"/>
|
||||
<url value="Patient?identifier=http://twitter.com|2922960201"/>
|
||||
</request>
|
||||
</entry>
|
||||
<entry>
|
||||
<resource>
|
||||
<Communication>
|
||||
<meta>
|
||||
<profile value="http://foo/Profile1"/>
|
||||
<tag>
|
||||
<system value="http://twitter.com"/>
|
||||
<code value="http://twitter.com/hashtag/FHIR"/>
|
||||
<display value="#FHIR"/>
|
||||
</tag>
|
||||
</meta>
|
||||
<text>
|
||||
<status value="generated"/>
|
||||
<xhtml:div>
|
||||
<xhtml:b> @fhirabend:</xhtml:b>
|
||||
RT @kainamti: Motto of the FHIR calendar 2016: the #FHIR is strong in you @HL7 http://t.co/E03Y3NIjME
|
||||
</xhtml:div>
|
||||
</text>
|
||||
<identifier>
|
||||
<system value="http://twitter.com"/>
|
||||
<value value="650408456562823168"/>
|
||||
</identifier>
|
||||
<sender>
|
||||
<reference value="uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d"/>
|
||||
</sender>
|
||||
<payload>
|
||||
<contentString value="RT @kainamti: Motto of the FHIR calendar 2016: the #FHIR is strong in you @HL7 http://t.co/E03Y3NIjME"/>
|
||||
</payload>
|
||||
<medium>
|
||||
<coding>
|
||||
<code value="Twitter"/>
|
||||
</coding>
|
||||
</medium>
|
||||
<sent value="2015-10-03T22:33:54+02:00"/>
|
||||
</Communication>
|
||||
</resource>
|
||||
<request>
|
||||
<method value="PUT"/>
|
||||
<url value="Communication?identifier=http://twitter.com|650408456562823168"/>
|
||||
</request>
|
||||
</entry>
|
||||
</Bundle>
|
|
@ -55,6 +55,8 @@
|
|||
<property name="loggerName" value="fhirtest.access"/>
|
||||
<property name="messageFormat"
|
||||
value="Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]"/>
|
||||
<property name="logExceptions" value="true"/>
|
||||
<property name="errorMessageFormat" value="ERROR - ${requestVerb} ${requestUrl}"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
|
@ -54,6 +54,39 @@ public class JsonParserDstu2Test {
|
|||
private static final FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserDstu2Test.class);
|
||||
|
||||
@Test
|
||||
public void testNamespacePreservationEncode() throws Exception {
|
||||
//@formatter:off
|
||||
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
|
||||
"<text>" +
|
||||
"<xhtml:div>" +
|
||||
"<xhtml:img src=\"foo\"/>" +
|
||||
"@fhirabend" +
|
||||
"</xhtml:div>" +
|
||||
"</text>" +
|
||||
"</Patient>";
|
||||
//@formatter:on
|
||||
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
|
||||
|
||||
String expected = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>";
|
||||
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
|
||||
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
|
||||
ourLog.info(encoded);
|
||||
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamespacePreservationParse() throws Exception {
|
||||
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
|
||||
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
|
||||
|
||||
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", parsed.getText().getDiv().getValueAsString());
|
||||
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
|
||||
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>",encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeAndParseExtensions() throws Exception {
|
||||
|
||||
|
@ -98,8 +131,10 @@ public class JsonParserDstu2Test {
|
|||
assertThat(enc, Matchers.stringContainsInOrder("{\"resourceType\":\"Patient\",", "\"extension\":[{\"url\":\"http://example.com/extensions#someext\",\"valueDateTime\":\"2011-01-02T11:13:15\"}",
|
||||
"{\"url\":\"http://example.com#parent\",\"extension\":[{\"url\":\"http://example.com#child\",\"valueString\":\"value1\"},{\"url\":\"http://example.com#child\",\"valueString\":\"value2\"}]}"));
|
||||
assertThat(enc, Matchers.stringContainsInOrder("\"modifierExtension\":[" + "{" + "\"url\":\"http://example.com/extensions#modext\"," + "\"valueDate\":\"1995-01-02\"" + "}" + "],"));
|
||||
assertThat(enc, containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{"
|
||||
+ "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}" + "]" + "}"));
|
||||
assertThat(enc,
|
||||
containsString("\"_given\":[" + "{" + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext\"," + "\"valueString\":\"given\"" + "}" + "]" + "}," + "{" + "\"extension\":[" + "{"
|
||||
+ "\"url\":\"http://examples.com#givenext_parent\"," + "\"extension\":[" + "{" + "\"url\":\"http://examples.com#givenext_child\"," + "\"valueString\":\"CHILD\"" + "}" + "]" + "}"
|
||||
+ "]" + "}"));
|
||||
|
||||
/*
|
||||
* Now parse this back
|
||||
|
@ -402,7 +437,8 @@ public class JsonParserDstu2Test {
|
|||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, containsString("Patient"));
|
||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\",", "\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\","));
|
||||
assertThat(encoded, stringContainsInOrder("\"tag\"", "\"system\":\"foo\",", "\"code\":\"bar\"", "\"system\":\"" + Constants.TAG_SUBSETTED_SYSTEM + "\",",
|
||||
"\"code\":\"" + Constants.TAG_SUBSETTED_CODE + "\","));
|
||||
assertThat(encoded, not(containsString("THE DIV")));
|
||||
assertThat(encoded, containsString("family"));
|
||||
assertThat(encoded, not(containsString("maritalStatus")));
|
||||
|
@ -423,7 +459,8 @@ public class JsonParserDstu2Test {
|
|||
String enc = ourCtx.newJsonParser().encodeResourceToString(pt);
|
||||
ourLog.info(enc);
|
||||
|
||||
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}", enc);
|
||||
assertEquals("{\"resourceType\":\"Patient\",\"meta\":{\"tag\":[{\"system\":\"scheme\",\"code\":\"term\",\"display\":\"display\"}]},\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}]}",
|
||||
enc);
|
||||
|
||||
}
|
||||
|
||||
|
@ -517,7 +554,7 @@ public class JsonParserDstu2Test {
|
|||
assertEquals(exp, act);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for #146
|
||||
*/
|
||||
|
@ -636,9 +673,9 @@ public class JsonParserDstu2Test {
|
|||
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-transaction2.json"));
|
||||
|
||||
ourCtx.newJsonParser().parseBundle(content);
|
||||
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content);
|
||||
|
||||
|
||||
// TODO: preserve comments
|
||||
}
|
||||
|
||||
|
@ -857,7 +894,7 @@ public class JsonParserDstu2Test {
|
|||
assertEquals(exp, act);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParsePatientInBundle() {
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ import ca.uhn.fhir.rest.annotation.RequiredParam;
|
|||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
/**
|
||||
|
@ -78,6 +79,30 @@ public class LoggingInterceptorDstu2Test {
|
|||
assertThat(captor.getValue(), StringContains.containsString("read - Patient/1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testException() throws Exception {
|
||||
|
||||
LoggingInterceptor interceptor = new LoggingInterceptor();
|
||||
interceptor.setLogExceptions(true);
|
||||
assertTrue(interceptor.isLogExceptions());
|
||||
interceptor.setErrorMessageFormat("ERROR - ${requestVerb} ${requestUrl}");
|
||||
assertEquals("ERROR - ${requestVerb} ${requestUrl}", interceptor.getErrorMessageFormat());
|
||||
|
||||
servlet.setInterceptors(Collections.singletonList((IServerInterceptor) interceptor));
|
||||
|
||||
Logger logger = mock(Logger.class);
|
||||
interceptor.setLogger(logger);
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/EX");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
||||
verify(logger, times(2)).info(captor.capture());
|
||||
assertThat(captor.getAllValues().get(0), StringContains.containsString("read - Patient/EX"));
|
||||
assertThat(captor.getAllValues().get(1), StringContains.containsString("ERROR - GET http://localhost:"+ourPort+"/Patient/EX"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
|
||||
|
@ -242,6 +267,9 @@ public class LoggingInterceptorDstu2Test {
|
|||
*/
|
||||
@Read()
|
||||
public Patient getResourceById(@IdParam IdDt theId) {
|
||||
if (theId.getIdPart().equals("EX")) {
|
||||
throw new InvalidRequestException("FOO");
|
||||
}
|
||||
String key = theId.getIdPart();
|
||||
Patient retVal = getIdToPatient().get(key);
|
||||
return retVal;
|
||||
|
|
|
@ -133,6 +133,12 @@
|
|||
Parameters using chained method calls instead
|
||||
of by passing a Parameters resource in
|
||||
</action>
|
||||
<action type="fix">
|
||||
Parsing an XML resource where the XHTML
|
||||
namespace was declared before the beginning
|
||||
of the narrative section caused an invalid
|
||||
re-encoding when encoding to JSON.
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.2" date="2015-09-18">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue