Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2017-07-20 10:19:18 -04:00
commit a220405e97
8 changed files with 219 additions and 6 deletions

View File

@ -99,7 +99,11 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
if (childOrder != null) {
forcedOrder = new HashMap<String, Integer>();
for (int i = 0; i < childOrder.names().length; i++) {
forcedOrder.put(childOrder.names()[i], i);
String nextName = childOrder.names()[i];
if (nextName.endsWith("[x]")) {
nextName = nextName.substring(0, nextName.length() - 3);
}
forcedOrder.put(nextName, i);
}
}
}

View File

@ -21,6 +21,7 @@ import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.demo.ContextHolder;
import ca.uhn.fhir.jpa.demo.FhirServerConfig;
import ca.uhn.fhir.jpa.demo.FhirServerConfigDstu3;
@ -30,6 +31,7 @@ public class RunServerCommand extends BaseCommand {
private static final String OPTION_DISABLE_REFERENTIAL_INTEGRITY = "disable-referential-integrity";
private static final String OPTION_LOWMEM = "lowmem";
private static final String OPTION_ALLOW_EXTERNAL_REFS = "allow-external-refs";
private static final String OPTION_REUSE_SEARCH_RESULTS_MILLIS = "reuse-search-results-milliseconds";
private static final int DEFAULT_PORT = 8080;
private static final String OPTION_P = "p";
@ -51,6 +53,10 @@ public class RunServerCommand extends BaseCommand {
options.addOption(null, OPTION_LOWMEM, false, "If this flag is set, the server will operate in low memory mode (some features disabled)");
options.addOption(null, OPTION_ALLOW_EXTERNAL_REFS, false, "If this flag is set, the server will allow resources to be persisted contaning external resource references");
options.addOption(null, OPTION_DISABLE_REFERENTIAL_INTEGRITY, false, "If this flag is set, the server will not enforce referential integrity");
Long defaultReuseSearchResults = DaoConfig.DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS;
String defaultReuseSearchResultsStr = defaultReuseSearchResults == null ? "off" : String.valueOf(defaultReuseSearchResults);
options.addOption(null, OPTION_REUSE_SEARCH_RESULTS_MILLIS, true, "The time in milliseconds within which the same results will be returned for multiple identical searches, or \"off\" (default is " + defaultReuseSearchResultsStr + ")");
return options;
}
@ -58,7 +64,7 @@ public class RunServerCommand extends BaseCommand {
try {
return Integer.parseInt(theCommandLine.getOptionValue(opt, Integer.toString(defaultPort)));
} catch (NumberFormatException e) {
throw new ParseException("Invalid value '" + theCommandLine.getOptionValue(opt) + " (must be numeric)");
throw new ParseException("Invalid value '" + theCommandLine.getOptionValue(opt) + "' (must be numeric)");
}
}
@ -81,6 +87,25 @@ public class RunServerCommand extends BaseCommand {
ContextHolder.setDisableReferentialIntegrity(true);
}
String reuseSearchResults = theCommandLine.getOptionValue(OPTION_REUSE_SEARCH_RESULTS_MILLIS);
if (reuseSearchResults != null) {
if (reuseSearchResults.equals("off")) {
ourLog.info("Server is configured to not reuse search results");
ContextHolder.setReuseCachedSearchResultsForMillis(null);
} else {
try {
long reuseSearchResultsMillis = Long.parseLong(reuseSearchResults);
if (reuseSearchResultsMillis < 0) {
throw new NumberFormatException("expected a positive integer");
}
ourLog.info("Server is configured to reuse search results for " + String.valueOf(reuseSearchResultsMillis) + " milliseconds");
ContextHolder.setReuseCachedSearchResultsForMillis(reuseSearchResultsMillis);
} catch (NumberFormatException e) {
throw new ParseException("Invalid value '" + reuseSearchResults + "' (must be a positive integer)");
}
}
}
ContextHolder.setCtx(getSpecVersionContext(theCommandLine));
ourLog.info("Preparing HAPI FHIR JPA server on port {}", myPort);

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.demo;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.Validate;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.context.FhirContext;
public class ContextHolder {
@ -11,6 +12,11 @@ public class ContextHolder {
private static FhirContext ourCtx;
private static boolean ourDisableReferentialIntegrity;
private static String ourPath;
private static Long ourReuseSearchResultsMillis;
static {
ourReuseSearchResultsMillis = DaoConfig.DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS;
}
public static FhirContext getCtx() {
Validate.notNull(ourPath, "Context not set");
@ -53,4 +59,11 @@ public class ContextHolder {
ourDisableReferentialIntegrity = theDisableReferentialIntegrity;
}
public static void setReuseCachedSearchResultsForMillis(Long reuseSearchResultsMillis) {
ourReuseSearchResultsMillis = reuseSearchResultsMillis;
}
public static Long getReuseCachedSearchResultsForMillis() {
return ourReuseSearchResultsMillis;
}
}

View File

@ -170,7 +170,7 @@ public class JpaServerDemo extends RestfulServer {
daoConfig.setAllowExternalReferences(ContextHolder.isAllowExternalRefs());
daoConfig.setEnforceReferentialIntegrityOnDelete(!ContextHolder.isDisableReferentialIntegrity());
daoConfig.setEnforceReferentialIntegrityOnWrite(!ContextHolder.isDisableReferentialIntegrity());
daoConfig.setReuseCachedSearchResultsForMillis(ContextHolder.getReuseCachedSearchResultsForMillis());
}
}

View File

@ -47,7 +47,8 @@ import org.hl7.fhir.exceptions.FHIRException;
* A statement of relationships from one set of concepts to one or more other concepts - either code systems or data elements, or classes in class models.
*/
@ResourceDef(name="ConceptMap", profile="http://hl7.org/fhir/Profile/ConceptMap")
@ChildOrder(names={"url", "identifier", "version", "name", "title", "status", "experimental", "date", "publisher", "contact", "description", "useContext", "jurisdiction", "purpose", "copyright", "source[x]", "target[x]", "group"})
//@ChildOrder(names={"url", "identifier", "version", "name", "title", "status", "experimental", "date", "publisher", "contact", "description", "useContext", "jurisdiction", "purpose", "copyright", "source[x]", "target[x]", "group"})
@ChildOrder(names={"url", "identifier", "version", "name", "title", "status", "experimental", "date", "publisher", "contact", "description", "useContext", "jurisdiction", "purpose", "copyright", "source", "target", "group"})
public class ConceptMap extends MetadataResource {
public enum ConceptMapGroupUnmappedMode {

View File

@ -36,6 +36,8 @@ import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Address.AddressUse;
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
@ -71,6 +73,9 @@ import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.IValidationContext;
import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationContext;
import ca.uhn.fhir.validation.ValidationResult;
import net.sf.json.JSON;
import net.sf.json.JSONSerializer;
@ -84,6 +89,78 @@ public class JsonParserDstu3Test {
public void after() {
ourCtx.setNarrativeGenerator(null);
}
@Test
public void testActivityDefinitionElementsOrder() throws Exception {
final String origContent = "{\"resourceType\":\"ActivityDefinition\",\"id\":\"x1\",\"url\":\"http://testing.org\",\"status\":\"draft\",\"timingDateTime\":\"2011-02-03\"}";
final IParser parser = ourCtx.newJsonParser();
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
// verify that InstanceValidator likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
ActivityDefinition fhirObj = parser.parseResource(ActivityDefinition.class, origContent);
String content = parser.encodeResourceToString(fhirObj);
ourLog.info("Serialized form: {}", content);
// verify that InstanceValidator still likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
// verify that the original and newly serialized match
Assert.assertEquals(origContent, content);
}
@Test
public void testConceptMapElementsOrder() throws Exception {
final String origContent = "{\"resourceType\":\"ConceptMap\",\"id\":\"x1\",\"url\":\"http://testing.org\",\"status\":\"draft\",\"sourceUri\":\"http://y1\"}";
final IParser parser = ourCtx.newJsonParser();
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
// verify that InstanceValidator likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
ConceptMap fhirObj = parser.parseResource(ConceptMap.class, origContent);
String content = parser.encodeResourceToString(fhirObj);
ourLog.info("Serialized form: {}", content);
// verify that InstanceValidator still likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
// verify that the original and newly serialized match
Assert.assertEquals(origContent, content);
}
/**
* See #563

View File

@ -34,6 +34,8 @@ import org.custommonkey.xmlunit.XMLUnit;
import org.hamcrest.collection.IsEmptyCollection;
import org.hamcrest.core.StringContains;
import org.hamcrest.text.StringContainsInOrder;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Address.AddressUse;
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
@ -67,6 +69,10 @@ import ca.uhn.fhir.parser.PatientWithCustomCompositeExtension.FooParentExtension
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.IValidationContext;
import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationContext;
import ca.uhn.fhir.validation.ValidationResult;
public class XmlParserDstu3Test {
private static FhirContext ourCtx = FhirContext.forDstu3();
@ -79,7 +85,7 @@ public class XmlParserDstu3Test {
}
ourCtx.setNarrativeGenerator(null);
}
/**
* See #544
*/
@ -107,7 +113,7 @@ public class XmlParserDstu3Test {
assertNotNull(subject);
assertEquals("FAMILY", subject.getNameFirstRep().getFamily());
}
@Test
public void testBundleWithBinary() {
@ -138,6 +144,81 @@ public class XmlParserDstu3Test {
}
/**
* See #683
*/
@Test
public void testChildOrderWithChoiceType() throws Exception {
final String origContent = "<ActivityDefinition xmlns=\"http://hl7.org/fhir\"><id value=\"x1\"/><url value=\"http://testing.org\"/><status value=\"draft\"/><timingDateTime value=\"2011-02-03\"/></ActivityDefinition>";
final IParser parser = ourCtx.newXmlParser();
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
// verify that InstanceValidator likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
ActivityDefinition fhirObj = parser.parseResource(ActivityDefinition.class, origContent);
String content = parser.encodeResourceToString(fhirObj);
ourLog.info("Serialized form: {}", content);
// verify that InstanceValidator still likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
// verify that the original and newly serialized match
Assert.assertEquals(origContent, content);
}
@Test
public void testConceptMapElementsOrder() throws Exception {
final String origContent = "<ConceptMap xmlns=\"http://hl7.org/fhir\"><id value=\"x1\"/><url value=\"http://testing.org\"/><status value=\"draft\"/><sourceUri value=\"http://url1\"/></ConceptMap>";
final IParser parser = ourCtx.newXmlParser();
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
// verify that InstanceValidator likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, origContent);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
ConceptMap fhirObj = parser.parseResource(ConceptMap.class, origContent);
String content = parser.encodeResourceToString(fhirObj);
ourLog.info("Serialized form: {}", content);
// verify that InstanceValidator still likes the format
{
IValidationContext<IBaseResource> validationCtx = ValidationContext.forText(ourCtx, content);
new FhirInstanceValidator(validationSupport).validateResource(validationCtx);
ValidationResult result = validationCtx.toResult();
for (SingleValidationMessage msg : result.getMessages()) {
ourLog.info("{}", msg);
}
Assert.assertEquals(0, result.getMessages().size());
}
// verify that the original and newly serialized match
Assert.assertEquals(origContent, content);
}
@Test
public void testContainedResourceInExtensionUndeclared() {
Patient p = new Patient();

View File

@ -164,6 +164,18 @@
Fix a typo in the documentation. Thanks to Saren Currie
for the pull request!
</action>
<action type="add" issue="689">
Add a command line flag to the CLI tool to allow configuration of the
server search result cache timeout period. Thanks to Eugene Lubarsky
for the pull request!
</action>
<action type="fix" issue="683">
Correct an issue with the model classes for STU3 where any classes
containing the @ChildOrder annotation (basically the conformance
resources) will not correctly set the order if any of the
elements are a choice type (i.e. named "foo[x]"). Thanks to
GitHub user @CarthageKing for the pull request!
</action>
</release>
<release version="2.5" date="2017-06-08">
<action type="fix">