From c8adab545276d203ad410ba367c7696d179d4b6e Mon Sep 17 00:00:00 2001 From: James Agnew Date: Tue, 23 Dec 2014 09:42:16 -0500 Subject: [PATCH 1/3] Better logging in JPA --- hapi-fhir-base/pom.xml | 8 ++--- hapi-fhir-jpaserver-base/.classpath | 10 ------ .../org.eclipse.wst.common.component | 2 -- hapi-fhir-jpaserver-base/pom.xml | 2 +- .../java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java | 21 +++++++++++-- .../uhn/fhir/jpa/entity/BaseHasResource.java | 2 ++ .../fhir/jpa/entity/ResourceHistoryTable.java | 4 +++ .../org.eclipse.wst.common.component | 3 ++ .../org.eclipse.wst.common.component.orig | 31 +++++++++++-------- hapi-fhir-jpaserver-uhnfhirtest/pom.xml | 2 +- hapi-tinder-plugin/pom.xml | 8 ++--- pom.xml | 20 +++++++----- restful-server-example/pom.xml | 2 +- src/changes/changes.xml | 10 ++++++ 14 files changed, 79 insertions(+), 46 deletions(-) diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 4c4c88ea089..e22ca1503d5 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -88,12 +88,12 @@ commons-codec commons-codec - 1.9 + ${commons_codec_version} commons-io commons-io - 2.4 + ${commons_io_version} @@ -118,7 +118,7 @@ org.apache.httpcomponents httpclient - 4.3.3 + ${apache_httpclient_version} commons-logging @@ -129,7 +129,7 @@ org.apache.httpcomponents httpcore - 4.3.2 + ${apache_httpcore_version} diff --git a/hapi-fhir-jpaserver-base/.classpath b/hapi-fhir-jpaserver-base/.classpath index 77ae23ab4aa..caa2612fd4f 100644 --- a/hapi-fhir-jpaserver-base/.classpath +++ b/hapi-fhir-jpaserver-base/.classpath @@ -26,15 +26,5 @@ - - - - - - - - - - diff --git a/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component b/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component index dc4d46e13ac..4e5bc0108c7 100644 --- a/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component +++ b/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component @@ -2,7 +2,5 @@ - - diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 4e2a36abb46..a77b7084d86 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -263,7 +263,7 @@ de.juplo hibernate4-maven-plugin - 1.0.2 + 1.0.5 true SCRIPT diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java index cd3a142e583..400eff15302 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java @@ -743,8 +743,25 @@ public abstract class BaseFhirDao implements IDao { } IParser parser = theEntity.getEncoding().newParser(getContext(theEntity.getFhirVersion())); - T retVal = parser.parseResource(theResourceType, resourceText); - + T retVal; + try { + retVal = parser.parseResource(theResourceType, resourceText); + } catch (Exception e) { + StringBuilder b = new StringBuilder(); + b.append("Failed to parse database resource["); + b.append(theResourceType); + b.append("/"); + b.append(theEntity.getIdDt().getIdPart()); + b.append(" (pid "); + b.append(theEntity.getId()); + b.append(", version "); + b.append(myContext.getVersion().getVersion()); + b.append("): "); + b.append(e.getMessage()); + String msg = b.toString(); + ourLog.error(msg, e); + throw new DataFormatException(msg, e); + } IResource res = (IResource) retVal; res.setId(theEntity.getIdDt()); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java index 863fea48820..60e4d1a0d30 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java @@ -107,6 +107,8 @@ public abstract class BaseHasResource { myDeleted = theDate; } + public abstract Long getId(); + public void setEncoding(ResourceEncodingEnum theEncoding) { myEncoding = theEncoding; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java index 704e78e0f47..a10b4627c0d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceHistoryTable.java @@ -67,6 +67,10 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl return historyTag; } + public Long getId() { + return myId; + } + @Override public IdDt getIdDt() { Object id = getForcedId()==null? getResourceId() : getForcedId().getForcedId(); diff --git a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component index 124f33524d7..7d2c3dbcedf 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component +++ b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component @@ -14,6 +14,9 @@ uses + + uses + consumes diff --git a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component.orig b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component.orig index 951bce12d13..f4c72946dd5 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component.orig +++ b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component.orig @@ -2,24 +2,29 @@ - - - uses - - - uses - - - uses - <<<<<<< HEAD - + + uses + + + uses + + ======= - ->>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2 + + uses + + + uses + + + uses + + +>>>>>>> hl7org_structs consumes diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index c898a9bf335..11e6b282c0c 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -109,7 +109,7 @@ com.google.guava guava - 17.0 + ${guava_version} diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 9ffec4fb7e7..f32293b6a50 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -60,19 +60,19 @@ commons-io commons-io - 2.4 + ${commons_io_version} org.slf4j slf4j-api - 1.7.6 + ${slf4j_version} ch.qos.logback logback-classic - 1.1.1 + ${logback_version} true @@ -93,7 +93,7 @@ org.apache.maven maven-plugin-api - 3.2.1 + 3.2.5 org.apache.maven.plugin-tools diff --git a/pom.xml b/pom.xml index dd9f36e685d..7db64c17575 100644 --- a/pom.xml +++ b/pom.xml @@ -136,15 +136,19 @@ ${user.home}/sites/scm/hapi-fhir + 4.3.6 + 4.4 + 2.4 3.3.2 + 1.10 10.11.1.1 18.0 1.3 - 4.2.12.Final + 4.3.7.Final 5.1.0.Final - 9.2.2.v20140723 + 9.2.6.v20141205 4.3.1 - 4.11 + 4.12 1.1.2 2.4.1 2.10.1 @@ -153,15 +157,15 @@ 3.4 2.3 1.1.8 - 1.9.5 + 1.10.17 2.7.1 - 4.3.3 + 4.3.5 UTF-8 3.1.0 - 1.7.7 - 4.1.0.RELEASE + 1.7.9 + 4.1.3.RELEASE 3.2.4.RELEASE - 2.1.3.RELEASE + 2.1.4.RELEASE 1.0.1 4.4.0 diff --git a/restful-server-example/pom.xml b/restful-server-example/pom.xml index f7aec12b3c7..74994fd5057 100644 --- a/restful-server-example/pom.xml +++ b/restful-server-example/pom.xml @@ -80,7 +80,7 @@ org.thymeleaf thymeleaf - 2.1.3.RELEASE + 2.1.4.RELEASE diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 0e95f8d4fd2..2b9c3fd98e6 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -16,6 +16,16 @@ (e.g. because they don't have a no-argument constructor) in order to avoid failing later + + Bump a few dependency JARs to the latest versions in Maven POM: + +
  • SLF4j (in base module) - Bumped to 1.7.9
  • +
  • Apache HTTPClient (in base module) - Bumped to 4.3.6
  • +
  • Hibernate (in JPA module) - Bumped to 4.3.7
  • + + ]]> +
    From 81851f4808f2b0eb914fbaabfc7777e9a8509459 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Tue, 23 Dec 2014 14:10:53 -0500 Subject: [PATCH 2/3] Fix #65 - Correctly parse and encode extensions on non-repeatable primitive fields --- .../ca/uhn/fhir/model/api/IFhirVersion.java | 5 +- .../java/ca/uhn/fhir/parser/JsonParser.java | 86 ++- .../java/ca/uhn/fhir/parser/XmlParser.java | 29 +- .../server/IServerConformanceProvider.java | 16 + .../parser/MultiVersionXmlParserTest.java | 33 + hapi-fhir-jpaserver-base/.classpath | 10 + .../org.eclipse.wst.common.component | 2 + .../provider/JpaConformanceProviderDev.java | 81 +++ ....java => JpaConformanceProviderDstu1.java} | 4 +- hapi-fhir-jpaserver-uhnfhirtest/pom.xml | 13 +- .../ca/uhn/fhirtest/TestRestfulServer.java | 86 ++- .../META-INF/fhirtest_persistence.xml | 2 + .../hapi-fhir-server-database-config.xml | 2 +- .../WEB-INF/hapi-fhir-tester-config.xml | 4 +- hapi-fhir-structures-dev/.gitignore | 1 + .../java/ca/uhn/fhir/model/dev/FhirDev.java | 2 +- .../dev/ServerConformanceProvider.java | 15 +- .../ca/uhn/fhir/parser/JsonParserTest.java | 26 +- .../server/ServerConformanceProviderTest.java | 39 +- hapi-fhir-structures-dstu/.gitignore | 1 + .../ca/uhn/fhir/model/dstu/FhirDstu1.java | 3 +- .../provider/ServerConformanceProvider.java | 5 +- .../ca/uhn/fhir/parser/JsonParserTest.java | 22 +- .../ca/uhn/fhir/jpa/test/OverlayTestApp.java | 2 +- .../java/ca/uhn/fhir/model/dev/FhirDev.java | 2 +- .../ca/uhn/fhir/model/dstu/FhirDstu1.java | 2 +- .../provider/ServerConformanceProvider.java | 3 +- .../dev/ServerConformanceProvider.java | 7 +- src/changes/changes.xml | 7 + src/changes/changes.xml.orig | 656 ++++++++++++++++++ 30 files changed, 1040 insertions(+), 126 deletions(-) create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java create mode 100644 hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionXmlParserTest.java create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDev.java rename hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/{JpaConformanceProvider.java => JpaConformanceProviderDstu1.java} (93%) create mode 100644 src/changes/changes.xml.orig diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java index 5cc1460d53f..9bf7a988247 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/IFhirVersion.java @@ -22,9 +22,12 @@ package ca.uhn.fhir.model.api; import java.io.InputStream; +import org.hl7.fhir.instance.model.IBaseResource; + import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.server.RestfulServer; public interface IFhirVersion { @@ -37,7 +40,7 @@ public interface IFhirVersion { IResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase); - Object createServerConformanceProvider(RestfulServer theRestfulServer); + IServerConformanceProvider createServerConformanceProvider(RestfulServer theRestfulServer); String getPathToSchemaDefinitions(); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index 703c8847581..b3f6bfb49d9 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -288,20 +288,20 @@ public class JsonParser extends BaseParser implements IParser { writeTagWithTextNode(theEventWriter, "instant", nextEntry.getDeletedAt()); } -// linkStarted = false; -// linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "self", nextEntry.getLinkSelf(), linkStarted); -// linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "alternate", nextEntry.getLinkAlternate(), linkStarted); -// linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "search", nextEntry.getLinkSearch(), linkStarted); -// if (linkStarted) { -// theEventWriter.writeEnd(); -// } -// -// writeOptionalTagWithTextNode(theEventWriter, "updated", nextEntry.getUpdated()); -// writeOptionalTagWithTextNode(theEventWriter, "published", nextEntry.getPublished()); -// -// writeCategories(theEventWriter, nextEntry.getCategories()); -// -// writeAuthor(nextEntry, theEventWriter); + // linkStarted = false; + // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "self", nextEntry.getLinkSelf(), linkStarted); + // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "alternate", nextEntry.getLinkAlternate(), linkStarted); + // linkStarted = writeAtomLinkInDstu1Format(theEventWriter, "search", nextEntry.getLinkSearch(), linkStarted); + // if (linkStarted) { + // theEventWriter.writeEnd(); + // } + // + // writeOptionalTagWithTextNode(theEventWriter, "updated", nextEntry.getUpdated()); + // writeOptionalTagWithTextNode(theEventWriter, "published", nextEntry.getPublished()); + // + // writeCategories(theEventWriter, nextEntry.getCategories()); + // + // writeAuthor(nextEntry, theEventWriter); IResource resource = nextEntry.getResource(); if (resource != null && !resource.isEmpty() && !deleted) { @@ -532,7 +532,12 @@ public class JsonParser extends BaseParser implements IParser { } if (extensions.size() > 0 || modifierExtensions.size() > 0) { - theEventWriter.writeStartArray('_' + currentChildName); + if (inArray) { + // If this is a repeatable field, the extensions go in an array too + theEventWriter.writeStartArray('_' + currentChildName); + } else { + theEventWriter.writeStartObject('_' + currentChildName); + } for (int i = 0; i < valueIdx; i++) { boolean haveContent = false; @@ -552,9 +557,13 @@ public class JsonParser extends BaseParser implements IParser { if (!haveContent) { theEventWriter.writeNull(); } else { - theEventWriter.writeStartObject(); + if (inArray) { + theEventWriter.writeStartObject(); + } writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts, null); - theEventWriter.writeEnd(); + if (inArray) { + theEventWriter.writeEnd(); + } } } @@ -735,11 +744,23 @@ public class JsonParser extends BaseParser implements IParser { } } - private void parseAlternates(JsonValue theAlternateVal, ParserState theState) { + private void parseAlternates(JsonValue theAlternateVal, ParserState theState, String theElementName) { if (theAlternateVal == null || theAlternateVal.getValueType() == ValueType.NULL) { return; } + if (theAlternateVal instanceof JsonArray) { + JsonArray array = (JsonArray) theAlternateVal; + if (array.size() > 1) { + throw new DataFormatException("Unexpected array of length " + array.size() + " (expected 0 or 1) for element: " + theElementName); + } + if (array.size() == 0) { + return; + } + parseAlternates(array.getJsonObject(0), theState, theElementName); + return; + } + boolean newerThanDstu1 = myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1); JsonObject alternate = (JsonObject) theAlternateVal; for (Entry nextEntry : alternate.entrySet()) { @@ -880,7 +901,7 @@ public class JsonParser extends BaseParser implements IParser { } JsonValue nextVal = theObject.get(nextName); - parseChildren(theState, nextName, nextVal, null); + parseChildren(theState, nextName, nextVal, null, null); } } @@ -926,9 +947,10 @@ public class JsonParser extends BaseParser implements IParser { } JsonValue nextVal = theObject.get(nextName); - JsonValue alternateVal = theObject.get('_' + nextName); + String alternateName = '_' + nextName; + JsonValue alternateVal = theObject.get(alternateName); - parseChildren(theState, nextName, nextVal, alternateVal); + parseChildren(theState, nextName, nextVal, alternateVal, alternateName); } @@ -942,7 +964,7 @@ public class JsonParser extends BaseParser implements IParser { } } - private void parseChildren(ParserState theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal) { + private void parseChildren(ParserState theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal, String theAlternateName) { switch (theJsonVal.getValueType()) { case ARRAY: { JsonArray nextArray = (JsonArray) theJsonVal; @@ -953,13 +975,13 @@ public class JsonParser extends BaseParser implements IParser { if (nextAlternateArray != null) { nextAlternate = nextAlternateArray.get(i); } - parseChildren(theState, theName, nextObject, nextAlternate); + parseChildren(theState, theName, nextObject, nextAlternate, theAlternateName); } break; } case OBJECT: { theState.enteringNewElement(null, theName); - parseAlternates(theAlternateVal, theState); + parseAlternates(theAlternateVal, theState, theAlternateName); JsonObject nextObject = (JsonObject) theJsonVal; boolean preResource = false; if (theState.isPreResource()) { @@ -981,7 +1003,7 @@ public class JsonParser extends BaseParser implements IParser { JsonString nextValStr = (JsonString) theJsonVal; theState.enteringNewElement(null, theName); theState.attributeValue("value", nextValStr.getString()); - parseAlternates(theAlternateVal, theState); + parseAlternates(theAlternateVal, theState, theAlternateName); theState.endingElement(); break; } @@ -990,7 +1012,7 @@ public class JsonParser extends BaseParser implements IParser { case TRUE: theState.enteringNewElement(null, theName); theState.attributeValue("value", theJsonVal.toString()); - parseAlternates(theAlternateVal, theState); + parseAlternates(theAlternateVal, theState, theAlternateName); theState.endingElement(); break; case NULL: @@ -1015,7 +1037,7 @@ public class JsonParser extends BaseParser implements IParser { parseExtension(theState, jsonVal, true); } else { JsonValue jsonVal = nextExtObj.get(next); - parseChildren(theState, next, jsonVal, null); + parseChildren(theState, next, jsonVal, null, null); } } theState.endingElement(); @@ -1039,7 +1061,7 @@ public class JsonParser extends BaseParser implements IParser { JsonArray arrayValue = (JsonArray) jsonVal; parseExtensionInDstu2Style(theModifier, theState, extUrl, nextKey, arrayValue); } else { - parseChildren(theState, nextKey, jsonVal, null); + parseChildren(theState, nextKey, jsonVal, null, null); } } } @@ -1371,9 +1393,9 @@ public class JsonParser extends BaseParser implements IParser { boolean noValue = value == null || value.isEmpty(); if (noValue && ext.getAllUndeclaredExtensions().isEmpty()) { - + ourLog.debug("Extension with URL[{}] has no value", extensionUrl); - + } else if (noValue) { BaseRuntimeElementDefinition elemDef = null; @@ -1381,7 +1403,7 @@ public class JsonParser extends BaseParser implements IParser { extractAndWriteExtensionsAsDirectChild(ext, theEventWriter, elemDef, resDef, theResource, extensionUrl); } else { - + RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition(); String childName = extDef.getChildNameByDatatype(value.getClass()); BaseRuntimeElementDefinition childDef; @@ -1396,7 +1418,7 @@ public class JsonParser extends BaseParser implements IParser { childDef = extDef.getChildElementDefinitionByDatatype(value.getClass()); } encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true); - + } theEventWriter.writeEnd(); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index 3acd1668a2c..4404775fb9c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -815,21 +815,36 @@ public class XmlParser extends BaseParser implements IParser { theEventWriter.writeEndElement(); } - private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, List extensions, String tagName, + private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, List theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException { - for (ExtensionDt next : extensions) { + for (ExtensionDt next : theExtensions) { theWriter.writeStartElement(tagName); theWriter.writeAttribute("url", next.getUrl().getValue()); if (next.getValue() != null) { - IElement nextValue = next.getValue(); + IElement value = next.getValue(); +// RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition(); +// String childName = extDef.getChildNameByDatatype(nextValue.getClass()); +// if (childName == null) { +// throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + nextValue.getClass().getCanonicalName()); +// } +// BaseRuntimeElementDefinition childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass()); +// +// RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition(); - String childName = extDef.getChildNameByDatatype(nextValue.getClass()); + String childName = extDef.getChildNameByDatatype(value.getClass()); + BaseRuntimeElementDefinition childDef; if (childName == null) { - throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + nextValue.getClass().getCanonicalName()); + childDef = myContext.getElementDefinition(value.getClass()); + if (childDef == null) { + throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName()); + } else { + childName = RuntimeChildUndeclaredExtensionDefinition.createExtensionChildName(childDef); + } + } else { + childDef = extDef.getChildElementDefinitionByDatatype(value.getClass()); } - BaseRuntimeElementDefinition childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass()); - encodeChildElementToStreamWriter(theResDef, theResource, theWriter, nextValue, childName, childDef, null, theIncludedResource); + encodeChildElementToStreamWriter(theResDef, theResource, theWriter, value, childName, childDef, null, theIncludedResource); } // child extensions diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java new file mode 100644 index 00000000000..f5aa0cdc0b6 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java @@ -0,0 +1,16 @@ +package ca.uhn.fhir.rest.server; + +import javax.servlet.http.HttpServletRequest; + +import org.hl7.fhir.instance.model.IBaseResource; + +public interface IServerConformanceProvider { + + /** + * Actually create and return the conformance statement + * + * See the class documentation for an important note if you are extending this class + */ + public abstract T getServerConformance(HttpServletRequest theRequest); + +} \ No newline at end of file diff --git a/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionXmlParserTest.java b/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionXmlParserTest.java new file mode 100644 index 00000000000..93875da7d8a --- /dev/null +++ b/hapi-fhir-base/testmindeps/src/test/java/ca/uhn/fhir/parser/MultiVersionXmlParserTest.java @@ -0,0 +1,33 @@ +package ca.uhn.fhir.parser; + +import static org.junit.Assert.assertThat; + +import org.hamcrest.core.StringContains; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.composite.QuantityDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; + +public class MultiVersionXmlParserTest { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MultiVersionXmlParserTest.class); + + @Test + public void testEncodeExtensionFromDifferentVersion() { + Patient p = new Patient(); + p.addIdentifier("urn:sys", "001"); + p.addUndeclaredExtension(false, "http://foo#ext", new QuantityDt(QuantityCompararatorEnum.LESSTHAN, 2.2, "g/L")); + + String str; + str = FhirContext.forDstu1().newXmlParser().encodeResourceToString(p); + ourLog.info(str); + assertThat(str,StringContains.containsString("")); + + str = FhirContext.forDev().newXmlParser().encodeResourceToString(p); + ourLog.info(str); + assertThat(str,StringContains.containsString("")); + } + +} diff --git a/hapi-fhir-jpaserver-base/.classpath b/hapi-fhir-jpaserver-base/.classpath index caa2612fd4f..65543c3eeac 100644 --- a/hapi-fhir-jpaserver-base/.classpath +++ b/hapi-fhir-jpaserver-base/.classpath @@ -26,5 +26,15 @@
    + + + + + + + + + + diff --git a/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component b/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component index 4e5bc0108c7..dc4d46e13ac 100644 --- a/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component +++ b/hapi-fhir-jpaserver-base/.settings/org.eclipse.wst.common.component @@ -2,5 +2,7 @@ + + diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDev.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDev.java new file mode 100644 index 00000000000..dc61a1f8cb2 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDev.java @@ -0,0 +1,81 @@ +package ca.uhn.fhir.jpa.provider; + +import java.util.List; +import java.util.Map; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.context.RuntimeSearchParam; +import ca.uhn.fhir.jpa.dao.IFhirSystemDao; +import ca.uhn.fhir.model.dev.resource.Conformance; +import ca.uhn.fhir.model.dev.resource.Conformance.Rest; +import ca.uhn.fhir.model.dev.resource.Conformance.RestResource; +import ca.uhn.fhir.model.dev.resource.Conformance.RestResourceSearchParam; +import ca.uhn.fhir.model.dev.valueset.ResourceTypeEnum; +import ca.uhn.fhir.model.dev.valueset.SearchParamTypeEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.DecimalDt; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.rest.server.provider.dev.ServerConformanceProvider; +import ca.uhn.fhir.util.ExtensionConstants; + +import javax.servlet.http.HttpServletRequest; + +public class JpaConformanceProviderDev extends ServerConformanceProvider { + + private String myImplementationDescription; + private IFhirSystemDao mySystemDao; + private volatile Conformance myCachedValue; + private RestfulServer myRestfulServer; + + public JpaConformanceProviderDev(RestfulServer theRestfulServer, IFhirSystemDao theSystemDao) { + super(theRestfulServer); + myRestfulServer = theRestfulServer; + mySystemDao = theSystemDao; + super.setCache(false); + } + + @Override + public Conformance getServerConformance(HttpServletRequest theRequest) { + Conformance retVal = myCachedValue; + + Map counts = mySystemDao.getResourceCounts(); + + FhirContext ctx = myRestfulServer.getFhirContext(); + + retVal = super.getServerConformance(theRequest); + for (Rest nextRest : retVal.getRest()) { + for (RestResource nextResource : nextRest.getResource()) { + + // Add resource counts + Long count = counts.get(nextResource.getTypeElement().getValueAsString()); + if (count != null) { + nextResource.addUndeclaredExtension(false, ExtensionConstants.CONF_RESOURCE_COUNT, new DecimalDt(count)); + } + + // Add chained params + for (RestResourceSearchParam nextParam : nextResource.getSearchParam()) { + if (nextParam.getTypeElement().getValueAsEnum() == SearchParamTypeEnum.REFERENCE) { + List> targets = nextParam.getTarget(); + for (BoundCodeDt next : targets) { + RuntimeResourceDefinition def = ctx.getResourceDefinition(next.getValue()); + for (RuntimeSearchParam nextChainedParam : def.getSearchParams()) { + nextParam.addChain(nextChainedParam.getName()); + } + } + } + } + + } + } + + retVal.getImplementation().setDescription(myImplementationDescription); + myCachedValue = retVal; + return retVal; + } + + public void setImplementationDescription(String theImplDesc) { + myImplementationDescription = theImplDesc; + } + +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDstu1.java similarity index 93% rename from hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProvider.java rename to hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDstu1.java index e0fbd37b15d..28081d0899f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDstu1.java @@ -21,14 +21,14 @@ import ca.uhn.fhir.util.ExtensionConstants; import javax.servlet.http.HttpServletRequest; -public class JpaConformanceProvider extends ServerConformanceProvider { +public class JpaConformanceProviderDstu1 extends ServerConformanceProvider { private String myImplementationDescription; private IFhirSystemDao mySystemDao; private volatile Conformance myCachedValue; private RestfulServer myRestfulServer; - public JpaConformanceProvider(RestfulServer theRestfulServer, IFhirSystemDao theSystemDao) { + public JpaConformanceProviderDstu1(RestfulServer theRestfulServer, IFhirSystemDao theSystemDao) { super(theRestfulServer); myRestfulServer = theRestfulServer; mySystemDao = theSystemDao; diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index 11e6b282c0c..e1d843f5ae2 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -41,14 +41,14 @@ com.phloc phloc-schematron - ${phloc_schematron_version} + ${phloc_schematron_version} com.phloc phloc-commons - ${phloc_commons_version} + ${phloc_commons_version} - + ca.uhn.hapi.fhir hapi-fhir-jpaserver-test @@ -151,11 +151,18 @@ test + + + org.apache.commons + commons-dbcp2 + 2.0.1 + diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java index bf4786fb6af..f0d2b03043c 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java @@ -10,7 +10,8 @@ import org.springframework.web.context.ContextLoaderListener; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; -import ca.uhn.fhir.jpa.provider.JpaConformanceProvider; +import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDev; +import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu1; import ca.uhn.fhir.jpa.provider.JpaSystemProvider; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; @@ -22,103 +23,96 @@ import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor; public class TestRestfulServer extends RestfulServer { private static final long serialVersionUID = 1L; - + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestRestfulServer.class); private ApplicationContext myAppCtx; - + @SuppressWarnings("unchecked") @Override protected void initialize() throws ServletException { super.initialize(); - -// try { -// ourLog.info("Creating database"); -// DriverManager.getConnection("jdbc:derby:directory:" + System.getProperty("fhir.db.location") + ";create=true"); -// } catch (Exception e) { -// ourLog.error("Failed to create database: {}",e); -// } - - -// myAppCtx = new ClassPathXmlApplicationContext("fhir-spring-uhnfhirtest-config.xml", "hapi-jpaserver-springbeans.xml"); -// myAppCtx = new FileSystemXmlApplicationContext( -// "WEB-INF/hapi-fhir-server-database-config.xml", -// "WEB-INF/hapi-fhir-server-config.xml" -// ); + // Get the spring context from the web container (it's declared in web.xml) + myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext(); + // These two parmeters are also declared in web.xml + String implDesc = getInitParameter("ImplementationDescription"); String fhirVersionParam = getInitParameter("FhirVersion"); if (StringUtils.isBlank(fhirVersionParam)) { - fhirVersionParam="DSTU1"; + fhirVersionParam = "DSTU1"; } - - myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext(); - + + // Depending on the version this server is supporing, we will + // retrieve all the appropriate resource providers and the + // conformance provider List beans; JpaSystemProvider systemProvider; IFhirSystemDao systemDao; switch (fhirVersionParam.trim().toUpperCase()) { case "DSTU": - case "DSTU1": + case "DSTU1": { setFhirContext(FhirContext.forDstu1()); beans = myAppCtx.getBean("myResourceProvidersDstu1", List.class); systemProvider = myAppCtx.getBean("mySystemProviderDstu1", JpaSystemProvider.class); systemDao = myAppCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class); + JpaConformanceProviderDstu1 confProvider = new JpaConformanceProviderDstu1(this, systemDao); + confProvider.setImplementationDescription(implDesc); + setServerConformanceProvider(confProvider); break; - case "DEV": + } + case "DEV": { setFhirContext(FhirContext.forDev()); beans = myAppCtx.getBean("myResourceProvidersDev", List.class); systemProvider = myAppCtx.getBean("mySystemProviderDev", JpaSystemProvider.class); systemDao = myAppCtx.getBean("mySystemDaoDev", IFhirSystemDao.class); + JpaConformanceProviderDev confProvider = new JpaConformanceProviderDev(this, systemDao); + confProvider.setImplementationDescription(implDesc); + setServerConformanceProvider(confProvider); break; + } default: throw new ServletException("Unknown FHIR version specified in init-param[FhirVersion]: " + fhirVersionParam); } - - FhirContext ctx = getFhirContext(); - ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); - + for (IResourceProvider nextResourceProvider : beans) { ourLog.info(" * Have resource provider for: {}", nextResourceProvider.getResourceType().getSimpleName()); } setResourceProviders(beans); setPlainProviders(systemProvider); - - String implDesc = getInitParameter("ImplementationDescription"); - - JpaConformanceProvider confProvider = new JpaConformanceProvider(this, systemDao); - confProvider.setImplementationDescription(implDesc); - setServerConformanceProvider(confProvider); + + FhirContext ctx = getFhirContext(); + ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); setUseBrowserFriendlyContentTypes(true); - + String baseUrl = System.getProperty("fhir.baseurl"); if (StringUtils.isBlank(baseUrl)) { throw new ServletException("Missing system property: fhir.baseurl"); } - + setServerAddressStrategy(new HardcodedServerAddressStrategy(baseUrl)); setPagingProvider(new FifoMemoryPagingProvider(10)); - + LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); loggingInterceptor.setLoggerName("fhirtest.access"); loggingInterceptor.setMessageFormat("Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]"); this.registerInterceptor(loggingInterceptor); - + } @Override public void destroy() { super.destroy(); - -// myAppCtx.close(); -// -// try { -// ourLog.info("Shutting down derby"); -// DriverManager.getConnection("jdbc:derby:directory:" + System.getProperty("fhir.db.location") + ";shutdown=true"); -// } catch (Exception e) { -// ourLog.info("Failed to create database: {}",e.getMessage()); -// } + + // myAppCtx.close(); + // + // try { + // ourLog.info("Shutting down derby"); + // DriverManager.getConnection("jdbc:derby:directory:" + System.getProperty("fhir.db.location") + ";shutdown=true"); + // } catch (Exception e) { + // ourLog.info("Failed to create database: {}",e.getMessage()); + // } } } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml index 579b995dbbb..7590c543962 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml @@ -28,8 +28,10 @@ --> + diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml index c3abff2f203..32b386941d4 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml @@ -25,7 +25,7 @@ - + diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml index 1bc844d3cf5..5725f359e13 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml @@ -13,9 +13,9 @@ home , DSTU1 , UHN/HAPI Server (DSTU1 FHIR) , http://fhirtest.uhn.ca/baseDstu1 - home_dev , DEV , UHN/HAPI Server (DSTU2 FHIR) , http://fhirtest.uhn.ca/baseDev + home_dev , DEV , UHN/HAPI Server (DSTU2 FHIR) , http://fhirtest.uhn.ca/baseDev hi , DSTU1 , Health Intersections (DSTU1 FHIR) , http://fhir.healthintersections.com.au/open - hidev , DEV , Health Intersections (DSTU2 FHIR) , http://fhir-dev.healthintersections.com.au/open + hidev , DEV , Health Intersections (DSTU2 FHIR) , http://fhir-dev.healthintersections.com.au/open furore , DSTU1 , Spark - Furore , http://spark.furore.com/fhir blaze , DSTU1 , Blaze (Orion Health) , https://fhir.orionhealth.com/blaze/fhir oridashi , DSTU1 , Oridashi , http://demo.oridashi.com.au:8190 diff --git a/hapi-fhir-structures-dev/.gitignore b/hapi-fhir-structures-dev/.gitignore index a1c3ab4d08c..521dc209ce2 100644 --- a/hapi-fhir-structures-dev/.gitignore +++ b/hapi-fhir-structures-dev/.gitignore @@ -2,3 +2,4 @@ /.settings/ .classpath .project +/target/ diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java index bae7804fad1..7e1009339b1 100644 --- a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java @@ -41,7 +41,7 @@ public class FhirDev implements IFhirVersion { private String myId; @Override - public Object createServerConformanceProvider(RestfulServer theServer) { + public ServerConformanceProvider createServerConformanceProvider(RestfulServer theServer) { return new ServerConformanceProvider(theServer); } diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java index 2395699e1e4..d0d0ed6963b 100644 --- a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java @@ -28,6 +28,8 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import javax.servlet.http.HttpServletRequest; + import org.apache.commons.lang3.StringUtils; import ca.uhn.fhir.context.RuntimeResourceDefinition; @@ -58,6 +60,7 @@ import ca.uhn.fhir.rest.method.IParameter; import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.method.SearchParameter; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; @@ -71,7 +74,7 @@ import ca.uhn.fhir.util.ExtensionConstants; * false. This means that if you are adding anything to the returned conformance instance on each call you should call setCache(false) in your provider constructor. *

    */ -public class ServerConformanceProvider { +public class ServerConformanceProvider implements IServerConformanceProvider { private boolean myCache = true; private volatile Conformance myConformance; @@ -90,13 +93,9 @@ public class ServerConformanceProvider { return myPublisher; } - /** - * Actually create and return the conformance statement - * - * See the class documentation for an important note if you are extending this class - */ + @Override @Metadata - public Conformance getServerConformance() { + public Conformance getServerConformance(HttpServletRequest theRequest) { if (myConformance != null && myCache) { return myConformance; } @@ -136,7 +135,7 @@ public class ServerConformanceProvider { String resourceName = next.getResourceName(); RuntimeResourceDefinition def = myRestfulServer.getFhirContext().getResourceDefinition(resourceName); resource.getTypeElement().setValue(def.getName()); - resource.getProfile().setReference(new IdDt(def.getResourceProfile())); + resource.getProfile().setReference(new IdDt(def.getResourceProfile(myRestfulServer.getServerBaseForRequest(theRequest)))); TreeSet includes = new TreeSet(); diff --git a/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java index 7f7d1926924..30fe1506ae5 100644 --- a/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java +++ b/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -1,6 +1,10 @@ package ca.uhn.fhir.parser; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import net.sf.json.JSON; import net.sf.json.JSONSerializer; import net.sf.json.JsonConfig; @@ -11,16 +15,17 @@ import org.junit.Test; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.ExtensionDt; -import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.dev.resource.MedicationPrescription; import ca.uhn.fhir.model.dev.resource.Patient; +import ca.uhn.fhir.model.dev.resource.QuestionnaireAnswers; import ca.uhn.fhir.model.dstu.resource.Binary; import ca.uhn.fhir.model.primitive.BooleanDt; import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.model.primitive.DateDt; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.StringDt; public class JsonParserTest { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserTest.class); @@ -37,6 +42,23 @@ public class JsonParserTest { assertEquals("{\"resourceType\":\"Binary\",\"id\":\"11\",\"meta\":{\"versionId\":\"22\"},\"contentType\":\"foo\",\"content\":\"AQIDBA==\"}", val); } + /** + * #65 + */ + @Test + public void testJsonPrimitiveWithExtensionEncoding() { + + QuestionnaireAnswers parsed = new QuestionnaireAnswers(); + parsed.getGroup().setLinkId("value123"); + parsed.getGroup().getLinkIdElement().addUndeclaredExtension(false, "http://123", new StringDt("HELLO")); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(parsed); + ourLog.info(encoded); + assertThat(encoded, containsString("{\"linkId\":\"value123\",\"_linkId\":{\"http://123\":[{\"valueString\":\"HELLO\"}]}}")); + + } + + @Test public void testParsePatientInBundle() { diff --git a/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderTest.java b/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderTest.java index 81def22581f..9ff1e97d17f 100644 --- a/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderTest.java +++ b/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderTest.java @@ -4,11 +4,16 @@ import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.Collection; import java.util.List; import java.util.Set; +import javax.servlet.ServletConfig; +import javax.servlet.http.HttpServletRequest; + import org.junit.Test; import ca.uhn.fhir.context.FhirContext; @@ -46,7 +51,7 @@ public class ServerConformanceProviderTest { ServerConformanceProvider sc = new ServerConformanceProvider(rs); rs.setServerConformanceProvider(sc); - rs.init(null); + rs.init(createServletConfig()); boolean found=false; Collection resourceBindings = rs.getResourceBindings(); @@ -60,7 +65,7 @@ public class ServerConformanceProviderTest { } } assertTrue(found); - Conformance conformance = sc.getServerConformance(); + Conformance conformance = sc.getServerConformance(createHttpServletRequest()); String conf = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -80,11 +85,11 @@ public class ServerConformanceProviderTest { ServerConformanceProvider sc = new ServerConformanceProvider(rs); rs.setServerConformanceProvider(sc); - rs.init(null); + rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(); + Conformance conformance = sc.getServerConformance(createHttpServletRequest()); - myCtx.newValidator().validate(conformance); + assertTrue(myCtx.newValidator().validateWithResult(conformance).isSuccessful()); } @@ -98,7 +103,7 @@ public class ServerConformanceProviderTest { ServerConformanceProvider sc = new ServerConformanceProvider(rs); rs.setServerConformanceProvider(sc); - rs.init(null); + rs.init(createServletConfig()); boolean found=false; Collection resourceBindings = rs.getResourceBindings(); @@ -113,7 +118,7 @@ public class ServerConformanceProviderTest { } assertTrue(found); - Conformance conformance = sc.getServerConformance(); + Conformance conformance = sc.getServerConformance(createHttpServletRequest()); String conf = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -131,9 +136,9 @@ public class ServerConformanceProviderTest { ServerConformanceProvider sc = new ServerConformanceProvider(rs); rs.setServerConformanceProvider(sc); - rs.init(null); + rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(); + Conformance conformance = sc.getServerConformance(createHttpServletRequest()); String conf = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -171,7 +176,6 @@ public class ServerConformanceProviderTest { /** * Created by dsotnikov on 2/25/2014. */ - @SuppressWarnings("unused") public static class MultiOptionalProvider { @Search(type = Patient.class) @@ -203,4 +207,19 @@ public class ServerConformanceProviderTest { } + private HttpServletRequest createHttpServletRequest() { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/FhirStorm/fhir/Patient/_search"); + when(req.getServletPath()).thenReturn("/fhir"); + when(req.getRequestURL()).thenReturn(new StringBuffer().append("http://fhirstorm.dyndns.org:8080/FhirStorm/fhir/Patient/_search")); + when(req.getContextPath()).thenReturn("/FhirStorm"); + return req; + } + + private ServletConfig createServletConfig() { + ServletConfig sc = mock(ServletConfig.class); + when (sc.getServletContext()).thenReturn(null); + return sc; + } + } diff --git a/hapi-fhir-structures-dstu/.gitignore b/hapi-fhir-structures-dstu/.gitignore index 631a1a2575f..431375f8356 100644 --- a/hapi-fhir-structures-dstu/.gitignore +++ b/hapi-fhir-structures-dstu/.gitignore @@ -6,3 +6,4 @@ .classpath .project /target/ +/target/ diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java index ae46a99e9a2..113592a0e3f 100644 --- a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java @@ -70,6 +70,7 @@ import ca.uhn.fhir.model.dstu.valueset.DataTypeEnum; import ca.uhn.fhir.model.dstu.valueset.SlicingRulesEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider; import ca.uhn.fhir.rest.server.provider.ServerProfileProvider; @@ -81,7 +82,7 @@ public class FhirDstu1 implements IFhirVersion { private String myId; @Override - public Object createServerConformanceProvider(RestfulServer theServer) { + public ServerConformanceProvider createServerConformanceProvider(RestfulServer theServer) { return new ServerConformanceProvider(theServer); } diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java index c64742294df..84ced6418b7 100644 --- a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java @@ -55,6 +55,7 @@ import ca.uhn.fhir.rest.method.IParameter; import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.method.SearchParameter; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.util.ExtensionConstants; @@ -71,7 +72,7 @@ import javax.servlet.http.HttpServletRequest; * setCache(false) in your provider constructor. *

    */ -public class ServerConformanceProvider { +public class ServerConformanceProvider implements IServerConformanceProvider { private boolean myCache = true; private volatile Conformance myConformance; @@ -106,7 +107,7 @@ public class ServerConformanceProvider { retVal.setPublisher(myPublisher); retVal.setDate(DateTimeDt.withCurrentTime()); - retVal.setFhirVersion("0.80"); // TODO: pull from model + retVal.setFhirVersion("0.0.82-3059"); // TODO: pull from model retVal.setAcceptUnknown(false); // TODO: make this configurable - this is a fairly big effort since the parser needs to be modified to actually allow it retVal.getImplementation().setDescription(myRestfulServer.getImplementationDescription()); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java index c91d77b13e2..1071bb39493 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -49,6 +49,7 @@ import ca.uhn.fhir.model.dstu.resource.Organization; import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.dstu.resource.Profile; import ca.uhn.fhir.model.dstu.resource.Query; +import ca.uhn.fhir.model.dstu.resource.Questionnaire; import ca.uhn.fhir.model.dstu.resource.Specimen; import ca.uhn.fhir.model.dstu.resource.ValueSet; import ca.uhn.fhir.model.dstu.resource.ValueSet.Define; @@ -89,6 +90,23 @@ public class JsonParserTest { } + /** + * #65 + */ + @Test + public void testJsonPrimitiveWithExtensionEncoding() { + String res = "{\"resourceType\":\"Questionnaire\",\"status\":\"draft\",\"authored\":\"2014-10-30T14:15:00\",\"subject\":{\"reference\":\"http://www.hl7.org/fhir/Patient/1\"},\"author\":{\"reference\":\"http://www.hl7.org/fhir/Practitioner/1\"},\"name\":{\"text\":\"WDHB Friends and Family Test\"},\"group\":{\"header\":\"Note: This is an anonymous survey, which means you cannot be identified.\",\"_header\":[{\"extension\":[{\"url\":\"http://hl7.org/fhir/Profile/iso-21090#language\",\"valueCode\":\"en\"},{\"url\":\"http://hl7.org/fhir/Profile/iso-21090#string-translation\",\"valueString\":\"è«\\u008b注æ\\u0084\\u008fï¼\\u009aè¿\\u0099æ\\u0098¯ä¸\\u0080个å\\u008c¿å\\u0090\\u008dè°\\u0083æ\\u009f¥ï¼\\u008c被è°\\u0083æ\\u009f¥äººå°\\u0086ä¸\\u008dä¼\\u009a被è¯\\u0086å\\u0088«å\\u0087ºæ\\u009d¥ã\\u0080\\u0082\"},{\"url\":\"http://hl7.org/fhir/Profile/iso-21090#string-translation\",\"valueString\":\"ì\\u009dµëª\\u0085ì\\u009c¼ë¡\\u009c í\\u0095\\u0098ë\\u008a\\u0094 ì\\u0084¤ë¬¸ì¡°ì\\u0082¬ì\\u009d´ë¯\\u0080ë¡\\u009c ì\\u009e\\u0091ì\\u0084±ì\\u009e\\u0090ê°\\u0080 ë\\u0088\\u0084구ì\\u009d¸ì§\\u0080 ë°\\u009dí\\u0098\\u0080ì§\\u0080ì§\\u0080 ì\\u0095\\u008aì\\u008aµë\\u008b\\u0088ë\\u008b¤.\"}]}],\"question\":[{\"extension\":[{\"url\":\"http://hl7.org/fhir/questionnaire-extensions#answerFormat\",\"valueCode\":\"single-choice\"}],\"text\":\"Are you a patient?\",\"options\":{\"reference\":\"#question1\"}}]}}"; + Questionnaire parsed = ourCtx.newJsonParser().parseResource(Questionnaire.class, res); + assertEquals("Note: This is an anonymous survey, which means you cannot be identified.", parsed.getGroup().getHeader().getValue()); + assertEquals(1, parsed.getGroup().getHeader().getUndeclaredExtensionsByUrl("http://hl7.org/fhir/Profile/iso-21090#language").size()); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(parsed); + ourLog.info(encoded); + assertThat(encoded, containsString("\"_header\":{")); + + } + + @Test public void testEncodeNonContained() { Organization org = new Organization(); @@ -193,7 +211,7 @@ public class JsonParserTest { encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c); ourLog.info(encoded); - assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"_acceptUnknown\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}]}"); + assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"_acceptUnknown\":{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}}"); // Now with a value ourLog.info("---------------"); @@ -207,7 +225,7 @@ public class JsonParserTest { encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c); ourLog.info(encoded); - assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"acceptUnknown\":true,\"_acceptUnknown\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}]}"); + assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"acceptUnknown\":true,\"_acceptUnknown\":{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}}"); } diff --git a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java index 8b067dcccee..a6f4d96acac 100644 --- a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java +++ b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java @@ -13,7 +13,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; -import ca.uhn.fhir.jpa.provider.JpaConformanceProvider; +import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu1; import ca.uhn.fhir.jpa.provider.JpaSystemProvider; import ca.uhn.fhir.jpa.rp.dev.DiagnosticReportResourceProvider; import ca.uhn.fhir.jpa.rp.dev.ObservationResourceProvider; diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java index 199a5e98748..73bdc1e28ab 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java @@ -43,7 +43,7 @@ public class FhirDev implements IFhirVersion { private String myId; @Override - public Object createServerConformanceProvider(RestfulServer theServer) { + public ServerConformanceProvider createServerConformanceProvider(RestfulServer theServer) { return new ServerConformanceProvider(theServer); } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java index 1c379803917..8851aa5e188 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java @@ -82,7 +82,7 @@ public class FhirDstu1 implements IFhirVersion { private String myId; @Override - public Object createServerConformanceProvider(RestfulServer theServer) { + public ServerConformanceProvider createServerConformanceProvider(RestfulServer theServer) { return new ServerConformanceProvider(theServer); } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java index c64742294df..a8c4bf69646 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java @@ -55,6 +55,7 @@ import ca.uhn.fhir.rest.method.IParameter; import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.method.SearchParameter; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.util.ExtensionConstants; @@ -71,7 +72,7 @@ import javax.servlet.http.HttpServletRequest; * setCache(false) in your provider constructor. *

    */ -public class ServerConformanceProvider { +public class ServerConformanceProvider implements IServerConformanceProvider { private boolean myCache = true; private volatile Conformance myConformance; diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java index f2e9ae9c740..221c280127a 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java @@ -28,6 +28,8 @@ import java.util.List; import java.util.Set; import java.util.TreeSet; +import javax.servlet.http.HttpServletRequest; + import org.apache.commons.lang3.StringUtils; import ca.uhn.fhir.context.RuntimeResourceDefinition; @@ -54,6 +56,7 @@ import ca.uhn.fhir.rest.method.IParameter; import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.method.SearchParameter; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.util.ExtensionConstants; @@ -68,7 +71,7 @@ import ca.uhn.fhir.util.ExtensionConstants; * setCache(false) in your provider constructor. *

    */ -public class ServerConformanceProvider { +public class ServerConformanceProvider implements IServerConformanceProvider { private boolean myCache = true; private volatile Conformance myConformance; @@ -94,7 +97,7 @@ public class ServerConformanceProvider { * See the class documentation for an important note if you are extending this class */ @Metadata - public Conformance getServerConformance() { + public Conformance getServerConformance(HttpServletRequest theReq) { if (myConformance != null && myCache) { return myConformance; } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 614948246ca..5e393a6fef8 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -11,6 +11,13 @@ Support for DSTU2 features introduced: New Bundle encoding style, as well as new extension encoding in JSON. + + Fix an issue encoding extensions on primitive types in JSON. Previously the "_value" object + would be an array even if the field it was extending was not repeatable. This is not correct + according to the specification, nor can HAPI's parser parse this correctly. The encoder + has been corrected, and the parser has been adjusted to be able to handle resources with + extensions encoded in this way. Thanks to Mohammad Jafari for reporting! + Library now checks if custom resource types can be instantiated on startup (e.g. because they don't have a no-argument constructor) in order to diff --git a/src/changes/changes.xml.orig b/src/changes/changes.xml.orig new file mode 100644 index 00000000000..d6c5eefd9e4 --- /dev/null +++ b/src/changes/changes.xml.orig @@ -0,0 +1,656 @@ + + + + James Agnew + HAPI FHIR Changelog + + + + + Support for DSTU2 features introduced: New Bundle encoding style, as well as new + extension encoding in JSON. + + + Library now checks if custom resource types can be instantiated on startup + (e.g. because they don't have a no-argument constructor) in order to + avoid failing later + +<<<<<<< HEAD + + Bump a few dependency JARs to the latest versions in Maven POM: + +
  • SLF4j (in base module) - Bumped to 1.7.9
  • +
  • Apache HTTPClient (in base module) - Bumped to 4.3.6
  • +
  • Hibernate (in JPA module) - Bumped to 4.3.7
  • + + ]]> +======= + + IdDt failed to recognize local identifiers containing fragments that look like + real identifiers as being local identifiers even though they started with '#'. + For example, a local resource reference of "#aa/_history/aa" would be incorrectly + parsed as a non-local reference. + Thanks to Mohammad Jafari for reporting! +>>>>>>> 31d61100db41590b9760daf9e0942ad553ff69e2 + +
    + + + API CHANGE:]]> The "FHIR structures" for DSTU1 (the classes which model the + resources and composite datatypes) have been moved out of the core JAR into their + own JAR, in order to allow support for DEV resources, and DSTU2 resources when thast + version is finalized. See + upgrading]]> + for more information. + + + Deprocated API Removal: The following classes (which were deprocated previously) + have now been removed: +
      +
    • ISecurityManager: If you are using this class, the same functionality + is available through the more general purpose + server interceptor + capabilities. +
    • CodingListParam: This class was made redundant by the + TokenOrListParam + class, which can be used in its place. +
    + ]]> +
    + + API Change: The IResource#getResourceMetadata() method has been changed + from returning + Map<ResourceMetadataKeyEnum<?>, Object> + to returning a new type called + ResourceMetadataMap. This new type implements + Map<ResourceMetadataKeyEnum<?>, Object> + itself, so this change should not break existing code, but may + require a clean build in order to run correctly. + ]]> + + + Profile generation on the server was not working due to IdDt being + incorrectly used. Thanks to Bill de Beaubien for the pull request! + + + Profiles did not generate correctly if a resource definition class had a + defined extension which was of a composite type. Thanks to Bill de Beaubien for the pull request! + + + Remove unnecessary IOException from narrative generator API. Thanks to + Petro Mykhailysyn for the pull request! + + + Introduced a new + @ProvidesResources]]> annotation which can be added to + resource provider and servers to allow them to declare additional resource + classes they are able to serve. This is useful if you have a server which can + serve up multiple classes for the same resource type (e.g. a server that sometimes + returns a default Patient, but sometimes uses a custom subclass). + Thanks to Bill de Beaubien for the pull request! +
    + + Introduced a new + @Destroy]]> annotation which can be added to + a resource provider method. This method will be called by the server when it + is being closed/destroyed (e.g. when the application is being undeployed, the + container is being shut down, etc.) + Thanks to Bill de Beaubien for the pull request! + + + Add a new method to the server interceptor + framework which allows interceptors to be notified of any exceptions and + runtime errors within server methods. Interceptors may optionally also + override the default error handling behaviour of the RestfulServer. + + + Add constants to BaseResource for the "_id" search parameter which all resources + should support. + + + DateRangeParam parameters on the server now return correct + getLowerBoundAsInstant()]]> + and + getUpperBoundAsInstant()]]> + values if a single unqualified value is passed in. For example, if + a query containing + &birthdate=2012-10-01]]> + is received, previously these two methods would both return the same + value, but with this fix + getUpperBoundAsInstant()]]> + now returns the instant at 23:59:59.9999. + + + Resource fields with a type of "*" (or Any) sometimes failed to parse if a + value type of "code" was used. Thanks to Bill de Beaubien for reporting! + + + Remove dependency on JAXB libraries, which were used to parse and encode + dates and times (even in the JSON parser). JAXB is built in to most JDKs + but the version bundled with IBM's JDK is flaky and resulted in a number + of problems when deploying to Websphere. + + + Primitive datatypes now preserve their original string value when parsing resources, + as well as containing the "parsed value". For instance, a DecimalDt field value of + 1.0000]]> will be parsed into the corresponding + decimal value, but will also retain the original value with the corresponding + level of precision. This allows vadliator rules to be applied to + original values as received "over the wire", such as well formatted but + invalid dates, e.g. "2001-15-01". Thanks to Joe Athman for reporting and + helping to come up with a fix! + + + When using Generic Client, if performing a + or operation using a String as the resource body, + the client will auto-detect the FHIR encoding style and send an appropriate + header. + + + JPA module (and public HAPI-FHIR test server) were unable to process resource types + where at least one search parameter has no path specified. These now correctly save + (although the server does not yet process these params, and it should). Thanks to + GitHub user shvoidlee for reporting and help with analysis! + + + Generic/Fluent Client "create" and "update" method requests were not setting a content type header + + + DateDt left precision value as in the constructor + . + + + RESTful server now doesn't overwrite resource IDs if they are absolute. In other words, if + a server's Resource Provider returns a resource with ID "Patient/123" it will be translated to + "[base url]/Patient/123" but if the RP returns ID "http://foo/Patient/123" the ID will be + returned exactly as is. Thanks to Bill de Beaubien for the suggestion! + + + JPA module Transaction operation was not correctly replacing logical IDs + beginning with "cid:" with server assigned IDs, as required by the + specification. + + + did not visit or find children in contained resources when + searching a resource. This caused server implementations to not always return contained + resources when they are included with a resource being returned. + + + Add a method which returns the name of the + resource in question (e.g. "Patient", or "Observation"). This is intended as a + convenience to users. + + + Do not strip version from resource references in resources returned + from server search methods. Thanks to Bill de Beaubien for reporting! + + + Correct an issue with the validator where changes to the underlying + OperationOutcome produced by a validation cycle cause the validation + results to be incorrect. + + + Client interceptors registered to an interface based client instance + were applied to other client instances for the same client interface as well. (Issue + did not affect generic/fluent clients) + + + DateDt, DateTimeDt and types InstantDt types now do not throw an exception + if they are used to parse a value with the wrong level of precision for + the given type but do throw an exception if the wrong level of precision + is passed into their constructors.
    ]]> + This means that HAPI FHIR can now successfully parse resources from external + sources that have the wrong level of precision, but will generate a validation + error if the resource is validated. Thanks to Alexander Kley for the suggestion! +
    + + Encoding a Binary resource without a content type set should not result in a NullPointerException. Thanks + to Alexander Kley for reporting! + + + Server gives a more helpful error message if multiple IResourceProvider implementations + are provided for the same resource type. Thanks to wanghaisheng for the idea! + + + Bring DSTU1 resource definitions up to version 0.0.82-2929]]> + Bring DEV resource definitions up to 0.4.0-3775]]> + Thanks to crinacimpian for reporting! + + + JPA server did not correctly process _include requests if included + resources were present with a non-numeric identifier. Thanks to + Bill de Beaubien for reporting! + + + Client requests which include a resource/bundle body (e.g. create, + update, transaction) were not including a charset in the content type + header, leading to servers incorrectly assuming ISO-8859/1. Thanks to + shvoidlee for reporting! + + + Clean up the way that Profile resources are automatically exported + by the server for custom resource profile classes. See the + @ResourceDef]]> + JavaDoc for information on how this works. + + + + + API CHANGE:]]> The TagList class previously implemented ArrayList semantics, + but this has been replaced with LinkedHashMap semantics. This means that the list of + tags will no longer accept duplicate tags, but that tag order will still be + preserved. Thanks to Bill de Beaubien for reporting! + + + Server was incorrectly including contained resources being returned as both contained resources, and as + top-level resources in the returned bundle for search operations. + Thanks to Bill de Beaubien for reporting! This also fixes Issue #20, thanks to + lephty for reporting! + + + Documentation fixes + + + Add a collection of new methods on the generic client which support the + read, + read, + and search + ]]> + operations using an absolute URL. This allows developers to perform these operations using + URLs they obtained from other sources (or external resource references within resources). In + addition, the existing read/vread operations will now access absolute URL references if + they are passed in. Thanks to Doug Martin of the Regenstrief Center for Biomedical Informatics + for contributing this implementation! + + + Server implementation was not correctly figuring out its own FHIR Base URL when deployed + on Amazon Web Service server. Thanks to Jeffrey Ting and Bill De Beaubien of + Systems Made Simple for their help in figuring out this issue! + + + XML Parser failed to encode fields with both a resource reference child and + a primitive type child. Thanks to Jeffrey Ting and Bill De Beaubien of + Systems Made Simple for their help in figuring out this issue! + + + HAPI now runs successfully on Servlet 2.5 containers (such as Tomcat 6). Thanks to + Bernard Gitaadji for reporting and diagnosing the issue! + + + Summary (in the bundle entry) is now encoded by the XML and JSON parsers if supplied. Thanks to David Hay of + Orion Health for reporting this! + + + Conformance profiles which are automatically generated by the server were missing a few mandatory elements, + which meant that the profile did not correctly validate. Thanks to Bill de Beaubien of Systems Made Simple + for reporting this! + + + XHTML (in narratives) containing escapable characters (e.g. < or ") will now always have those characters + escaped properly in encoded messages. + + + Resources containing entities which are not valid in basic XML (e.g. &sect;) will have those + entities converted to their equivalent unicode characters when resources are encoded, since FHIR does + not allow extended entities in resource instances. + + + Add a new client interceptor which adds HTTP Authorization Bearer Tokens (for use with OAUTH2 servers) + to client requests. + + + Add phloc-commons dependency explicitly, which resolves an issue building HAPI from source on + some platforms. Thanks to Odysseas Pentakalos for the patch! + + + HAPI now logs a single line indicating the StAX implementation being used upon the + first time an XML parser is created. + + + Update methods on the server did not return a "content-location" header, but + only a "location" header. Both are required according to the FHIR specification. + Thanks to Bill de Beaubien of Systems Made Simple for reporting this! + + + Parser failed to correctly read contained Binary resources. Thanks to Alexander Kley for + the patch! + + + Calling encode multiple times on a resource with contained resources caused the contained + resources to be re-added (and the actual message to grow) with each encode pass. Thanks to + Alexander Kley for the test case! + + + JSON-encoded contained resources with the incorrect "_id" element (which should be "id", but some + incorrect examples exist on the FHIR specification) now parse correctly. In other words, HAPI + previously only accepted the correct "id" element, but now it also accepts the incorrect + "_id" element just to be more lenient. + + + Several unit tests failed on Windows (or any platform with non UTF-8 default encoding). This may + have also caused resource validation to fail occasionally on these platforms as well. + Thanks to Bill de Beaubien for reporting! + + + toString() method on TokenParam was incorrectly showing the system as the value. + Thanks to Bill de Beaubien for reporting! + + + Documentation on contained resources contained a typo and did not actually produce contained resources. Thanks + to David Hay of Orion Health for reporting! + + + Add a + Vagrant]]> + based environment (basically a fully built, self contained development environment) for + trying out the HAPI server modules. Thanks to Preston Lee for the pull request, and for + offering to maintain this! + + + Change validation API so that it uses a return type instead of exceptions to communicate + validation failures. Thanks to Joe Athman for the pull request! + + + Add a client interceptor which adds an HTTP cookie to each client request. Thanks to + Petro Mykhailysyn for the pull request! + + + + + + Add server interceptor framework, and new interceptor for logging incoming + requests. + + + Add server validation framework for validating resources against the FHIR schemas and schematrons + + + Tester UI created double _format and _pretty param entries in searches. Thanks to Gered King of University + Health Network for reporting! + + + Create method was incorrectly returning an HTTP 204 on sucessful completion, but + should be returning an HTTP 200 per the FHIR specification. Thanks to wanghaisheng + for reporting! + + + FHIR Tester UI now correctly sends UTF-8 charset in responses so that message payloads containing + non US-ASCII characters will correctly display in the browser + + + JSON parser was incorrectly encoding extensions on composite elements outside the element itself + (as is done correctly for non-composite elements) instead of inside of them. Thanks to David Hay of + Orion for reporting this! + + + Contained/included resource instances received by a client are now automatically + added to any ResourceReferenceDt instancea in other resources which reference them. + + + Add documentation on how to use eBay CORS Filter to support Cross Origin Resource + Sharing (CORS) to server. CORS support that was built in to the server itself has + been removed, as it did not work correctly (and was reinventing a wheel that others + have done a great job inventing). Thanks to Peter Bernhardt of Relay Health for all the assistance + in testing this! + + + IResource interface did not expose the getLanguage/setLanguage methods from BaseResource, + so the resource language was difficult to access. + + + JSON Parser now gives a more friendly error message if it tries to parse JSON with invalid use + of single quotes + + + Transaction server method is now allowed to return an OperationOutcome in addition to the + incoming resources. The public test server now does this in order to return status information + about the transaction processing. + + + Update method in the server can now flag (via a field on the MethodOutcome object being returned) + that the result was actually a creation, and Create method can indicate that it was actually an + update. This has no effect other than to switch between the HTTP 200 and HTTP 201 status codes on the + response, but this may be useful in some circumstances. + + + Annotation client search methods with a specific resource type (e.g. List<Patient> search()) + won't return any resources that aren't of the correct type that are received in a response + bundle (generally these are referenced resources, so they are populated in the reference fields instead). + Thanks to Tahura Chaudhry of University Health Network for the unit test! + + + Added narrative generator template for OperationOutcome resource + + + Date/time types did not correctly parse values in the format "yyyymmdd" (although the FHIR-defined format + is "yyyy-mm-dd" anyhow, and this is correctly handled). Thanks to Jeffrey Ting of Systems Made Simple + for reporting! + + + Server search method for an unnamed query gets called if the client requests a named query + with the same parameter list. Thanks to Neal Acharya of University Health Network for reporting! + + + Category header (for tags) is correctly read in client for "read" operation + + + Transaction method in server can now have parameter type Bundle instead of + List<IResource> + + + HAPI parsers now use field access to get/set values instead of method accessors and mutators. + This should give a small performance boost. + + + JSON parser encodes resource references incorrectly, using the name "resource" instead + of the name "reference" for the actual reference. Thanks to + Ricky Nguyen for reporting and tracking down the issue! + + + Rename NotImpementedException to NotImplementedException (to correct typo) + + + Server setUseBrowserFriendlyContentType setting also respected for errors (e.g. OperationOutcome with 4xx/5xx status) + + + Fix performance issue in date/time datatypes where pattern matchers were not static + + + Server now gives a more helpful error message if a @Read method has a search parameter (which is invalid, but + previously lead to a very unhelpful error message). Thanks to Tahura Chaudhry of UHN for reporting! + + + Resource of type "List" failed to parse from a bundle correctly. Thanks to David Hay of Orion Health + for reporting! + + + QuantityParam correctly encodes approximate (~) prefix to values + + + If a server defines a method with parameter "_id", incoming search requests for that method may + get delegated to the wrong method. Thanks to Neal Acharya for reporting! + + + SecurityEvent.Object structural element has been renamed to + SecurityEvent.ObjectElement to avoid conflicting names with the + java Object class. Thanks to Laurie Macdougall-Sookraj of UHN for + reporting! + + + Text/narrative blocks that were created with a non-empty + namespace prefix (e.g. <xhtml:div xmlns:xhtml="...">...</xhtml:div>) + failed to encode correctly (prefix was missing in encoded resource) + + + Resource references previously encoded their children (display and reference) + in the wrong order so references with both would fail schema validation. + + + SecurityEvent resource's enums now use friendly enum names instead of the unfriendly + numeric code values. Thanks to Laurie MacDougall-Sookraj of UHN for the + suggestion! + + + + + HAPI has a number of RESTful method parameter types that have similar but not identical + purposes and confusing names. A cleanup has been undertaken to clean this up. + This means that a number of existing classes + have been deprocated in favour of new naming schemes. +
    ]]> + All annotation-based clients and all server search method parameters are now named + (type)Param, for example: StringParam, TokenParam, etc. +
    ]]> + All generic/fluent client method parameters are now named + (type)ClientParam, for example: StringClientParam, TokenClientParam, etc. +
    ]]> + All renamed classes have been retained and deprocated, so this change should not cause any issues + for existing applications but those applications should be refactored to use the + new parameters when possible. +
    + + Allow server methods to return wildcard generic types (e.g. List<? extends IResource>) + + + Search parameters are not properly escaped and unescaped. E.g. for a token parameter such as + "&identifier=system|codepart1\|codepart2" + + + Add support for OPTIONS verb (which returns the server conformance statement) + + + Add support for CORS headers in server + + + Bump SLF4j dependency to latest version (1.7.7) + + + Add interceptor framework for clients (annotation based and generic), and add interceptors + for configurable logging, capturing requests and responses, and HTTP basic auth. + + + Transaction client invocations with XML encoding were using the wrong content type ("application/xml+fhir" instead + of the correct "application/atom+xml"). Thanks to David Hay of Orion Health for surfacing this one! + + + Bundle entries now support a link type of "search". Thanks to David Hay for the suggestion! + + + If a client receives a non 2xx response (e.g. HTTP 500) and the response body is a text/plain message or + an OperationOutcome resource, include the message in the exception message so that it will be + more conveniently displayed in logs and other places. Thanks to Neal Acharya for the suggestion! + + + Read invocations in the client now process the "Content-Location" header and use it to + populate the ID of the returned resource. Thanks to Neal Acharya for the suggestion! + + + Fix issue where vread invocations on server incorrectly get routed to instance history method if one is + defined. Thanks to Neal Acharya from UHN for surfacing this one! + + + Binary reads on a server not include the Content-Disposition header, to prevent HTML in binary + blobs from being used for nefarious purposes. See + FHIR Tracker Bug 3298]]> + for more information. + + + Support has been added for using an HTTP proxy for outgoing requests. + + + Fix: Primitive extensions declared against custom resource types + are encoded even if they have no value. Thanks to David Hay of Orion for + reporting this! + + + Fix: RESTful server deployed to a location where the URL to access it contained a + space (e.g. a WAR file with a space in the name) failed to work correctly. + Thanks to David Hay of Orion for reporting this! + +
    + + + BREAKING CHANGE:]]>: IdDt has been modified so that it + contains a partial or complete resource identity. Previously it contained + only the simple alphanumeric id of the resource (the part at the end of the "read" URL for + that resource) but it can now contain a complete URL or even a partial URL (e.g. "Patient/123") + and can optionally contain a version (e.g. "Patient/123/_history/456"). New methods have + been added to this datatype which provide just the numeric portion. See the JavaDoc + for more information. + + + API CHANGE:]]>: Most elements in the HAPI FHIR model contain + a getId() and setId() method. This method is confusing because it is only actually used + for IDREF elements (which are rare) but its name makes it easy to confuse with more + important identifiers. For this reason, these methods have been deprocated and replaced with + get/setElementSpecificId() methods. The old methods will be removed at some point. Resource + types are unchanged and retain their get/setId methods. + + + Allow use of QuantityDt as a service parameter to support the "quantity" type. Previously + QuantityDt did not implement IQueryParameterType so it was not valid, and there was no way to + support quantity search parameters on the server (e.g. Observation.value-quantity) + + + Introduce StringParameter type which can be used as a RESTful operation search parameter + type. StringParameter allows ":exact" matches to be specified in clients, and handled in servers. + + + Parsers (XML/JSON) now support deleted entries in bundles + + + Transaction method now supported in servers + + + Support for Binary resources added (in servers, clients, parsers, etc.) + + + Support for Query resources fixed (in parser) + + + Nested contained resources (e.g. encoding a resource with a contained resource that itself contains a resource) + now parse and encode correctly, meaning that all contained resources are placed in the "contained" element + of the root resource, and the parser looks in the root resource for all container levels when stitching + contained resources back together. + + + Server methods with @Include parameter would sometimes fail when no _include was actually + specified in query strings. + + + Client requests for IdentifierDt types (such as Patient.identifier) did not create the correct + query string if the system is null. + + + Add support for paging responses from RESTful servers. + + + Don't fail on narrative blocks in JSON resources with only an XML declaration but no content (these are + produced by the Health Intersections server) + + + Server now automatically compresses responses if the client indicates support + + + Server failed to support optional parameters when type is String and :exact qualifier is used + + + Read method in client correctly populated resource ID in returned object + + + Support added for deleted-entry by/name, by/email, and comment from Tombstones spec + + + + + + From b856c2386bedb54d69264daef01bce84fe6fa27d Mon Sep 17 00:00:00 2001 From: James Agnew Date: Tue, 23 Dec 2014 15:44:54 -0500 Subject: [PATCH 3/3] Better logging for public server --- .../interceptor/LoggingInterceptor.java | 23 ++++++++++--------- .../ca/uhn/fhirtest/TestRestfulServer.java | 15 ++++++++---- .../WEB-INF/hapi-fhir-tester-config.xml | 2 +- .../src/main/webapp/WEB-INF/web.xml | 5 ++++ 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java index 5dcdaa22e06..9ead6faca93 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptor.java @@ -68,6 +68,10 @@ import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; * ${requestParameters} * The HTTP request parameters (or "") * + * + * ${servletPath} + * The part of thre requesting URL that corresponds to the particular Servlet being called (see {@link HttpServletRequest#getServletPath()}) + * * */ public class LoggingInterceptor extends InterceptorAdapter { @@ -76,7 +80,7 @@ public class LoggingInterceptor extends InterceptorAdapter { private Logger myLogger = ourLog; private String myMessageFormat = "${operationType} - ${idOrResourceName}"; - + @Override public boolean incomingRequestPostProcessed(final RequestDetails theRequestDetails, final HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException { @@ -132,14 +136,14 @@ public class LoggingInterceptor extends InterceptorAdapter { return myRequestDetails.getOtherOperationType().getCode(); } return ""; - } - if ("id".equals(theKey)) { + } else if ("id".equals(theKey)) { if (myRequestDetails.getId() != null) { return myRequestDetails.getId().getValue(); } return ""; - } - if ("idOrResourceName".equals(theKey)) { + } else if ("servletPath".equals(theKey)) { + return StringUtils.defaultString(myRequest.getServletPath()); + } else if ("idOrResourceName".equals(theKey)) { if (myRequestDetails.getId() != null) { return myRequestDetails.getId().getValue(); } @@ -147,8 +151,7 @@ public class LoggingInterceptor extends InterceptorAdapter { return myRequestDetails.getResourceName(); } return ""; - } - if (theKey.equals("requestParameters")) { + } else if (theKey.equals("requestParameters")) { StringBuilder b = new StringBuilder(); for (Entry next : myRequestDetails.getParameters().entrySet()) { for (String nextValue : next.getValue()) { @@ -167,12 +170,10 @@ public class LoggingInterceptor extends InterceptorAdapter { } } return b.toString(); - } - if (theKey.startsWith("requestHeader.")) { + } else if (theKey.startsWith("requestHeader.")) { String val = myRequest.getHeader(theKey.substring("requestHeader.".length())); return StringUtils.defaultString(val); - } - if (theKey.startsWith("remoteAddr")) { + } else if (theKey.startsWith("remoteAddr")) { return StringUtils.defaultString(myRequest.getRemoteAddr()); } return "!VAL!"; diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java index f0d2b03043c..0c1820d5a19 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java @@ -49,6 +49,7 @@ public class TestRestfulServer extends RestfulServer { List beans; JpaSystemProvider systemProvider; IFhirSystemDao systemDao; + String baseUrlProperty; switch (fhirVersionParam.trim().toUpperCase()) { case "DSTU": case "DSTU1": { @@ -59,6 +60,7 @@ public class TestRestfulServer extends RestfulServer { JpaConformanceProviderDstu1 confProvider = new JpaConformanceProviderDstu1(this, systemDao); confProvider.setImplementationDescription(implDesc); setServerConformanceProvider(confProvider); + baseUrlProperty = "fhir.baseurl.dstu1"; break; } case "DEV": { @@ -69,6 +71,7 @@ public class TestRestfulServer extends RestfulServer { JpaConformanceProviderDev confProvider = new JpaConformanceProviderDev(this, systemDao); confProvider.setImplementationDescription(implDesc); setServerConformanceProvider(confProvider); + baseUrlProperty = "fhir.baseurl.dstu2"; break; } default: @@ -83,12 +86,16 @@ public class TestRestfulServer extends RestfulServer { FhirContext ctx = getFhirContext(); ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); - + setUseBrowserFriendlyContentTypes(true); - String baseUrl = System.getProperty("fhir.baseurl"); + String baseUrl = System.getProperty(baseUrlProperty); if (StringUtils.isBlank(baseUrl)) { - throw new ServletException("Missing system property: fhir.baseurl"); + // Fall back to the old URL + baseUrl = System.getProperty("fhir.baseurl"); + if (StringUtils.isBlank(baseUrl)) { + throw new ServletException("Missing system property: " + baseUrlProperty); + } } setServerAddressStrategy(new HardcodedServerAddressStrategy(baseUrl)); @@ -96,7 +103,7 @@ public class TestRestfulServer extends RestfulServer { LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); loggingInterceptor.setLoggerName("fhirtest.access"); - loggingInterceptor.setMessageFormat("Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]"); + loggingInterceptor.setMessageFormat("Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]"); this.registerInterceptor(loggingInterceptor); } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml index 5725f359e13..6731c447a37 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-tester-config.xml @@ -13,7 +13,7 @@ home , DSTU1 , UHN/HAPI Server (DSTU1 FHIR) , http://fhirtest.uhn.ca/baseDstu1 - home_dev , DEV , UHN/HAPI Server (DSTU2 FHIR) , http://fhirtest.uhn.ca/baseDev + home_dev , DEV , UHN/HAPI Server (DSTU2 FHIR) , http://fhirtest.uhn.ca/baseDstu2 hi , DSTU1 , Health Intersections (DSTU1 FHIR) , http://fhir.healthintersections.com.au/open hidev , DEV , Health Intersections (DSTU2 FHIR) , http://fhir-dev.healthintersections.com.au/open furore , DSTU1 , Spark - Furore , http://spark.furore.com/fhir diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/web.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/web.xml index 07f1578b223..93a81b81e84 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/web.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/web.xml @@ -71,6 +71,11 @@ /baseDstu1/* + + fhirServletDev + /baseDstu2/* + + fhirServletDev /baseDev/*