Fix #24 - Add a bunch of elements to the automatically generated

conformance profiles to ensure that they validate against the HL7
schemas.
This commit is contained in:
James Agnew 2014-09-22 16:27:57 -04:00
parent 7192c9348a
commit c214f7fe19
7 changed files with 127 additions and 61 deletions

View File

@ -186,6 +186,8 @@ public class GenericClientExample {
}
}
public static void main(String[] args) {

View File

@ -45,6 +45,11 @@
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!
</action>
<action type="fix" issue="24">
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!
</action>
</release>
<release version="0.6" date="2014-Sep-08" description="This release brings a number of new features and bug fixes!">
<!--

View File

@ -91,4 +91,11 @@ public class DateTimeDt extends BaseDateTimeDt {
}
}
/**
* Returns a new instance of DateTimeDt with the current system time and SECOND precision
*/
public static DateTimeDt withCurrentTime() {
return new DateTimeDt(new Date(), TemporalPrecisionEnum.SECOND);
}
}

View File

@ -153,11 +153,11 @@ public class InstantDt extends BaseDateTimeDt {
}
/**
* Factory method which creates a new InstantDt and initializes it with the
* Factory method which creates a new InstantDt with millisecond precision and initializes it with the
* current time.
*/
public static InstantDt withCurrentTime() {
return new InstantDt(new Date());
return new InstantDt(new Date(), TemporalPrecisionEnum.MILLI);
}
}

View File

@ -45,6 +45,7 @@ import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.model.primitive.BooleanDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.Metadata;
@ -70,14 +71,24 @@ import ca.uhn.fhir.util.ExtensionConstants;
*/
public class ServerConformanceProvider {
private volatile Conformance myConformance;
private final RestfulServer myRestfulServer;
private boolean myCache = true;
private volatile Conformance myConformance;
private String myPublisher = "Not provided";
private final RestfulServer myRestfulServer;
public ServerConformanceProvider(RestfulServer theRestfulServer) {
myRestfulServer = theRestfulServer;
}
/**
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this
* is a mandatory element, the value should not be null (although this is not enforced). The value defaults
* to "Not provided" but may be set to null, which will cause this element to be omitted.
*/
public String getPublisher() {
return myPublisher;
}
/**
* Actually create and return the conformance statement
*
@ -91,6 +102,11 @@ public class ServerConformanceProvider {
Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher);
retVal.setDate(DateTimeDt.withCurrentTime());
retVal.setFhirVersion("0.80"); // 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());
retVal.getSoftware().setName(myRestfulServer.getServerName());
retVal.getSoftware().setVersion(myRestfulServer.getServerVersion());
@ -177,6 +193,51 @@ public class ServerConformanceProvider {
return retVal;
}
private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
includes.addAll(searchMethodBinding.getIncludes());
List<RuntimeSearchParam> searchParameters = new ArrayList<RuntimeSearchParam>();
searchParameters.addAll(searchMethodBinding.getSearchParams());
sortRuntimeSearchParameters(searchParameters);
if (!searchParameters.isEmpty()) {
for (RuntimeSearchParam nextParameter : searchParameters) {
String nextParamName = nextParameter.getName();
// String chain = null;
String nextParamUnchainedName = nextParamName;
if (nextParamName.contains(".")) {
// chain = nextParamName.substring(nextParamName.indexOf('.') + 1);
nextParamUnchainedName = nextParamName.substring(0, nextParamName.indexOf('.'));
}
String nextParamDescription = nextParameter.getDescription();
/*
* If the parameter has no description, default to the one from the resource
*/
if (StringUtils.isBlank(nextParamDescription)) {
RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName);
if (paramDef != null) {
nextParamDescription = paramDef.getDescription();
}
}
RestResourceSearchParam param;
param = resource.addSearchParam();
param.setName(nextParamName);
// if (StringUtils.isNotBlank(chain)) {
// param.addChain(chain);
// }
param.setDocumentation(nextParamDescription);
param.setType(nextParameter.getParamType());
}
}
}
private void handleSearchMethodBinding(Rest rest, RestResource resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes, SearchMethodBinding searchMethodBinding) {
includes.addAll(searchMethodBinding.getIncludes());
@ -251,49 +312,24 @@ public class ServerConformanceProvider {
}
}
private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
includes.addAll(searchMethodBinding.getIncludes());
List<RuntimeSearchParam> searchParameters = new ArrayList<RuntimeSearchParam>();
searchParameters.addAll(searchMethodBinding.getSearchParams());
sortRuntimeSearchParameters(searchParameters);
if (!searchParameters.isEmpty()) {
for (RuntimeSearchParam nextParameter : searchParameters) {
String nextParamName = nextParameter.getName();
// String chain = null;
String nextParamUnchainedName = nextParamName;
if (nextParamName.contains(".")) {
// chain = nextParamName.substring(nextParamName.indexOf('.') + 1);
nextParamUnchainedName = nextParamName.substring(0, nextParamName.indexOf('.'));
}
String nextParamDescription = nextParameter.getDescription();
/*
* If the parameter has no description, default to the one from the resource
/**
* Sets the cache property (default is true). If set to true, the same response will be returned for each
* invocation.
* <p>
* See the class documentation for an important note if you are extending this class
* </p>
*/
if (StringUtils.isBlank(nextParamDescription)) {
RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName);
if (paramDef != null) {
nextParamDescription = paramDef.getDescription();
}
public void setCache(boolean theCache) {
myCache = theCache;
}
RestResourceSearchParam param;
param = resource.addSearchParam();
param.setName(nextParamName);
// if (StringUtils.isNotBlank(chain)) {
// param.addChain(chain);
// }
param.setDocumentation(nextParamDescription);
param.setType(nextParameter.getParamType());
}
}
/**
* Sets the value of the "publisher" that will be placed in the generated conformance statement. As this
* is a mandatory element, the value should not be null (although this is not enforced). The value defaults
* to "Not provided" but may be set to null, which will cause this element to be omitted.
*/
public void setPublisher(String thePublisher) {
myPublisher = thePublisher;
}
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
@ -319,15 +355,4 @@ public class ServerConformanceProvider {
}
});
}
/**
* Sets the cache property (default is true). If set to true, the same response will be returned for each
* invocation.
* <p>
* See the class documentation for an important note if you are extending this class
* </p>
*/
public void setCache(boolean theCache) {
myCache = theCache;
}
}

View File

@ -34,6 +34,7 @@ import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider;
public class ServerConformanceProviderTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProviderTest.class);
private FhirContext myCtx = new FhirContext();
@Test
public void testSearchParameterDocumentation() throws Exception {
@ -59,14 +60,34 @@ public class ServerConformanceProviderTest {
}
assertTrue(found);
Conformance conformance = sc.getServerConformance();
String conf = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
String conf = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
assertThat(conf, containsString("<documentation value=\"The patient's identifier (MRN or other card number)\"/>"));
assertThat(conf, containsString("<type value=\"token\"/>"));
}
@Test
public void testValidateGeneratedStatement() throws Exception {
RestfulServer rs = new RestfulServer();
rs.setProviders(new MultiOptionalProvider());
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
rs.setServerConformanceProvider(sc);
rs.init(null);
Conformance conformance = sc.getServerConformance();
myCtx.newValidator().validate(conformance);
}
@Test
public void testMultiOptionalDocumentation() throws Exception {

View File

@ -18,5 +18,11 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>