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 extends IBaseResource> 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. §) 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/*