Fix #315 - Allow declaring of custom types for specific profiles
This commit is contained in:
parent
5895881fa5
commit
1adfc4b4d9
|
@ -0,0 +1,7 @@
|
|||
package example;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Observation;
|
||||
|
||||
public class CustomObservation extends Observation {
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ import ca.uhn.fhir.model.primitive.DateTimeDt;
|
|||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
public class Extensions {
|
||||
public class ExtensionsDstu2 {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void main(String[] args) throws DataFormatException, IOException {
|
|
@ -0,0 +1,140 @@
|
|||
package example;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.HumanName;
|
||||
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
|
||||
public class ExtensionsDstu3 {
|
||||
|
||||
public void customType() {
|
||||
|
||||
IGenericClient client = FhirContext.forDstu3().newRestfulGenericClient("http://foo");
|
||||
|
||||
//START SNIPPET: customTypeClientSimple
|
||||
// Create an example patient
|
||||
MyPatient custPatient = new MyPatient();
|
||||
custPatient.addName().addFamily("Smith").addGiven("John");
|
||||
custPatient.setPetName(new StringType("Rover")); // populate the extension
|
||||
|
||||
// Create the resource like normal
|
||||
client.create().resource(custPatient).execute();
|
||||
|
||||
// You can also read the resource back like normal
|
||||
custPatient = client.read().resource(MyPatient.class).withId("123").execute();
|
||||
//END SNIPPET: customTypeClientSimple
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void customTypeDeclared() {
|
||||
|
||||
|
||||
//START SNIPPET: customTypeClientDeclared
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
|
||||
// Instruct the context that if it receives a resource which
|
||||
// claims to conform to the given profile (by URL), it should
|
||||
// use the MyPatient type to parse this resource
|
||||
ctx.setDefaultTypeForProfile("http://example.com/StructureDefinition/mypatient", MyPatient.class);
|
||||
|
||||
// You can declare as many default types as you like
|
||||
ctx.setDefaultTypeForProfile("http://foo.com/anotherProfile", CustomObservation.class);
|
||||
|
||||
// Create a client
|
||||
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu3");
|
||||
|
||||
// You can also read the resource back like normal
|
||||
Patient patient = client.read().resource(Patient.class).withId("123").execute();
|
||||
if (patient instanceof MyPatient) {
|
||||
// If the server supplied a resource which declared to conform
|
||||
// to the given profile, MyPatient will have been returned so
|
||||
// process it differently..
|
||||
}
|
||||
|
||||
//END SNIPPET: customTypeClientDeclared
|
||||
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void main(String[] args) throws DataFormatException, IOException {
|
||||
|
||||
|
||||
// START SNIPPET: resourceExtension
|
||||
// Create an example patient
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setUse(IdentifierUse.OFFICIAL).setSystem("urn:example").setValue("7000135");
|
||||
|
||||
// Create an extension
|
||||
Extension ext = new Extension();
|
||||
ext.setUrl("http://example.com/extensions#someext");
|
||||
ext.setValue(new DateTimeType("2011-01-02T11:13:15"));
|
||||
|
||||
// Add the extension to the resource
|
||||
patient.addExtension(ext);
|
||||
//END SNIPPET: resourceExtension
|
||||
|
||||
|
||||
//START SNIPPET: resourceStringExtension
|
||||
// Continuing the example from above, we will add a name to the patient, and then
|
||||
// add an extension to part of that name
|
||||
HumanName name = patient.addName();
|
||||
name.addFamily("Shmoe");
|
||||
|
||||
// Add a new "given name", which is of type String
|
||||
StringType given = name.addGivenElement();
|
||||
given.setValue("Joe");
|
||||
|
||||
// Create an extension and add it to the String
|
||||
Extension givenExt = new Extension("http://examples.com#moreext", new StringType("Hello"));
|
||||
given.addExtension(givenExt);
|
||||
//END SNIPPET: resourceStringExtension
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
String output = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
|
||||
System.out.println(output);
|
||||
|
||||
|
||||
//START SNIPPET: parseExtension
|
||||
// Get all extensions (modifier or not) for a given URL
|
||||
List<Extension> resourceExts = patient.getExtensionsByUrl("http://fooextensions.com#exts");
|
||||
|
||||
// Get all non-modifier extensions regardless of URL
|
||||
List<Extension> nonModExts = patient.getExtension();
|
||||
|
||||
//Get all non-modifier extensions regardless of URL
|
||||
List<Extension> modExts = patient.getModifierExtension();
|
||||
//END SNIPPET: parseExtension
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void foo() {
|
||||
//START SNIPPET: subExtension
|
||||
Patient patient = new Patient();
|
||||
|
||||
// Add an extension (initially with no contents) to the resource
|
||||
Extension parent = new Extension("http://example.com#parent");
|
||||
patient.addExtension(parent);
|
||||
|
||||
// Add two extensions as children to the parent extension
|
||||
Extension child1 = new Extension("http://example.com#childOne", new StringType("value1"));
|
||||
parent.addExtension(child1);
|
||||
|
||||
Extension child2 = new Extension("http://example.com#chilwo", new StringType("value1"));
|
||||
parent.addExtension(child2);
|
||||
//END SNIPPET: subExtension
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -4,13 +4,14 @@ package example;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +26,9 @@ import ca.uhn.fhir.util.ElementUtil;
|
|||
@ResourceDef(name="Patient", profile="http://example.com/StructureDefinition/mypatient")
|
||||
public class MyPatient extends Patient {
|
||||
|
||||
/**
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Each extension is defined in a field. Any valid HAPI Data Type
|
||||
* can be used for the field type. Note that the [name=""] attribute
|
||||
* in the @Child annotation needs to match the name for the bean accessor
|
||||
|
@ -34,7 +37,7 @@ public class MyPatient extends Patient {
|
|||
@Child(name="petName")
|
||||
@Extension(url="http://example.com/dontuse#petname", definedLocally=false, isModifier=false)
|
||||
@Description(shortDefinition="The name of the patient's favourite pet")
|
||||
private StringDt myPetName;
|
||||
private StringType myPetName;
|
||||
|
||||
/**
|
||||
* The second example extension uses a List type to provide
|
||||
|
@ -46,7 +49,7 @@ public class MyPatient extends Patient {
|
|||
@Child(name="importantDates", max=Child.MAX_UNLIMITED)
|
||||
@Extension(url="http://example.com/dontuse#importantDates", definedLocally=false, isModifier=true)
|
||||
@Description(shortDefinition="Some dates of note for this patient")
|
||||
private List<DateTimeDt> myImportantDates;
|
||||
private List<DateTimeType> myImportantDates;
|
||||
|
||||
/**
|
||||
* It is important to override the isEmpty() method, adding a check for any
|
||||
|
@ -67,28 +70,28 @@ public class MyPatient extends Patient {
|
|||
********/
|
||||
|
||||
/** Getter for important dates */
|
||||
public List<DateTimeDt> getImportantDates() {
|
||||
public List<DateTimeType> getImportantDates() {
|
||||
if (myImportantDates==null) {
|
||||
myImportantDates = new ArrayList<DateTimeDt>();
|
||||
myImportantDates = new ArrayList<DateTimeType>();
|
||||
}
|
||||
return myImportantDates;
|
||||
}
|
||||
|
||||
/** Getter for pet name */
|
||||
public StringDt getPetName() {
|
||||
public StringType getPetName() {
|
||||
if (myPetName == null) {
|
||||
myPetName = new StringDt();
|
||||
myPetName = new StringType();
|
||||
}
|
||||
return myPetName;
|
||||
}
|
||||
|
||||
/** Setter for important dates */
|
||||
public void setImportantDates(List<DateTimeDt> theImportantDates) {
|
||||
public void setImportantDates(List<DateTimeType> theImportantDates) {
|
||||
myImportantDates = theImportantDates;
|
||||
}
|
||||
|
||||
/** Setter for pet name */
|
||||
public void setPetName(StringDt thePetName) {
|
||||
public void setPetName(StringType thePetName) {
|
||||
myPetName = thePetName;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import ca.uhn.fhir.parser.IParser;
|
|||
|
||||
public class MyPatientUse {
|
||||
|
||||
@ResourceDef
|
||||
@ResourceDef()
|
||||
public static class MyPatient extends Patient {
|
||||
|
||||
@Child(name="petName")
|
||||
|
|
|
@ -6,22 +6,16 @@
|
|||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/hapi-fhir-base"/>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -5,6 +5,16 @@
|
|||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
|
@ -13,5 +23,7 @@
|
|||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<faceted-project>
|
||||
<installed facet="java" version="1.7"/>
|
||||
</faceted-project>
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.hamcrest.core.StringContains;
|
||||
|
@ -22,7 +23,10 @@ public class MultiVersionJsonParserTest {
|
|||
String str = FhirContext.forDstu2().newJsonParser().encodeResourceToString(p);
|
||||
ourLog.info(str);
|
||||
|
||||
assertThat(str, StringContains.containsString("{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://foo#ext\",\"valueQuantity\":{\"value\":2.2}}],\"identifier\":[{\"system\":\"urn:sys\",\"value\":\"001\"}]}"));
|
||||
assertThat(str, stringContainsInOrder(
|
||||
"{\"resourceType\":\"Patient\"",
|
||||
"\"extension\":[{\"url\":\"http://foo#ext\",\"valueQuantity\":{\"value\":2.2}}]",
|
||||
"\"identifier\":[{\"system\":\"urn:sys\",\"value\":\"001\"}]"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import ca.uhn.fhir.rest.client.IRestfulClientFactory;
|
|||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import ca.uhn.fhir.util.VersionUtil;
|
||||
|
@ -77,7 +78,9 @@ public class FhirContext {
|
|||
|
||||
private static final List<Class<? extends IBaseResource>> EMPTY_LIST = Collections.emptyList();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirContext.class);
|
||||
private AddProfileTagEnum myAddProfileTagWhenEncoding = AddProfileTagEnum.ONLY_FOR_CUSTOM;
|
||||
private volatile Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myClassToElementDefinition = Collections.emptyMap();
|
||||
private Map<String, Class<? extends IBaseResource>> myDefaultTypeForProfile = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
private volatile Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = Collections.emptyMap();
|
||||
private HapiLocalizer myLocalizer = new HapiLocalizer();
|
||||
private volatile Map<String, BaseRuntimeElementDefinition<?>> myNameToElementDefinition = Collections.emptyMap();
|
||||
|
@ -89,7 +92,7 @@ public class FhirContext {
|
|||
private volatile RuntimeChildUndeclaredExtensionDefinition myRuntimeChildUndeclaredExtensionDefinition;
|
||||
private final IFhirVersion myVersion;
|
||||
private Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> myVersionToNameToResourceType = Collections.emptyMap();
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor. In most cases this is the right constructor to use.
|
||||
*/
|
||||
|
@ -144,6 +147,26 @@ public class FhirContext {
|
|||
return getLocalizer().getMessage(FhirContext.class, "unknownResourceName", theResourceName, theVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* When encoding resources, this setting configures the parser to include
|
||||
* an entry in the resource's metadata section which indicates which profile(s) the
|
||||
* resource claims to conform to. The default is {@link AddProfileTagEnum#ONLY_FOR_CUSTOM}.
|
||||
*
|
||||
* @see #setAddProfileTagWhenEncoding(AddProfileTagEnum) for more information
|
||||
*/
|
||||
public AddProfileTagEnum getAddProfileTagWhenEncoding() {
|
||||
return myAddProfileTagWhenEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default resource type for the given profile
|
||||
*
|
||||
* @see #setDefaultTypeForProfile(String, Class)
|
||||
*/
|
||||
public Class<? extends IBaseResource> getDefaultTypeForProfile(String theProfile) {
|
||||
return myDefaultTypeForProfile.get(theProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed
|
||||
* for extending the core library.
|
||||
|
@ -298,14 +321,6 @@ public class FhirContext {
|
|||
return myIdToResourceDefinition.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the restful client factory
|
||||
* @param theRestfulClientFactory
|
||||
*/
|
||||
public void setRestfulClientFactory(IRestfulClientFactory theRestfulClientFactory) {
|
||||
this.myRestfulClientFactory = theRestfulClientFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the restful client factory. If no factory has been set, this will be initialized with
|
||||
* a new ApacheRestfulClientFactory.
|
||||
|
@ -326,6 +341,17 @@ public class FhirContext {
|
|||
return myVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if any default types for specific profiles have been defined
|
||||
* within this context.
|
||||
*
|
||||
* @see #setDefaultTypeForProfile(String, Class)
|
||||
* @see #getDefaultTypeForProfile(String)
|
||||
*/
|
||||
public boolean hasDefaultTypeForProfile() {
|
||||
return !myDefaultTypeForProfile.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be considered experimental and will likely change in future releases
|
||||
* of HAPI. Use with caution!
|
||||
|
@ -472,6 +498,50 @@ public class FhirContext {
|
|||
|
||||
return classToElementDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* When encoding resources, this setting configures the parser to include
|
||||
* an entry in the resource's metadata section which indicates which profile(s) the
|
||||
* resource claims to conform to. The default is {@link AddProfileTagEnum#ONLY_FOR_CUSTOM}.
|
||||
* <p>
|
||||
* This feature is intended for situations where custom resource types are being used,
|
||||
* avoiding the need to manually add profile declarations for these custom types.
|
||||
* </p>
|
||||
* <p>
|
||||
* See <a href="http://jamesagnew.gihhub.io/hapi-fhir/doc_extensions.html">Profiling and Extensions</a>
|
||||
* for more information on using custom types.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this feature automatically adds the profile, but leaves any profile tags
|
||||
* which have been manually added in place as well.
|
||||
* </p>
|
||||
*
|
||||
* @param theAddProfileTagWhenEncoding
|
||||
* The add profile mode (must not be <code>null</code>)
|
||||
*/
|
||||
public void setAddProfileTagWhenEncoding(AddProfileTagEnum theAddProfileTagWhenEncoding) {
|
||||
Validate.notNull(theAddProfileTagWhenEncoding, "theAddProfileTagWhenEncoding must not be null");
|
||||
myAddProfileTagWhenEncoding = theAddProfileTagWhenEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default type which will be used when parsing a resource that is found to be
|
||||
* of the given profile.
|
||||
* <p>
|
||||
* For example, this method is invoked with the profile string of
|
||||
* <code>"http://example.com/some_patient_profile"</code> and the type of <code>MyPatient.class</code>,
|
||||
* if the parser is parsing a resource and finds that it declares that it conforms to that profile,
|
||||
* the <code>MyPatient</code> type will be used unless otherwise specified.
|
||||
* </p>
|
||||
*
|
||||
* @param theProfile The profile string, e.g. <code>"http://example.com/some_patient_profile"</code>. Must not be <code>null</code> or empty.
|
||||
* @param theClass The resource type. Must not be <code>null</code> or empty.
|
||||
*/
|
||||
public void setDefaultTypeForProfile(String theProfile, Class<? extends IBaseResource> theClass) {
|
||||
Validate.notBlank(theProfile, "theProfile must not be null or empty");
|
||||
Validate.notNull(theClass, "theProfile must not be null");
|
||||
myDefaultTypeForProfile.put(theProfile, theClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* This feature is not yet in its final state and should be considered an internal part of HAPI for now - use with
|
||||
|
@ -495,6 +565,14 @@ public class FhirContext {
|
|||
myParserErrorHandler = theParserErrorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the restful client factory
|
||||
* @param theRestfulClientFactory
|
||||
*/
|
||||
public void setRestfulClientFactory(IRestfulClientFactory theRestfulClientFactory) {
|
||||
this.myRestfulClientFactory = theRestfulClientFactory;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "cast" })
|
||||
private List<Class<? extends IElement>> toElementList(Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
if (theResourceTypes == null) {
|
||||
|
@ -508,21 +586,28 @@ public class FhirContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU1}
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU1 DSTU1}
|
||||
*/
|
||||
public static FhirContext forDstu1() {
|
||||
return new FhirContext(FhirVersionEnum.DSTU1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2 DSTU 2}
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2 DSTU2}
|
||||
*/
|
||||
public static FhirContext forDstu2() {
|
||||
return new FhirContext(FhirVersionEnum.DSTU2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU3 DSTU 3}
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2_HL7ORG DSTU2} (using the Reference Implementation Structures)
|
||||
*/
|
||||
public static FhirContext forDstu2Hl7Org() {
|
||||
return new FhirContext(FhirVersionEnum.DSTU2_HL7ORG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU3 DSTU3}
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
@ -530,10 +615,6 @@ public class FhirContext {
|
|||
return new FhirContext(FhirVersionEnum.DSTU3);
|
||||
}
|
||||
|
||||
public static FhirContext forDstu2Hl7Org() {
|
||||
return new FhirContext(FhirVersionEnum.DSTU2_HL7ORG);
|
||||
}
|
||||
|
||||
private static Collection<Class<? extends IBaseResource>> toCollection(Class<? extends IBaseResource> theResourceType) {
|
||||
ArrayList<Class<? extends IBaseResource>> retVal = new ArrayList<Class<? extends IBaseResource>>(1);
|
||||
retVal.add(theResourceType);
|
||||
|
|
|
@ -683,6 +683,14 @@ class ModelScanner {
|
|||
}
|
||||
}
|
||||
|
||||
Class<? extends IBaseResource> builtInType = myNameToResourceType.get(resourceName.toLowerCase());
|
||||
boolean standardType = builtInType != null && builtInType.equals(theClass) == true;
|
||||
if (primaryNameProvider) {
|
||||
if (builtInType != null && builtInType.equals(theClass) == false) {
|
||||
primaryNameProvider = false;
|
||||
}
|
||||
}
|
||||
|
||||
String resourceId = resourceDefinition.id();
|
||||
if (!isBlank(resourceId)) {
|
||||
if (myIdToResourceDefinition.containsKey(resourceId)) {
|
||||
|
@ -691,7 +699,7 @@ class ModelScanner {
|
|||
}
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resourceDef = new RuntimeResourceDefinition(myContext, resourceName, theClass, resourceDefinition, isStandardType(theClass));
|
||||
RuntimeResourceDefinition resourceDef = new RuntimeResourceDefinition(myContext, resourceName, theClass, resourceDefinition, standardType);
|
||||
myClassToElementDefinitions.put(theClass, resourceDef);
|
||||
if (primaryNameProvider) {
|
||||
if (resourceDef.getStructureVersion() == myVersion) {
|
||||
|
|
|
@ -155,10 +155,6 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini
|
|||
return "Bundle".equals(getName());
|
||||
}
|
||||
|
||||
public boolean isStandardProfile() {
|
||||
return myResourceProfile.startsWith("http://hl7.org/fhir/profiles");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||
super.sealAndInitialize(theContext, theClassToElementDefinitions);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -62,6 +64,15 @@ public interface IResource extends ICompositeElement, org.hl7.fhir.instance.mode
|
|||
*/
|
||||
CodeDt getLanguage();
|
||||
|
||||
/**
|
||||
* Returns a view of the {@link #getResourceMetadata() resource metadata} map.
|
||||
* Note that getters from this map return immutable objects, but the <code>addFoo()</code>
|
||||
* and <code>setFoo()</code> methods may be used to modify metadata.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
IBaseMetaType getMeta();
|
||||
|
||||
/**
|
||||
* Returns the metadata map for this object, creating it if neccesary. Metadata entries are used to get/set feed bundle entries, such as the resource version, or the last updated timestamp.
|
||||
* <p>
|
||||
|
@ -72,10 +83,23 @@ public interface IResource extends ICompositeElement, org.hl7.fhir.instance.mode
|
|||
*/
|
||||
ResourceMetadataMap getResourceMetadata();
|
||||
|
||||
/**
|
||||
* Returns a String representing the name of this Resource. This return value is not used for anything by HAPI itself, but is provided as a convenience to developers using the API.
|
||||
*
|
||||
* @return the name of this resource, e.g. "Patient", or "Observation"
|
||||
*/
|
||||
String getResourceName();
|
||||
|
||||
/**
|
||||
* Returns the FHIR version represented by this structure
|
||||
*/
|
||||
@Override
|
||||
public ca.uhn.fhir.context.FhirVersionEnum getStructureFhirVersionEnum();
|
||||
|
||||
/**
|
||||
* Returns the narrative block for this resource
|
||||
*/
|
||||
BaseNarrativeDt getText();
|
||||
BaseNarrativeDt<?> getText();
|
||||
|
||||
/**
|
||||
* Sets the ID of this resource. Note that this identifier is the URL (or a portion of the URL) used to access this resource, and is not the same thing as any business identifiers stored within the
|
||||
|
@ -99,16 +123,4 @@ public interface IResource extends ICompositeElement, org.hl7.fhir.instance.mode
|
|||
*/
|
||||
void setResourceMetadata(ResourceMetadataMap theMap);
|
||||
|
||||
/**
|
||||
* Returns a String representing the name of this Resource. This return value is not used for anything by HAPI itself, but is provided as a convenience to developers using the API.
|
||||
*
|
||||
* @return the name of this resource, e.g. "Patient", or "Observation"
|
||||
*/
|
||||
String getResourceName();
|
||||
|
||||
/**
|
||||
* Returns the FHIR version represented by this structure
|
||||
*/
|
||||
public ca.uhn.fhir.context.FhirVersionEnum getStructureFhirVersionEnum();
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.net.URI;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
|
||||
/**
|
||||
* A single tag
|
||||
|
@ -34,7 +35,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
|
|||
* {@link #getScheme() scheme} and
|
||||
* </p>
|
||||
*/
|
||||
public class Tag extends BaseElement implements IElement {
|
||||
public class Tag extends BaseElement implements IElement, IBaseCoding {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -59,10 +60,6 @@ public class Tag extends BaseElement implements IElement {
|
|||
private String myScheme;
|
||||
private String myTerm;
|
||||
|
||||
/**
|
||||
* @deprecated Tags will become immutable in a future release, so this constructor should not be used.
|
||||
*/
|
||||
@Deprecated
|
||||
public Tag() {
|
||||
}
|
||||
|
||||
|
@ -149,12 +146,7 @@ public class Tag extends BaseElement implements IElement {
|
|||
|
||||
/**
|
||||
* Sets the label and returns a reference to this tag
|
||||
*
|
||||
* @deprecated Tags will become immutable in a future release of HAPI in order to facilitate
|
||||
* ensuring that the TagList acts as an unordered set. Use the constructor to set this field when creating a new
|
||||
* tag object
|
||||
*/
|
||||
@Deprecated
|
||||
public Tag setLabel(String theLabel) {
|
||||
myLabel = theLabel;
|
||||
return this;
|
||||
|
@ -162,12 +154,7 @@ public class Tag extends BaseElement implements IElement {
|
|||
|
||||
/**
|
||||
* Sets the scheme and returns a reference to this tag
|
||||
*
|
||||
* @deprecated Tags will become immutable in a future release of HAPI in order to facilitate
|
||||
* ensuring that the TagList acts as an unordered set. Use the constructor to set this field when creating a new
|
||||
* tag object
|
||||
*/
|
||||
@Deprecated
|
||||
public Tag setScheme(String theScheme) {
|
||||
myScheme = theScheme;
|
||||
return this;
|
||||
|
@ -175,12 +162,7 @@ public class Tag extends BaseElement implements IElement {
|
|||
|
||||
/**
|
||||
* Sets the term and returns a reference to this tag
|
||||
*
|
||||
* @deprecated Tags will become immutable in a future release of HAPI in order to facilitate
|
||||
* ensuring that the TagList acts as an unordered set. Use the constructor to set this field when creating a new
|
||||
* tag object
|
||||
*/
|
||||
@Deprecated
|
||||
public Tag setTerm(String theTerm) {
|
||||
myTerm = theTerm;
|
||||
return this;
|
||||
|
@ -207,4 +189,37 @@ public class Tag extends BaseElement implements IElement {
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return getTerm();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplay() {
|
||||
return getLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSystem() {
|
||||
return getScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding setCode(String theTerm) {
|
||||
setTerm(myTerm);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding setDisplay(String theLabel) {
|
||||
setLabel(theLabel);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding setSystem(String theScheme) {
|
||||
setScheme(theScheme);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,13 +46,17 @@ public @interface ResourceDef {
|
|||
* for the generated profile exported by the server. For example, if you set this value to
|
||||
* "hello" on a custom resource class, your server will automatically export a profile with the
|
||||
* identity: <code>http://localhost:8080/fhir/Profile/hello</code> (the base URL will be whatever
|
||||
* your server uses, not necessarily "http://localhost:8080/fhir")
|
||||
* your server uses, not necessarily "http://localhost:8080/fhir")
|
||||
*/
|
||||
String id() default "";
|
||||
|
||||
/**
|
||||
* The URL indicating the profile for this resource definition. If specified, this URL will be
|
||||
* automatically added to the meta tag when the resource is serialized.
|
||||
* <p>
|
||||
* This URL should be fully qualified to indicate the complete URL of
|
||||
* the profile being used, e.g. <code>http://example.com/fhir/StructureDefiniton/some_profile</code>
|
||||
* </p>
|
||||
*/
|
||||
String profile() default "";
|
||||
|
||||
|
|
|
@ -78,12 +78,14 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
|
||||
|
||||
private IIdType myEncodeForceResourceId;
|
||||
private ContainedResources myContainedResources;
|
||||
private FhirContext myContext;
|
||||
private Set<String> myDontEncodeElements;
|
||||
private boolean myDontEncodeElementsIncludesStars;
|
||||
private Set<String> myEncodeElements;
|
||||
private Set<String> myEncodeElementsAppliesToResourceTypes;
|
||||
private boolean myEncodeElementsIncludesStars;
|
||||
private IIdType myEncodeForceResourceId;
|
||||
private IParserErrorHandler myErrorHandler;
|
||||
private boolean myOmitResourceId;
|
||||
private String myServerBaseUrl;
|
||||
|
@ -91,10 +93,6 @@ public abstract class BaseParser implements IParser {
|
|||
private boolean mySummaryMode;
|
||||
private boolean mySuppressNarratives;
|
||||
|
||||
private Set<String> myDontEncodeElements;
|
||||
|
||||
private boolean myDontEncodeElementsIncludesStars;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -439,6 +437,47 @@ public abstract class BaseParser implements IParser {
|
|||
return tags;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected <T extends IPrimitiveType<String>> List<T> getProfileTagsForEncoding(IBaseResource theResource, List<T> theProfiles) {
|
||||
switch (myContext.getAddProfileTagWhenEncoding()) {
|
||||
case NEVER:
|
||||
return theProfiles;
|
||||
case ONLY_FOR_CUSTOM:
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||
if (resDef.isStandardType()) {
|
||||
return theProfiles;
|
||||
}
|
||||
break;
|
||||
case ALWAYS:
|
||||
break;
|
||||
}
|
||||
|
||||
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
||||
RuntimeResourceDefinition nextDef = myContext.getResourceDefinition(theResource);
|
||||
String profile = nextDef.getResourceProfile(myServerBaseUrl);
|
||||
if (isNotBlank(profile)) {
|
||||
for (T next : theProfiles) {
|
||||
if (profile.equals(next.getValue())) {
|
||||
return theProfiles;
|
||||
}
|
||||
}
|
||||
|
||||
List<T> newList = new ArrayList<T>();
|
||||
newList.addAll(theProfiles);
|
||||
|
||||
BaseRuntimeElementDefinition<?> idElement = myContext.getElementDefinition("id");
|
||||
@SuppressWarnings("unchecked")
|
||||
T newId = (T) idElement.newInstance();
|
||||
newId.setValue(profile);
|
||||
|
||||
newList.add(newId);
|
||||
return newList;
|
||||
}
|
||||
}
|
||||
|
||||
return theProfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>), narratives will not be included in the encoded
|
||||
* values.
|
||||
|
@ -595,6 +634,17 @@ public abstract class BaseParser implements IParser {
|
|||
filterCodingsWithNoCodeOrSystem(metaValue.getTag());
|
||||
filterCodingsWithNoCodeOrSystem(metaValue.getSecurity());
|
||||
|
||||
List<? extends IPrimitiveType<String>> newProfileList = getProfileTagsForEncoding(theResource, metaValue.getProfile());
|
||||
List<? extends IPrimitiveType<String>> oldProfileList = metaValue.getProfile();
|
||||
if (oldProfileList != newProfileList) {
|
||||
oldProfileList.clear();
|
||||
for (IPrimitiveType<String> next : newProfileList) {
|
||||
if (isNotBlank(next.getValue())) {
|
||||
metaValue.addProfile(next.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldAddSubsettedTag()) {
|
||||
IBaseCoding coding = metaValue.addTag();
|
||||
coding.setCode(Constants.TAG_SUBSETTED_CODE);
|
||||
|
@ -748,11 +798,11 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
protected static <T> List<T> extractMetadataListNotNull(IResource resource, ResourceMetadataKeyEnum<List<T>> key) {
|
||||
List<T> securityLabels = key.get(resource);
|
||||
List<? extends T> securityLabels = key.get(resource);
|
||||
if (securityLabels == null) {
|
||||
securityLabels = Collections.emptyList();
|
||||
}
|
||||
return securityLabels;
|
||||
return new ArrayList<T>(securityLabels);
|
||||
}
|
||||
|
||||
static boolean hasExtensions(IBase theElement) {
|
||||
|
|
|
@ -104,7 +104,7 @@ public interface IParser {
|
|||
boolean isOmitResourceId();
|
||||
|
||||
/**
|
||||
* If set to <code>true<code> (which is the default), resource references containing a version
|
||||
* If set to <code>true<code> (which is the default), resource references containing a version
|
||||
* will have the version removed when the resource is encoded. This is generally good behaviour because
|
||||
* in most situations, references from one resource to another should be to the resource by ID, not
|
||||
* by ID and version. In some cases though, it may be desirable to preserve the version in resource
|
||||
|
@ -222,12 +222,13 @@ public interface IParser {
|
|||
* <li><b>Patient</b> - Don't encode patient and all its children</li>
|
||||
* <li><b>Patient.name</b> - Don't encode the patient's name</li>
|
||||
* <li><b>Patient.name.family</b> - Don't encode the patient's family name</li>
|
||||
* <li><b>*.text</b> - Don't encode the text element on any resource (only the very first position may contain a wildcard)</li>
|
||||
* <li><b>*.text</b> - Don't encode the text element on any resource (only the very first position may contain a
|
||||
* wildcard)</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* DSTU2 note: Note that values including meta, such as <code>Patient.meta</code>
|
||||
* will work for DSTU2 parsers, but values with subelements on meta such
|
||||
* as <code>Patient.meta.lastUpdated</code> will only work in
|
||||
* as <code>Patient.meta.lastUpdated</code> will only work in
|
||||
* DSTU3+ mode.
|
||||
* </p>
|
||||
*
|
||||
|
@ -244,7 +245,8 @@ public interface IParser {
|
|||
* <li><b>Patient</b> - Encode patient and all its children</li>
|
||||
* <li><b>Patient.name</b> - Encode only the patient's name</li>
|
||||
* <li><b>Patient.name.family</b> - Encode only the patient's family name</li>
|
||||
* <li><b>*.text</b> - Encode the text element on any resource (only the very first position may contain a wildcard)</li>
|
||||
* <li><b>*.text</b> - Encode the text element on any resource (only the very first position may contain a
|
||||
* wildcard)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param theEncodeElements
|
||||
|
@ -308,7 +310,7 @@ public interface IParser {
|
|||
IParser setServerBaseUrl(String theUrl);
|
||||
|
||||
/**
|
||||
* If set to <code>true<code> (which is the default), resource references containing a version
|
||||
* If set to <code>true<code> (which is the default), resource references containing a version
|
||||
* will have the version removed when the resource is encoded. This is generally good behaviour because
|
||||
* in most situations, references from one resource to another should be to the resource by ID, not
|
||||
* by ID and version. In some cases though, it may be desirable to preserve the version in resource
|
||||
|
@ -316,7 +318,7 @@ public interface IParser {
|
|||
*
|
||||
* @param theStripVersionsFromReferences
|
||||
* Set this to <code>false<code> to prevent the parser from removing
|
||||
* resource versions from references.
|
||||
* resource versions from references.
|
||||
* @return Returns a reference to <code>this</code> parser so that method calls can be chained together
|
||||
*/
|
||||
IParser setStripVersionsFromReferences(boolean theStripVersionsFromReferences);
|
||||
|
|
|
@ -838,7 +838,9 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
// Object securityLabelRawObj =
|
||||
|
||||
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
|
||||
List<IdDt> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
profiles = super.getProfileTagsForEncoding(resource, profiles);
|
||||
|
||||
TagList tags = getMetaTagsForEncoding(resource);
|
||||
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
||||
IdDt resourceId = resource.getId();
|
||||
|
@ -854,7 +856,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
|
||||
if (profiles != null && profiles.isEmpty() == false) {
|
||||
theEventWriter.writeStartArray("profile");
|
||||
for (IdDt profile : profiles) {
|
||||
for (IIdType profile : profiles) {
|
||||
if (profile != null && isNotBlank(profile.getValue())) {
|
||||
theEventWriter.write(profile.getValue());
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.hl7.fhir.instance.model.api.IBaseElement;
|
|||
import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
|
||||
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseXhtml;
|
||||
|
@ -1433,6 +1434,11 @@ class ParserState<T> {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populateTarget() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ContainedResourcesStateHl7Org extends PreResourceState {
|
||||
|
@ -1464,6 +1470,11 @@ class ParserState<T> {
|
|||
def.getChildByName("contained").getMutator().addValue(preResCurrentElement, res);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populateTarget() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class DeclaredExtensionState extends BaseState {
|
||||
|
@ -1969,6 +1980,8 @@ class ParserState<T> {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract void populateTarget();
|
||||
|
||||
public PreResourceState(PreResourceState thePreResourcesState, FhirVersionEnum theParentVersion) {
|
||||
super(thePreResourcesState);
|
||||
Validate.notNull(theParentVersion);
|
||||
|
@ -2045,6 +2058,40 @@ class ParserState<T> {
|
|||
public void wereBack() {
|
||||
final boolean bundle = "Bundle".equals(myContext.getResourceDefinition(myInstance).getName());
|
||||
|
||||
if (myContext.hasDefaultTypeForProfile()) {
|
||||
IBaseMetaType meta = myInstance.getMeta();
|
||||
Class<? extends IBaseResource> wantedProfileType = null;
|
||||
String usedProfile = null;
|
||||
for (IPrimitiveType<String> next : meta.getProfile()) {
|
||||
if (isNotBlank(next.getValue())) {
|
||||
wantedProfileType = myContext.getDefaultTypeForProfile(next.getValue());
|
||||
if (wantedProfileType != null) {
|
||||
usedProfile = next.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wantedProfileType != null && !wantedProfileType.equals(myInstance.getClass())) {
|
||||
if (myResourceType == null || myResourceType.isAssignableFrom(wantedProfileType)) {
|
||||
ourLog.debug("Converting resource of type {} to type defined for profile \"{}\": {}", new Object[] {myInstance.getClass().getName(), usedProfile, wantedProfileType});
|
||||
|
||||
/*
|
||||
* This isn't the most efficient thing really.. If we want a specific
|
||||
* type we just re-parse into that type. The problem is that we don't know
|
||||
* until we've parsed the resource which type we want to use because the
|
||||
* profile declarations are in the text of the resource itself.
|
||||
*
|
||||
* At some point it would be good to write code which can present a view
|
||||
* of one type backed by another type and use that.
|
||||
*/
|
||||
IParser parser = myContext.newJsonParser();
|
||||
String asString = parser.encodeResourceToString(myInstance);
|
||||
myInstance = parser.parseResource(wantedProfileType, asString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FhirTerser terser = myContext.newTerser();
|
||||
terser.visit(myInstance, new IModelVisitor() {
|
||||
|
||||
|
@ -2114,6 +2161,7 @@ class ParserState<T> {
|
|||
|
||||
}
|
||||
|
||||
populateTarget();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2141,14 +2189,19 @@ class ParserState<T> {
|
|||
assert theResourceType == null || IResource.class.isAssignableFrom(theResourceType);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
|
||||
// super.enteringNewElement(theNamespaceUri, theLocalPart);
|
||||
// populateTarget();
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
|
||||
super.enteringNewElement(theNamespaceUri, theLocalPart);
|
||||
protected void populateTarget() {
|
||||
if (myEntry != null) {
|
||||
myEntry.setResource((IResource) getCurrentElement());
|
||||
}
|
||||
if (myMutator != null) {
|
||||
myMutator.addValue(myTarget, getCurrentElement());
|
||||
myMutator.setValue(myTarget, getCurrentElement());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2192,10 +2245,9 @@ class ParserState<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
|
||||
super.enteringNewElement(theNamespaceUri, theLocalPart);
|
||||
protected void populateTarget() {
|
||||
if (myMutator != null) {
|
||||
myMutator.addValue(myTarget, getCurrentElement());
|
||||
myMutator.setValue(myTarget, getCurrentElement());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,16 +132,6 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
} catch (XMLStreamException e1) {
|
||||
throw new DataFormatException(e1);
|
||||
}
|
||||
|
||||
// XMLEventReader streamReader;
|
||||
// try {
|
||||
// streamReader = myXmlInputFactory.createXMLEventReader(theReader);
|
||||
// } catch (XMLStreamException e) {
|
||||
// throw new DataFormatException(e);
|
||||
// } catch (FactoryConfigurationError e) {
|
||||
// throw new ConfigurationException("Failed to initialize STaX event factory", e);
|
||||
// }
|
||||
// return streamReader;
|
||||
}
|
||||
|
||||
private XMLStreamWriter createXmlWriter(Writer theWriter) throws XMLStreamException {
|
||||
|
@ -433,8 +423,6 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
theEventWriter.writeEndElement();
|
||||
}
|
||||
|
||||
String bundleBaseUrl = theBundle.getLinkBase().getValue();
|
||||
|
||||
writeOptionalTagWithValue(theEventWriter, "type", theBundle.getType().getValue());
|
||||
writeOptionalTagWithValue(theEventWriter, "total", theBundle.getTotalResults().getValueAsString());
|
||||
|
||||
|
@ -841,7 +829,9 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
|
||||
}
|
||||
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
|
||||
List<IdDt> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
profiles = super.getProfileTagsForEncoding(resource, profiles);
|
||||
|
||||
TagList tags = getMetaTagsForEncoding((resource));
|
||||
|
||||
if (super.shouldEncodeResourceMeta(resource) && ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) {
|
||||
|
@ -851,7 +841,7 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString());
|
||||
}
|
||||
|
||||
for (IdDt profile : profiles) {
|
||||
for (IIdType profile : profiles) {
|
||||
theEventWriter.writeStartElement("profile");
|
||||
theEventWriter.writeAttribute("value", profile.getValue());
|
||||
theEventWriter.writeEndElement();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -21,9 +23,9 @@ package ca.uhn.fhir.rest.server;
|
|||
*/
|
||||
|
||||
/**
|
||||
* RESTful server behaviour for automatically adding profile tags
|
||||
* RESTful server behaviour for automatically adding profile tags when serializing resources
|
||||
*
|
||||
* @see RestfulServer#setAddProfileTag(AddProfileTagEnum)
|
||||
* @see FhirContext#setAddProfileTagWhenEncoding(AddProfileTagEnum)
|
||||
*/
|
||||
public enum AddProfileTagEnum {
|
||||
/**
|
||||
|
@ -33,7 +35,13 @@ public enum AddProfileTagEnum {
|
|||
|
||||
/**
|
||||
* Add any profile tags that returned resources appear to conform to
|
||||
*
|
||||
* @deprecated This mode causes even FHIR's default profiles to be exported in the
|
||||
* resource metadata section. This is not generally expected behaviour from other
|
||||
* systems and it offers no real benefit, so it will be removed at some point. This
|
||||
* option was deprecated in HAPI 1.5
|
||||
*/
|
||||
@Deprecated
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,7 +48,9 @@ public interface IRestfulServerDefaults {
|
|||
|
||||
/**
|
||||
* @return Returns the setting for automatically adding profile tags
|
||||
* @deprecated As of HAPI FHIR 1.5, this property has been moved to {@link FhirContext#setAddProfileTagWhenEncoding(AddProfileTagEnum)}
|
||||
*/
|
||||
@Deprecated
|
||||
AddProfileTagEnum getAddProfileTag();
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,7 +40,7 @@ public interface IVersionSpecificBundleFactory {
|
|||
|
||||
void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, IPrimitiveType<Date> theLastUpdated);
|
||||
|
||||
void initializeBundleFromBundleProvider(IRestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint,
|
||||
void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint,
|
||||
int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes);
|
||||
|
||||
Bundle getDstu1Bundle();
|
||||
|
|
|
@ -74,6 +74,7 @@ import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
|
|||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.VersionUtil;
|
||||
|
@ -93,7 +94,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
private static final ExceptionHandlingInterceptor DEFAULT_EXCEPTION_HANDLER = new ExceptionHandlingInterceptor();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServer.class);
|
||||
private static final long serialVersionUID = 1L;
|
||||
private AddProfileTagEnum myAddProfileTag;
|
||||
private BundleInclusionRule myBundleInclusionRule = BundleInclusionRule.BASED_ON_INCLUDES;
|
||||
private boolean myDefaultPrettyPrint = false;
|
||||
private EncodingEnum myDefaultResponseEncoding = EncodingEnum.XML;
|
||||
|
@ -369,11 +369,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddProfileTagEnum getAddProfileTag() {
|
||||
return myAddProfileTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BundleInclusionRule getBundleInclusionRule() {
|
||||
return myBundleInclusionRule;
|
||||
|
@ -1117,10 +1112,13 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
*
|
||||
* @param theAddProfileTag
|
||||
* The behaviour enum (must not be null)
|
||||
* @deprecated As of HAPI FHIR 1.5, this property has been moved to {@link FhirContext#setAddProfileTagWhenEncoding(AddProfileTagEnum)}
|
||||
*/
|
||||
@Deprecated
|
||||
@CoverageIgnore
|
||||
public void setAddProfileTag(AddProfileTagEnum theAddProfileTag) {
|
||||
Validate.notNull(theAddProfileTag, "theAddProfileTag must not be null");
|
||||
myAddProfileTag = theAddProfileTag;
|
||||
myFhirContext.setAddProfileTagWhenEncoding(theAddProfileTag);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1394,4 +1392,13 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
return nextString.length() > 0 && (nextString.charAt(0) == '_' || nextString.charAt(0) == '$' || nextString.equals(Constants.URL_TOKEN_METADATA));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated As of HAPI FHIR 1.5, this property has been moved to {@link FhirContext#setAddProfileTagWhenEncoding(AddProfileTagEnum)}
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public AddProfileTagEnum getAddProfileTag() {
|
||||
return myFhirContext.getAddProfileTagWhenEncoding();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.io.IOException;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
@ -49,15 +48,12 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.Tag;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
|
@ -77,36 +73,6 @@ public class RestfulServerUtils {
|
|||
|
||||
private static final HashSet<String> TEXT_ENCODE_ELEMENTS = new HashSet<String>(Arrays.asList("Bundle", "*.text"));
|
||||
|
||||
public static void addProfileToBundleEntry(FhirContext theContext, IBaseResource theResource, String theServerBase) {
|
||||
if (theResource instanceof IResource) {
|
||||
if (theContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
||||
RuntimeResourceDefinition nextDef = theContext.getResourceDefinition(theResource);
|
||||
String profile = nextDef.getResourceProfile(theServerBase);
|
||||
if (isNotBlank(profile)) {
|
||||
List<IdDt> newList = new ArrayList<IdDt>();
|
||||
List<IdDt> existingList = ResourceMetadataKeyEnum.PROFILES.get((IResource) theResource);
|
||||
if (existingList != null) {
|
||||
newList.addAll(existingList);
|
||||
}
|
||||
newList.add(new IdDt(profile));
|
||||
ResourceMetadataKeyEnum.PROFILES.put((IResource) theResource, newList);
|
||||
}
|
||||
} else {
|
||||
TagList tl = ResourceMetadataKeyEnum.TAG_LIST.get((IResource) theResource);
|
||||
if (tl == null) {
|
||||
tl = new TagList();
|
||||
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) theResource, tl);
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition nextDef = theContext.getResourceDefinition(theResource);
|
||||
String profile = nextDef.getResourceProfile(theServerBase);
|
||||
if (isNotBlank(profile)) {
|
||||
tl.add(new Tag(Tag.HL7_ORG_PROFILE_TAG, profile, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void configureResponseParser(RequestDetails theRequestDetails, IParser parser) {
|
||||
// Pretty print
|
||||
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theRequestDetails.getServer(), theRequestDetails);
|
||||
|
@ -608,13 +574,6 @@ public class RestfulServerUtils {
|
|||
}
|
||||
}
|
||||
|
||||
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
|
||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(theResource);
|
||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
|
||||
addProfileToBundleEntry(theServer.getFhirContext(), theResource, serverBase);
|
||||
}
|
||||
}
|
||||
|
||||
String contentType;
|
||||
if (theResource instanceof IBaseBinary && responseEncoding == null) {
|
||||
IBaseBinary bin = (IBaseBinary) theResource;
|
||||
|
|
|
@ -55,8 +55,6 @@ public interface IAnyResource extends IBaseResource {
|
|||
|
||||
IPrimitiveType<String> getLanguageElement();
|
||||
|
||||
IBaseMetaType getMeta();
|
||||
|
||||
public Object getUserData(String name);
|
||||
|
||||
@Override
|
||||
|
|
|
@ -39,6 +39,8 @@ import ca.uhn.fhir.model.api.Include;
|
|||
*/
|
||||
public interface IBaseResource extends IBase, IElement {
|
||||
|
||||
IBaseMetaType getMeta();
|
||||
|
||||
/**
|
||||
* Include constant for <code>*</code> (return all includes)
|
||||
*/
|
||||
|
|
|
@ -32,7 +32,7 @@ package org.hl7.fhir.instance.model.api;
|
|||
* which version of the strctures your application is using.
|
||||
* </p>
|
||||
*/
|
||||
public interface IIdType extends IBase {
|
||||
public interface IIdType extends IPrimitiveType<String> {
|
||||
|
||||
void applyTo(IBaseResource theResource);
|
||||
|
||||
|
|
|
@ -36,5 +36,5 @@
|
|||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package ca.uhn.fhir.model.dstu.resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Structures - DSTU1 (FHIR v0.80)
|
||||
|
@ -23,35 +28,31 @@ package ca.uhn.fhir.model.dstu.resource;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.model.api.BaseElement;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.Tag;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.SearchParamDefinition;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
|
||||
import ca.uhn.fhir.model.dstu.composite.CodingDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
public abstract class BaseResource extends BaseElement implements IResource {
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_language</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" )
|
||||
public static final String SP_RES_LANGUAGE = "_language";
|
||||
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_id</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" )
|
||||
public static final String SP_RES_ID = "_id";
|
||||
|
||||
/**
|
||||
* <b>Fluent Client</b> search parameter constant for <b>_id</b>
|
||||
* <p>
|
||||
|
@ -63,9 +64,24 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
public static final StringClientParam RES_ID = new StringClientParam(BaseResource.SP_RES_ID);
|
||||
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_id</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" )
|
||||
public static final String SP_RES_ID = "_id";
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_language</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" )
|
||||
public static final String SP_RES_LANGUAGE = "_language";
|
||||
|
||||
|
||||
|
||||
@Child(name = "contained", order = 2, min = 0, max = 1)
|
||||
private ContainedDt myContained;
|
||||
|
||||
|
||||
private IdDt myId;
|
||||
|
||||
@Child(name = "language", order = 0, min = 0, max = Child.MAX_UNLIMITED)
|
||||
|
@ -104,6 +120,216 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
return myLanguage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseMetaType getMeta() {
|
||||
return new IBaseMetaType() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public IBaseMetaType addProfile(String theProfile) {
|
||||
ArrayList<IdDt> newTagList = new ArrayList<IdDt>();
|
||||
List<IdDt> existingTagList = ResourceMetadataKeyEnum.PROFILES.get(BaseResource.this);
|
||||
if (existingTagList != null) {
|
||||
newTagList.addAll(existingTagList);
|
||||
}
|
||||
ResourceMetadataKeyEnum.PROFILES.put(BaseResource.this, newTagList);
|
||||
|
||||
IdDt tag = new IdDt(theProfile);
|
||||
newTagList.add(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding addSecurity() {
|
||||
List<BaseCodingDt> tagList = ResourceMetadataKeyEnum.SECURITY_LABELS.get(BaseResource.this);
|
||||
if (tagList == null) {
|
||||
tagList = new ArrayList<BaseCodingDt>();
|
||||
ResourceMetadataKeyEnum.SECURITY_LABELS.put(BaseResource.this, tagList);
|
||||
}
|
||||
CodingDt tag = new CodingDt();
|
||||
tagList.add(tag);
|
||||
return asBaseCoding(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding addTag() {
|
||||
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(BaseResource.this);
|
||||
if (tagList == null) {
|
||||
tagList = new TagList();
|
||||
ResourceMetadataKeyEnum.TAG_LIST.put(BaseResource.this, tagList);
|
||||
}
|
||||
Tag tag = new Tag();
|
||||
tagList.add(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* This view is used because the old DSTU1 BaseCodingDt can't implements IBaseCoding
|
||||
*/
|
||||
private IBaseCoding asBaseCoding(final BaseCodingDt theCoding) {
|
||||
return new IBaseCoding() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return theCoding.getCodeElement().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplay() {
|
||||
return theCoding.getDisplayElement().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFormatCommentsPost() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFormatCommentsPre() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSystem() {
|
||||
return theCoding.getSystemElement().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFormatComment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return ElementUtil.isEmpty(getSystem(), getCode(), getDisplay());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding setCode(String theTerm) {
|
||||
theCoding.setCode(theTerm);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding setDisplay(String theLabel) {
|
||||
theCoding.setDisplay(theLabel);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding setSystem(String theScheme) {
|
||||
theCoding.setSystem(theScheme);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFormatCommentsPost() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFormatCommentsPre() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastUpdated() {
|
||||
InstantDt lu = ResourceMetadataKeyEnum.UPDATED.get(BaseResource.this);
|
||||
if (lu != null) {
|
||||
return lu.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IPrimitiveType<String>> getProfile() {
|
||||
ArrayList<IPrimitiveType<String>> retVal = new ArrayList<IPrimitiveType<String>>();
|
||||
List<IdDt> profilesList = ResourceMetadataKeyEnum.PROFILES.get(BaseResource.this);
|
||||
if (profilesList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (IdDt next : profilesList) {
|
||||
retVal.add(next);
|
||||
}
|
||||
return Collections.unmodifiableList(retVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IBaseCoding> getSecurity() {
|
||||
ArrayList<IBaseCoding> retVal = new ArrayList<IBaseCoding>();
|
||||
List<BaseCodingDt> labelsList = ResourceMetadataKeyEnum.SECURITY_LABELS.get(BaseResource.this);
|
||||
if (labelsList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (BaseCodingDt next : labelsList) {
|
||||
retVal.add(asBaseCoding(next));
|
||||
}
|
||||
return Collections.unmodifiableList(retVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding getSecurity(String theSystem, String theCode) {
|
||||
for (BaseCodingDt next : ResourceMetadataKeyEnum.SECURITY_LABELS.get(BaseResource.this)) {
|
||||
if (theSystem.equals(next.getSystemElement().getValue()) && theCode.equals(next.getCodeElement().getValue())) {
|
||||
return asBaseCoding(next);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IBaseCoding> getTag() {
|
||||
ArrayList<IBaseCoding> retVal = new ArrayList<IBaseCoding>();
|
||||
for (Tag next : ResourceMetadataKeyEnum.TAG_LIST.get(BaseResource.this)) {
|
||||
retVal.add(next);
|
||||
}
|
||||
return Collections.unmodifiableList(retVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding getTag(String theSystem, final String theCode) {
|
||||
for (final Tag next : ResourceMetadataKeyEnum.TAG_LIST.get(BaseResource.this)) {
|
||||
if (next.getScheme().equals(theSystem) && next.getTerm().equals(theCode)) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionId() {
|
||||
return getId().getVersionIdPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFormatComment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return getResourceMetadata().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseMetaType setLastUpdated(Date theHeaderDateValue) {
|
||||
ResourceMetadataKeyEnum.UPDATED.put(BaseResource.this, new InstantDt(theHeaderDateValue));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBaseMetaType setVersionId(String theVersionId) {
|
||||
setId(getId().withVersion(theVersionId));
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceMetadataMap getResourceMetadata() {
|
||||
if (myResourceMetadata == null) {
|
||||
|
@ -120,10 +346,23 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
return myText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
|
||||
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isBaseEmpty() {
|
||||
return super.isBaseEmpty() && ElementUtil.isEmpty(myLanguage, myText, myId);
|
||||
}
|
||||
|
||||
public void setContained(ContainedDt theContained) {
|
||||
myContained = theContained;
|
||||
}
|
||||
|
||||
public void setId(IdDt theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
public BaseResource setId(IIdType theId) {
|
||||
if (theId instanceof IdDt) {
|
||||
myId = (IdDt) theId;
|
||||
|
@ -133,10 +372,6 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
return this;
|
||||
}
|
||||
|
||||
public void setId(IdDt theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
public BaseResource setId(String theId) {
|
||||
if (theId == null) {
|
||||
myId = null;
|
||||
|
@ -168,13 +403,4 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
|
||||
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isBaseEmpty() {
|
||||
return super.isBaseEmpty() && ElementUtil.isEmpty(myLanguage, myText, myId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ package ca.uhn.fhir.rest.server;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
@ -29,7 +28,6 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -43,6 +41,8 @@ import ca.uhn.fhir.model.api.BundleEntry;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.Tag;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
|
@ -53,7 +53,6 @@ import ca.uhn.fhir.util.ResourceReferenceInfo;
|
|||
|
||||
public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Dstu1BundleFactory.class);
|
||||
private Bundle myBundle;
|
||||
private FhirContext myContext;
|
||||
|
||||
|
@ -186,7 +185,7 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
boolean thePrettyPrint, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
||||
int numToReturn;
|
||||
String searchId = null;
|
||||
|
@ -224,17 +223,12 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
throw new InternalErrorException("Server method returned resource of type[" + next.getClass().getSimpleName() + "] with no ID specified (IResource#setId(IdDt) must be called)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
|
||||
for (IBaseResource nextRes : resourceList) {
|
||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
|
||||
RestfulServerUtils.addProfileToBundleEntry(theServer.getFhirContext(), nextRes, theServerBase);
|
||||
}
|
||||
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
|
||||
addProfileIfNeeded(theServer, theServerBase, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
||||
|
||||
|
@ -256,6 +250,23 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
}
|
||||
|
||||
private void addProfileIfNeeded(IRestfulServer<?> theServer, String theServerBase, IBaseResource nextRes) {
|
||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardType()) {
|
||||
TagList tl = ResourceMetadataKeyEnum.TAG_LIST.get((IResource) nextRes);
|
||||
if (tl == null) {
|
||||
tl = new TagList();
|
||||
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) nextRes, tl);
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition nextDef = myContext.getResourceDefinition(nextRes);
|
||||
String profile = nextDef.getResourceProfile(theServerBase);
|
||||
if (isNotBlank(profile)) {
|
||||
tl.add(new Tag(Tag.HL7_ORG_PROFILE_TAG, profile, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults,
|
||||
BundleTypeEnum theBundleType) {
|
||||
|
|
|
@ -214,9 +214,6 @@ public class CustomTypeTest {
|
|||
|
||||
private static boolean ourReturnExtended = false;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Search
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.List;
|
|||
import javax.servlet.ServletException;
|
||||
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.Test;
|
||||
|
@ -299,6 +300,12 @@ public class ServerInvalidDefinitionTest {
|
|||
public List<String> getFormatCommentsPost() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseMetaType getMeta() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}.getClass();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package ca.uhn.fhir.model.dstu2.resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
|
||||
|
@ -23,35 +28,31 @@ package ca.uhn.fhir.model.dstu2.resource;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.model.api.BaseElement;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.Tag;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.SearchParamDefinition;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.ContainedDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.NarrativeDt;
|
||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
public abstract class BaseResource extends BaseElement implements IResource {
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_language</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" )
|
||||
public static final String SP_RES_LANGUAGE = "_language";
|
||||
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_id</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" )
|
||||
public static final String SP_RES_ID = "_id";
|
||||
|
||||
/**
|
||||
* <b>Fluent Client</b> search parameter constant for <b>_id</b>
|
||||
* <p>
|
||||
|
@ -61,11 +62,24 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
* </p>
|
||||
*/
|
||||
public static final StringClientParam RES_ID = new StringClientParam(BaseResource.SP_RES_ID);
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_id</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" )
|
||||
public static final String SP_RES_ID = "_id";
|
||||
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_language</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" )
|
||||
public static final String SP_RES_LANGUAGE = "_language";
|
||||
|
||||
@Child(name = "contained", order = 2, min = 0, max = 1)
|
||||
private ContainedDt myContained;
|
||||
|
||||
|
||||
private IdDt myId;
|
||||
|
||||
@Child(name = "language", order = 0, min = 0, max = Child.MAX_UNLIMITED)
|
||||
|
@ -104,6 +118,157 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
return myLanguage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseMetaType getMeta() {
|
||||
return new IBaseMetaType() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public IBaseMetaType addProfile(String theProfile) {
|
||||
ArrayList<IdDt> newTagList = new ArrayList<IdDt>();
|
||||
List<IdDt> existingTagList = ResourceMetadataKeyEnum.PROFILES.get(BaseResource.this);
|
||||
if (existingTagList != null) {
|
||||
newTagList.addAll(existingTagList);
|
||||
}
|
||||
ResourceMetadataKeyEnum.PROFILES.put(BaseResource.this, newTagList);
|
||||
|
||||
IdDt tag = new IdDt(theProfile);
|
||||
newTagList.add(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding addSecurity() {
|
||||
List<BaseCodingDt> tagList = ResourceMetadataKeyEnum.SECURITY_LABELS.get(BaseResource.this);
|
||||
if (tagList == null) {
|
||||
tagList = new ArrayList<BaseCodingDt>();
|
||||
ResourceMetadataKeyEnum.SECURITY_LABELS.put(BaseResource.this, tagList);
|
||||
}
|
||||
CodingDt tag = new CodingDt();
|
||||
tagList.add(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding addTag() {
|
||||
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(BaseResource.this);
|
||||
if (tagList == null) {
|
||||
tagList = new TagList();
|
||||
ResourceMetadataKeyEnum.TAG_LIST.put(BaseResource.this, tagList);
|
||||
}
|
||||
Tag tag = new Tag();
|
||||
tagList.add(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFormatCommentsPost() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFormatCommentsPre() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastUpdated() {
|
||||
InstantDt lu = ResourceMetadataKeyEnum.UPDATED.get(BaseResource.this);
|
||||
if (lu != null) {
|
||||
return lu.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IPrimitiveType<String>> getProfile() {
|
||||
ArrayList<IPrimitiveType<String>> retVal = new ArrayList<IPrimitiveType<String>>();
|
||||
List<IdDt> profilesList = ResourceMetadataKeyEnum.PROFILES.get(BaseResource.this);
|
||||
if (profilesList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (IdDt next : profilesList) {
|
||||
retVal.add(next);
|
||||
}
|
||||
return Collections.unmodifiableList(retVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IBaseCoding> getSecurity() {
|
||||
ArrayList<CodingDt> retVal = new ArrayList<CodingDt>();
|
||||
List<BaseCodingDt> labelsList = ResourceMetadataKeyEnum.SECURITY_LABELS.get(BaseResource.this);
|
||||
if (labelsList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (BaseCodingDt next : labelsList) {
|
||||
retVal.add(new CodingDt(next.getSystemElement().getValue(), next.getCodeElement().getValue()).setDisplay(next.getDisplayElement().getValue()));
|
||||
}
|
||||
return Collections.unmodifiableList(retVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding getSecurity(String theSystem, String theCode) {
|
||||
for (IBaseCoding next : getSecurity()) {
|
||||
if (theSystem.equals(next.getSystem()) && theCode.equals(next.getCode())) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IBaseCoding> getTag() {
|
||||
ArrayList<IBaseCoding> retVal = new ArrayList<IBaseCoding>();
|
||||
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(BaseResource.this);
|
||||
if (tagList == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (Tag next : tagList) {
|
||||
retVal.add(next);
|
||||
}
|
||||
return Collections.unmodifiableList(retVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding getTag(String theSystem, String theCode) {
|
||||
for (IBaseCoding next : getTag()) {
|
||||
if (next.getSystem().equals(theSystem) && next.getCode().equals(theCode)) {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionId() {
|
||||
return getId().getVersionIdPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFormatComment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return getResourceMetadata().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseMetaType setLastUpdated(Date theHeaderDateValue) {
|
||||
ResourceMetadataKeyEnum.UPDATED.put(BaseResource.this, new InstantDt(theHeaderDateValue));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseMetaType setVersionId(String theVersionId) {
|
||||
setId(getId().withVersion(theVersionId));
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceMetadataMap getResourceMetadata() {
|
||||
if (myResourceMetadata == null) {
|
||||
|
@ -120,14 +285,23 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
return myText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
|
||||
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isBaseEmpty() {
|
||||
return super.isBaseEmpty() && ElementUtil.isEmpty(myLanguage, myText, myId);
|
||||
}
|
||||
|
||||
public void setContained(ContainedDt theContained) {
|
||||
myContained = theContained;
|
||||
}
|
||||
|
||||
|
||||
public void setId(IdDt theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
|
||||
public BaseResource setId(IIdType theId) {
|
||||
if (theId instanceof IdDt) {
|
||||
myId = (IdDt) theId;
|
||||
|
@ -168,13 +342,4 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
|
||||
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isBaseEmpty() {
|
||||
return super.isBaseEmpty() && ElementUtil.isEmpty(myLanguage, myText, myId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
|
@ -51,7 +50,6 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.rest.server.BundleInclusionRule;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
@ -65,7 +63,6 @@ import ca.uhn.fhir.util.ResourceReferenceInfo;
|
|||
|
||||
public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Dstu2BundleFactory.class);
|
||||
private Bundle myBundle;
|
||||
private FhirContext myContext;
|
||||
private String myBase;
|
||||
|
@ -302,7 +299,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
boolean thePrettyPrint, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
||||
myBase = theServerBase;
|
||||
|
||||
|
@ -352,15 +349,6 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
}
|
||||
|
||||
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
|
||||
for (IBaseResource nextRes : resourceList) {
|
||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
|
||||
RestfulServerUtils.addProfileToBundleEntry(theServer.getFhirContext(), nextRes, theServerBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
||||
|
||||
|
|
|
@ -0,0 +1,510 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
public class CustomTypeDstu2Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeDstu2Test.class);
|
||||
private static final FhirContext ourCtx = FhirContext.forDstu2();
|
||||
|
||||
@Test
|
||||
public void testAccessEmptyMetaLists() {
|
||||
Patient p = new Patient();
|
||||
assertThat(p.getMeta().getProfile(), empty());
|
||||
assertThat(p.getMeta().getFormatCommentsPost(), empty());
|
||||
assertThat(p.getMeta().getFormatCommentsPre(), empty());
|
||||
assertThat(p.getMeta().getLastUpdated(), nullValue());
|
||||
assertThat(p.getMeta().getSecurity(), empty());
|
||||
assertThat(p.getMeta().getSecurity("foo", "bar"), nullValue());
|
||||
assertThat(p.getMeta().getTag(), empty());
|
||||
assertThat(p.getMeta().getTag("foo", "bar"), nullValue());
|
||||
assertThat(p.getMeta().getVersionId(), nullValue());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeCompleteMetaLists() {
|
||||
Patient p = new Patient();
|
||||
p.getMeta().addProfile("http://foo/profile1");
|
||||
p.getMeta().addProfile("http://foo/profile2");
|
||||
p.getMeta().addSecurity().setSystem("SEC_S1").setCode("SEC_C1").setDisplay("SED_D1");
|
||||
p.getMeta().addSecurity().setSystem("SEC_S2").setCode("SEC_C2").setDisplay("SED_D2");
|
||||
p.getMeta().addTag().setSystem("TAG_S1").setCode("TAG_C1").setDisplay("TAG_D1");
|
||||
p.getMeta().addTag().setSystem("TAG_S2").setCode("TAG_C2").setDisplay("TAG_D2");
|
||||
|
||||
String out = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(out);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(out, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://foo/profile1\"/>",
|
||||
"<profile value=\"http://foo/profile2\"/>",
|
||||
"<security>",
|
||||
"<system value=\"SEC_S1\"/>",
|
||||
"<code value=\"SEC_C1\"/>",
|
||||
"<display value=\"SED_D1\"/>",
|
||||
"</security>",
|
||||
"<security>",
|
||||
"<system value=\"SEC_S2\"/>",
|
||||
"<code value=\"SEC_C2\"/>",
|
||||
"<display value=\"SED_D2\"/>",
|
||||
"</security>",
|
||||
"<tag>",
|
||||
"<system value=\"TAG_S1\"/>",
|
||||
"<display value=\"TAG_D1\"/>",
|
||||
"</tag>",
|
||||
"<tag>",
|
||||
"<system value=\"TAG_S2\"/>",
|
||||
"<display value=\"TAG_D2\"/>",
|
||||
"</tag>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeWithCustomType() {
|
||||
|
||||
MyCustomPatient patient = new MyCustomPatient();
|
||||
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("1234");
|
||||
patient.addName().addFamily("Rossi").addGiven("Mario");
|
||||
patient.setInsulinLevel(new QuantityDt());
|
||||
patient.setGlucoseLevel(new QuantityDt());
|
||||
patient.setHbA1c(new QuantityDt());
|
||||
patient.setBloodPressure(new QuantityDt());
|
||||
patient.setCholesterol(new QuantityDt());
|
||||
patient.setWeight(new StringDt("80 kg"));
|
||||
patient.setWeight(new StringDt("185 cm"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeDt>());
|
||||
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
|
||||
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
|
||||
ourLog.info(messageString);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, not(stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"", "/>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>")));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeWithCustomTypeAndAutoInsertedProfile() {
|
||||
|
||||
MyCustomPatient patient = new MyCustomPatient();
|
||||
|
||||
patient.getMeta().addProfile("http://example.com/foo");
|
||||
patient.getMeta().addProfile("http://example.com/bar");
|
||||
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("1234");
|
||||
patient.addName().addFamily("Rossi").addGiven("Mario");
|
||||
patient.setInsulinLevel(new QuantityDt());
|
||||
patient.setGlucoseLevel(new QuantityDt());
|
||||
patient.setHbA1c(new QuantityDt());
|
||||
patient.setBloodPressure(new QuantityDt());
|
||||
patient.setCholesterol(new QuantityDt());
|
||||
patient.setWeight(new StringDt("80 kg"));
|
||||
patient.setWeight(new StringDt("185 cm"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeDt>());
|
||||
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
|
||||
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
|
||||
ourLog.info(messageString);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"<profile value=\"http://example.com/bar\"/>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, not(stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"", "/>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>")));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeNormalType() {
|
||||
|
||||
Patient patient = new Patient();
|
||||
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("1234");
|
||||
patient.addName().addFamily("Rossi").addGiven("Mario");
|
||||
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
ourLog.info(messageString);
|
||||
|
||||
assertThat(messageString, not(containsString("<profile")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourceWithNoDirective() {
|
||||
String input = createResource(true);
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu2();
|
||||
Patient parsed = (Patient) ctx.newXmlParser().parseResource(input);
|
||||
assertEquals(1, parsed.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
|
||||
|
||||
List<ExtensionDt> exts = parsed.getUndeclaredExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(1, exts.size());
|
||||
assertEquals("185 cm", ((StringDt)exts.get(0).getValueAsPrimitive()).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourceWithDirective() {
|
||||
String input = createResource(true);
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu2();
|
||||
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
|
||||
|
||||
MyCustomPatient parsed = (MyCustomPatient) ctx.newXmlParser().parseResource(input);
|
||||
assertEquals(1, parsed.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
|
||||
|
||||
List<ExtensionDt> exts = parsed.getUndeclaredExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(0, exts.size());
|
||||
|
||||
assertEquals("185 cm", parsed.getWeight().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseBundleWithResourceDirective() {
|
||||
|
||||
String input = createBundle(createResource(false), createResource(true));
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu2();
|
||||
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
|
||||
|
||||
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, input);
|
||||
|
||||
Patient res0 = (Patient) bundle.getEntry().get(0).getResource();
|
||||
assertEquals(0, res0.getMeta().getProfile().size());
|
||||
List<ExtensionDt> exts = res0.getUndeclaredExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(1, exts.size());
|
||||
assertEquals("185 cm", ((StringDt)exts.get(0).getValueAsPrimitive()).getValue());
|
||||
|
||||
MyCustomPatient res1 = (MyCustomPatient) bundle.getEntry().get(1).getResource();
|
||||
assertEquals(1, res1.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", res1.getMeta().getProfile().get(0).getValue());
|
||||
exts = res1.getUndeclaredExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(0, exts.size());
|
||||
assertEquals("185 cm", res1.getWeight().getValue());
|
||||
}
|
||||
|
||||
private String createBundle(String... theResources) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<Bundle xmlns=\"http://hl7.org/fhir\">\n");
|
||||
for (String next : theResources) {
|
||||
b.append(" <entry>\n");
|
||||
b.append(" <resource>\n");
|
||||
b.append(next);
|
||||
b.append(" </resource>\n");
|
||||
b.append(" </entry>\n");
|
||||
}
|
||||
b.append("</Bundle>");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private String createResource(boolean theWithProfile) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<Patient xmlns=\"http://hl7.org/fhir\">\n");
|
||||
if (theWithProfile) {
|
||||
b.append(" <meta>\n");
|
||||
b.append(" <profile value=\"http://example.com/foo\"/>\n");
|
||||
b.append(" </meta>\n");
|
||||
}
|
||||
b.append(" <extension url=\"http://example.com/BloodPressure\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"110\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmHg\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
|
||||
b.append(" <valueDateTime value=\"2010-01-02\"/>\n");
|
||||
b.append(" </modifierExtension>\n");
|
||||
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
|
||||
b.append(" <valueDateTime value=\"2014-01-26T11:11:11\"/>\n");
|
||||
b.append(" </modifierExtension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Cholesterol\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"2\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmol/l\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Glucose\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"95\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mg/dl\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/HbA1c\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"48\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmol/mol\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Insuline\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"125\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"pmol/l\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Weight\">\n");
|
||||
b.append(" <valueString value=\"185 cm\"/>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <identifier>\n");
|
||||
b.append(" <system value=\"urn:system\"/>\n");
|
||||
b.append(" <value value=\"1234\"/>\n");
|
||||
b.append(" </identifier>\n");
|
||||
b.append(" <name>\n");
|
||||
b.append(" <family value=\"Rossi\"/>\n");
|
||||
b.append(" <given value=\"Mario\"/>\n");
|
||||
b.append(" </name>\n");
|
||||
b.append("</Patient>");
|
||||
String input =
|
||||
b.toString();
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
@ResourceDef(name = "Patient", profile = "http://example.com/foo")
|
||||
public static class MyCustomPatient extends Patient {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Child(name = "bloodPressure") // once every 3 month. The average target is 130/80 mmHg or less
|
||||
@Extension(url = "http://example.com/BloodPressure", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's blood pressure")
|
||||
private QuantityDt myBloodPressure;
|
||||
|
||||
// Dates of periodic tests
|
||||
@Child(name = "CheckDates", max = Child.MAX_UNLIMITED)
|
||||
@Extension(url = "http://example.com/diabetes2", definedLocally = false, isModifier = true)
|
||||
@Description(shortDefinition = "Dates of periodic tests")
|
||||
private List<DateTimeDt> myCheckDates;
|
||||
|
||||
@Child(name = "cholesterol") // once a year. The target is triglycerides =< 2 mmol/l e cholesterol =< 4 mmol/l
|
||||
@Extension(url = "http://example.com/Cholesterol", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's cholesterol")
|
||||
private QuantityDt myCholesterol;
|
||||
|
||||
@Child(name = "glucoseLevel") // fingerprick test
|
||||
@Extension(url = "http://example.com/Glucose", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's blood glucose")
|
||||
private QuantityDt myGlucoseLevel;
|
||||
|
||||
// Periodic Tests
|
||||
@Child(name = "hbA1c") // once every 6 month. The average target is 53 mmol/mol (or 7%) or less.
|
||||
@Extension(url = "http://example.com/HbA1c", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's glucose")
|
||||
private QuantityDt myHbA1c;
|
||||
|
||||
@Child(name = "Height")
|
||||
@Extension(url = "http://example.com/Height", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The patient's height in cm")
|
||||
private StringDt myHeight;
|
||||
|
||||
@Child(name = "insulinLevel") // Normal range is [43,208] pmol/l
|
||||
@Extension(url = "http://example.com/Insuline", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's insulin")
|
||||
private QuantityDt myInsulinLevel;
|
||||
|
||||
// Other parameters
|
||||
@Child(name = "weight")
|
||||
@Extension(url = "http://example.com/Weight", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The patient's weight in Kg")
|
||||
private StringDt myWeight;
|
||||
|
||||
public QuantityDt Cholesterol() {
|
||||
if (myCholesterol == null) {
|
||||
myCholesterol = new QuantityDt();
|
||||
}
|
||||
myCholesterol.getValue();
|
||||
myCholesterol.getSystem();
|
||||
myCholesterol.getCode();
|
||||
|
||||
return myCholesterol;
|
||||
}
|
||||
|
||||
public QuantityDt getBloodPressure() {
|
||||
if (myBloodPressure == null) {
|
||||
myBloodPressure = new QuantityDt();
|
||||
}
|
||||
myBloodPressure.getValue();
|
||||
myBloodPressure.getSystem();
|
||||
myBloodPressure.getCode();
|
||||
|
||||
return myBloodPressure;
|
||||
}
|
||||
|
||||
public List<DateTimeDt> getCheckDates() {
|
||||
if (myCheckDates == null) {
|
||||
myCheckDates = new ArrayList<DateTimeDt>();
|
||||
}
|
||||
return myCheckDates;
|
||||
}
|
||||
|
||||
public QuantityDt getGlucoseLevel() {
|
||||
if (myGlucoseLevel == null) {
|
||||
myGlucoseLevel = new QuantityDt();
|
||||
}
|
||||
myGlucoseLevel.getValue();
|
||||
myGlucoseLevel.getSystem();
|
||||
myGlucoseLevel.getCode();
|
||||
|
||||
return myGlucoseLevel;
|
||||
}
|
||||
|
||||
public QuantityDt getHbA1c() {
|
||||
if (myHbA1c == null) {
|
||||
myHbA1c = new QuantityDt();
|
||||
}
|
||||
myHbA1c.getValue();
|
||||
myHbA1c.getSystem();
|
||||
myHbA1c.getCode();
|
||||
|
||||
return myHbA1c;
|
||||
}
|
||||
|
||||
public StringDt getHeight() {
|
||||
if (myHeight == null) {
|
||||
myHeight = new StringDt();
|
||||
}
|
||||
return myHeight;
|
||||
}
|
||||
|
||||
public QuantityDt getInsulinLevel() {
|
||||
if (myInsulinLevel == null) {
|
||||
myInsulinLevel = new QuantityDt();
|
||||
}
|
||||
myInsulinLevel.getValue();
|
||||
myInsulinLevel.getSystem();
|
||||
myInsulinLevel.getCode();
|
||||
|
||||
return myInsulinLevel;
|
||||
}
|
||||
|
||||
public StringDt getWeight() {
|
||||
if (myWeight == null) {
|
||||
myWeight = new StringDt();
|
||||
}
|
||||
return myWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return super.isEmpty() && ElementUtil.isEmpty(myInsulinLevel, myGlucoseLevel, myHbA1c, myBloodPressure, myCholesterol, myWeight, myHeight, myCheckDates);
|
||||
}
|
||||
|
||||
public void setBloodPressure(QuantityDt bloodPressure) {
|
||||
myBloodPressure = bloodPressure;
|
||||
myBloodPressure.setValue(110);
|
||||
myBloodPressure.setSystem("http://unitsofmeasure.org");
|
||||
myBloodPressure.setCode("mmHg");
|
||||
}
|
||||
|
||||
public void setCheckDates(List<DateTimeDt> theCheckDates) {
|
||||
myCheckDates = theCheckDates;
|
||||
myCheckDates.add(new DateTimeDt("2010-01-02"));
|
||||
}
|
||||
|
||||
public void setCholesterol(QuantityDt cholesterol) {
|
||||
myCholesterol = cholesterol;
|
||||
myCholesterol.setValue(2);
|
||||
myCholesterol.setSystem("http://unitsofmeasure.org");
|
||||
myCholesterol.setCode("mmol/l");
|
||||
}
|
||||
|
||||
public void setGlucoseLevel(QuantityDt glucoseLevel) {
|
||||
myGlucoseLevel = glucoseLevel;
|
||||
myGlucoseLevel.setValue(95);
|
||||
myGlucoseLevel.setSystem("http://unitsofmeasure.org");
|
||||
myGlucoseLevel.setCode("mg/dl");
|
||||
}
|
||||
|
||||
public void setHbA1c(QuantityDt hba1c) {
|
||||
myHbA1c = hba1c;
|
||||
myHbA1c.setValue(48);
|
||||
myHbA1c.setSystem("http://unitsofmeasure.org");
|
||||
myHbA1c.setCode("mmol/mol");
|
||||
}
|
||||
|
||||
public void setHeight(StringDt height) {
|
||||
myHeight = height;
|
||||
}
|
||||
|
||||
// Setter/Getter methods
|
||||
public void setInsulinLevel(QuantityDt insulinLevel) {
|
||||
myInsulinLevel = insulinLevel;
|
||||
myInsulinLevel.setValue(125);
|
||||
myInsulinLevel.setSystem("http://unitsofmeasure.org");
|
||||
myInsulinLevel.setCode("pmol/l");
|
||||
}
|
||||
|
||||
public void setWeight(StringDt weight) {
|
||||
myWeight = weight;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
public class CustomTypeTest {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeTest.class);
|
||||
|
||||
@Test
|
||||
public void testEncode() {
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu2();
|
||||
|
||||
MyCustomPatient patient = new MyCustomPatient();
|
||||
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("1234");
|
||||
patient.addName().addFamily("Rossi").addGiven("Mario");
|
||||
patient.setInsulinLevel(new QuantityDt());
|
||||
patient.setGlucoseLevel(new QuantityDt());
|
||||
patient.setHbA1c(new QuantityDt());
|
||||
patient.setBloodPressure(new QuantityDt());
|
||||
patient.setCholesterol(new QuantityDt());
|
||||
patient.setWeight(new StringDt("80 kg"));
|
||||
patient.setWeight(new StringDt("185 cm"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeDt>());
|
||||
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
|
||||
|
||||
IParser p = ctx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
|
||||
ourLog.info(messageString);
|
||||
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient")
|
||||
public static class MyCustomPatient extends Patient {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Child(name = "bloodPressure") // once every 3 month. The average target is 130/80 mmHg or less
|
||||
@Extension(url = "http://example.com/BloodPressure", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's blood pressure")
|
||||
private QuantityDt myBloodPressure;
|
||||
|
||||
// Dates of periodic tests
|
||||
@Child(name = "CheckDates", max = Child.MAX_UNLIMITED)
|
||||
@Extension(url = "http://example.com/diabetes2", definedLocally = false, isModifier = true)
|
||||
@Description(shortDefinition = "Dates of periodic tests")
|
||||
private List<DateTimeDt> myCheckDates;
|
||||
|
||||
@Child(name = "cholesterol") // once a year. The target is triglycerides =< 2 mmol/l e cholesterol =< 4 mmol/l
|
||||
@Extension(url = "http://example.com/Cholesterol", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's cholesterol")
|
||||
private QuantityDt myCholesterol;
|
||||
|
||||
@Child(name = "glucoseLevel") // fingerprick test
|
||||
@Extension(url = "http://example.com/Glucose", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's blood glucose")
|
||||
private QuantityDt myGlucoseLevel;
|
||||
|
||||
// Periodic Tests
|
||||
@Child(name = "hbA1c") // once every 6 month. The average target is 53 mmol/mol (or 7%) or less.
|
||||
@Extension(url = "http://example.com/HbA1c", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's glucose")
|
||||
private QuantityDt myHbA1c;
|
||||
|
||||
@Child(name = "Height")
|
||||
@Extension(url = "http://example.com/Height", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The patient's height in cm")
|
||||
private StringDt myHeight;
|
||||
|
||||
@Child(name = "insulinLevel") // Normal range is [43,208] pmol/l
|
||||
@Extension(url = "http://example.com/Insuline", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The value of the patient's insulin")
|
||||
private QuantityDt myInsulinLevel;
|
||||
|
||||
// Other parameters
|
||||
@Child(name = "weight")
|
||||
@Extension(url = "http://example.com/Weight", definedLocally = false, isModifier = false)
|
||||
@Description(shortDefinition = "The patient's weight in Kg")
|
||||
private StringDt myWeight;
|
||||
|
||||
public QuantityDt Cholesterol() {
|
||||
if (myCholesterol == null) {
|
||||
myCholesterol = new QuantityDt();
|
||||
}
|
||||
myCholesterol.getValue();
|
||||
myCholesterol.getSystem();
|
||||
myCholesterol.getCode();
|
||||
|
||||
return myCholesterol;
|
||||
}
|
||||
|
||||
public QuantityDt getBloodPressure() {
|
||||
if (myBloodPressure == null) {
|
||||
myBloodPressure = new QuantityDt();
|
||||
}
|
||||
myBloodPressure.getValue();
|
||||
myBloodPressure.getSystem();
|
||||
myBloodPressure.getCode();
|
||||
|
||||
return myBloodPressure;
|
||||
}
|
||||
|
||||
public List<DateTimeDt> getCheckDates() {
|
||||
if (myCheckDates == null) {
|
||||
myCheckDates = new ArrayList<DateTimeDt>();
|
||||
}
|
||||
return myCheckDates;
|
||||
}
|
||||
|
||||
public QuantityDt getGlucoseLevel() {
|
||||
if (myGlucoseLevel == null) {
|
||||
myGlucoseLevel = new QuantityDt();
|
||||
}
|
||||
myGlucoseLevel.getValue();
|
||||
myGlucoseLevel.getSystem();
|
||||
myGlucoseLevel.getCode();
|
||||
|
||||
return myGlucoseLevel;
|
||||
}
|
||||
|
||||
public QuantityDt getHbA1c() {
|
||||
if (myHbA1c == null) {
|
||||
myHbA1c = new QuantityDt();
|
||||
}
|
||||
myHbA1c.getValue();
|
||||
myHbA1c.getSystem();
|
||||
myHbA1c.getCode();
|
||||
|
||||
return myHbA1c;
|
||||
}
|
||||
|
||||
public StringDt getHeight() {
|
||||
if (myHeight == null) {
|
||||
myHeight = new StringDt();
|
||||
}
|
||||
return myHeight;
|
||||
}
|
||||
|
||||
public QuantityDt getInsulinLevel() {
|
||||
if (myInsulinLevel == null) {
|
||||
myInsulinLevel = new QuantityDt();
|
||||
}
|
||||
myInsulinLevel.getValue();
|
||||
myInsulinLevel.getSystem();
|
||||
myInsulinLevel.getCode();
|
||||
|
||||
return myInsulinLevel;
|
||||
}
|
||||
|
||||
public StringDt getWeight() {
|
||||
if (myWeight == null) {
|
||||
myWeight = new StringDt();
|
||||
}
|
||||
return myWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return super.isEmpty() && ElementUtil.isEmpty(myInsulinLevel, myGlucoseLevel, myHbA1c, myBloodPressure, myCholesterol, myWeight, myHeight, myCheckDates);
|
||||
}
|
||||
|
||||
public void setBloodPressure(QuantityDt bloodPressure) {
|
||||
myBloodPressure = bloodPressure;
|
||||
myBloodPressure.setValue(110);
|
||||
myBloodPressure.setSystem("http://unitsofmeasure.org");
|
||||
myBloodPressure.setCode("mmHg");
|
||||
}
|
||||
|
||||
public void setCheckDates(List<DateTimeDt> theCheckDates) {
|
||||
myCheckDates = theCheckDates;
|
||||
myCheckDates.add(new DateTimeDt("2010-01-02"));
|
||||
}
|
||||
|
||||
public void setCholesterol(QuantityDt cholesterol) {
|
||||
myCholesterol = cholesterol;
|
||||
myCholesterol.setValue(2);
|
||||
myCholesterol.setSystem("http://unitsofmeasure.org");
|
||||
myCholesterol.setCode("mmol/l");
|
||||
}
|
||||
|
||||
public void setGlucoseLevel(QuantityDt glucoseLevel) {
|
||||
myGlucoseLevel = glucoseLevel;
|
||||
myGlucoseLevel.setValue(95);
|
||||
myGlucoseLevel.setSystem("http://unitsofmeasure.org");
|
||||
myGlucoseLevel.setCode("mg/dl");
|
||||
}
|
||||
|
||||
public void setHbA1c(QuantityDt hba1c) {
|
||||
myHbA1c = hba1c;
|
||||
myHbA1c.setValue(48);
|
||||
myHbA1c.setSystem("http://unitsofmeasure.org");
|
||||
myHbA1c.setCode("mmol/mol");
|
||||
}
|
||||
|
||||
public void setHeight(StringDt height) {
|
||||
myHeight = height;
|
||||
}
|
||||
|
||||
// Setter/Getter methods
|
||||
public void setInsulinLevel(QuantityDt insulinLevel) {
|
||||
myInsulinLevel = insulinLevel;
|
||||
myInsulinLevel.setValue(125);
|
||||
myInsulinLevel.setSystem("http://unitsofmeasure.org");
|
||||
myInsulinLevel.setCode("pmol/l");
|
||||
}
|
||||
|
||||
public void setWeight(StringDt weight) {
|
||||
myWeight = weight;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -94,6 +94,24 @@ public class JsonParserDstu2Test {
|
|||
assertEquals(true, obs.getReadOnly().getValue().booleanValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseBundleWithCustomObservationType() {
|
||||
ReportObservation obs = new ReportObservation();
|
||||
obs.setReadOnly(true);
|
||||
|
||||
IParser p = ourCtx.newJsonParser();
|
||||
// p.set
|
||||
p.setParserErrorHandler(mock(IParserErrorHandler.class, new ThrowsException(new IllegalStateException())));
|
||||
|
||||
String encoded = p.encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
obs = p.parseResource(ReportObservation.class, encoded);
|
||||
assertEquals(true, obs.getReadOnly().getValue().booleanValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeAndParseExtensions() throws Exception {
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import ca.uhn.fhir.model.primitive.BooleanDt;
|
|||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
@ResourceDef(name = "Observation", id = "reportobservation")
|
||||
@ResourceDef(name = "Observation", id = "http://example.com/reportobservation")
|
||||
public class ReportObservation extends Observation {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,72 +1,69 @@
|
|||
<Bundle
|
||||
xmlns="http://hl7.org/fhir">
|
||||
<id value="487d3669-0e1c-4867-b124-400d1849548d"></id>
|
||||
<type value="searchset"></type>
|
||||
<base value="http://localhost:19080/fhir/dstu1"></base>
|
||||
<link>
|
||||
<relation value="just trying add link"></relation>
|
||||
<url value="blarion"></url>
|
||||
</link>
|
||||
<link>
|
||||
<relation value="self"></relation>
|
||||
<url value="http://localhost:19080/fhir/dstu1/Observation?subject.identifier=puppet|CLONE-AA102"></url>
|
||||
</link>
|
||||
<entry>
|
||||
<link>
|
||||
<relation value="orionhealth.edit"></relation>
|
||||
<url value="Observation"></url>
|
||||
</link>
|
||||
<resource>
|
||||
<Observation
|
||||
xmlns="http://hl7.org/fhir">
|
||||
<id value="0d87f02c-da2c-4551-9ead-2956f0165a4f"></id>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
|
||||
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
|
||||
</extension>
|
||||
<code>
|
||||
<coding>
|
||||
<system value="http://loinc.org"></system>
|
||||
<code value="8867-4"></code>
|
||||
</coding>
|
||||
</code>
|
||||
<valueString value="observationValue"></valueString>
|
||||
<status value="final"></status>
|
||||
<reliability value="ok"></reliability>
|
||||
<subject>
|
||||
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
|
||||
</subject>
|
||||
</Observation>
|
||||
</resource>
|
||||
</entry>
|
||||
<entry>
|
||||
<link>
|
||||
<relation value="orionhealth.edit"></relation>
|
||||
<url value="Observation"></url>
|
||||
</link>
|
||||
<resource>
|
||||
<Observation
|
||||
xmlns="http://hl7.org/fhir">
|
||||
<id value="c54ac0cc-a99f-40aa-9541-c5aa853a2e88"></id>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
|
||||
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
|
||||
</extension>
|
||||
<code>
|
||||
<coding>
|
||||
<system value="http://loinc.org"></system>
|
||||
<code value="3141-9"></code>
|
||||
</coding>
|
||||
</code>
|
||||
<valueString value="observationValue"></valueString>
|
||||
<status value="final"></status>
|
||||
<reliability value="ok"></reliability>
|
||||
<subject>
|
||||
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
|
||||
</subject>
|
||||
</Observation>
|
||||
</resource>
|
||||
</entry>
|
||||
<Bundle xmlns="http://hl7.org/fhir">
|
||||
<id value="487d3669-0e1c-4867-b124-400d1849548d"></id>
|
||||
<type value="searchset"></type>
|
||||
<base value="http://localhost:19080/fhir/dstu1"></base>
|
||||
<link>
|
||||
<relation value="just trying add link"></relation>
|
||||
<url value="blarion"></url>
|
||||
</link>
|
||||
<link>
|
||||
<relation value="self"></relation>
|
||||
<url value="http://localhost:19080/fhir/dstu1/Observation?subject.identifier=puppet|CLONE-AA102"></url>
|
||||
</link>
|
||||
<entry>
|
||||
<link>
|
||||
<relation value="orionhealth.edit"></relation>
|
||||
<url value="Observation"></url>
|
||||
</link>
|
||||
<resource>
|
||||
<Observation xmlns="http://hl7.org/fhir">
|
||||
<id value="0d87f02c-da2c-4551-9ead-2956f0165a4f"></id>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
|
||||
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
|
||||
</extension>
|
||||
<code>
|
||||
<coding>
|
||||
<system value="http://loinc.org"></system>
|
||||
<code value="8867-4"></code>
|
||||
</coding>
|
||||
</code>
|
||||
<valueString value="observationValue"></valueString>
|
||||
<status value="final"></status>
|
||||
<reliability value="ok"></reliability>
|
||||
<subject>
|
||||
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
|
||||
</subject>
|
||||
</Observation>
|
||||
</resource>
|
||||
</entry>
|
||||
<entry>
|
||||
<link>
|
||||
<relation value="orionhealth.edit"></relation>
|
||||
<url value="Observation"></url>
|
||||
</link>
|
||||
<resource>
|
||||
<Observation xmlns="http://hl7.org/fhir">
|
||||
<id value="c54ac0cc-a99f-40aa-9541-c5aa853a2e88"></id>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
|
||||
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
|
||||
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
|
||||
</extension>
|
||||
<code>
|
||||
<coding>
|
||||
<system value="http://loinc.org"></system>
|
||||
<code value="3141-9"></code>
|
||||
</coding>
|
||||
</code>
|
||||
<valueString value="observationValue"></valueString>
|
||||
<status value="final"></status>
|
||||
<reliability value="ok"></reliability>
|
||||
<subject>
|
||||
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
|
||||
</subject>
|
||||
</Observation>
|
||||
</resource>
|
||||
</entry>
|
||||
</Bundle>
|
|
@ -31,27 +31,24 @@ import java.util.UUID;
|
|||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.DomainResource;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Resource;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
|
||||
import org.hl7.fhir.dstu3.model.DomainResource;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Resource;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.rest.server.BundleInclusionRule;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
@ -65,7 +62,6 @@ import ca.uhn.fhir.util.ResourceReferenceInfo;
|
|||
|
||||
public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Dstu3BundleFactory.class);
|
||||
private Bundle myBundle;
|
||||
private FhirContext myContext;
|
||||
private String myBase;
|
||||
|
@ -308,7 +304,7 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
boolean thePrettyPrint, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
||||
myBase = theServerBase;
|
||||
|
||||
|
@ -358,15 +354,6 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
}
|
||||
|
||||
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
|
||||
for (IBaseResource nextRes : resourceList) {
|
||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
|
||||
RestfulServerUtils.addProfileToBundleEntry(theServer.getFhirContext(), nextRes, theServerBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
||||
|
||||
|
|
|
@ -9,12 +9,24 @@ import org.junit.Test;
|
|||
import ca.uhn.fhir.context.BaseRuntimeChildDatatypeDefinition;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
|
||||
|
||||
public class FhirContextDstu3Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirContextDstu3Test.class);
|
||||
|
||||
private FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@Test
|
||||
public void testCustomTypeDoesntBecomeDefault() {
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
|
||||
MyPatientWithExtensions pt = new MyPatientWithExtensions();
|
||||
pt.addName().addGiven("FOO");
|
||||
ctx.newXmlParser().encodeResourceToString(pt);
|
||||
|
||||
assertEquals(Patient.class, ctx.getResourceDefinition("Patient").getImplementingClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryBoundCode() {
|
||||
RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class);
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Quantity;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
@ -13,17 +22,215 @@ import ca.uhn.fhir.model.api.annotation.Child;
|
|||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
public class CustomTypeDstu3Test {
|
||||
|
||||
private static final FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeDstu3Test.class);
|
||||
|
||||
@Test
|
||||
public void testEncode() {
|
||||
@Before
|
||||
public void before() {
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
}
|
||||
|
||||
|
||||
private String createBundle(String... theResources) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<Bundle xmlns=\"http://hl7.org/fhir\">\n");
|
||||
for (String next : theResources) {
|
||||
b.append(" <entry>\n");
|
||||
b.append(" <resource>\n");
|
||||
b.append(next);
|
||||
b.append(" </resource>\n");
|
||||
b.append(" </entry>\n");
|
||||
}
|
||||
b.append("</Bundle>");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private String createResource(boolean theWithProfile) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<Patient xmlns=\"http://hl7.org/fhir\">\n");
|
||||
if (theWithProfile) {
|
||||
b.append(" <meta>\n");
|
||||
b.append(" <profile value=\"http://example.com/foo\"/>\n");
|
||||
b.append(" </meta>\n");
|
||||
}
|
||||
b.append(" <extension url=\"http://example.com/BloodPressure\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"110\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmHg\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
|
||||
b.append(" <valueDateTime value=\"2010-01-02\"/>\n");
|
||||
b.append(" </modifierExtension>\n");
|
||||
b.append(" <modifierExtension url=\"http://example.com/diabetes2\">\n");
|
||||
b.append(" <valueDateTime value=\"2014-01-26T11:11:11\"/>\n");
|
||||
b.append(" </modifierExtension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Cholesterol\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"2\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmol/l\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Glucose\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"95\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mg/dl\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/HbA1c\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"48\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"mmol/mol\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Insuline\">\n");
|
||||
b.append(" <valueQuantity>\n");
|
||||
b.append(" <value value=\"125\"/>\n");
|
||||
b.append(" <system value=\"http://unitsofmeasure.org\"/>\n");
|
||||
b.append(" <code value=\"pmol/l\"/>\n");
|
||||
b.append(" </valueQuantity>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <extension url=\"http://example.com/Weight\">\n");
|
||||
b.append(" <valueString value=\"185 cm\"/>\n");
|
||||
b.append(" </extension>\n");
|
||||
b.append(" <identifier>\n");
|
||||
b.append(" <system value=\"urn:system\"/>\n");
|
||||
b.append(" <value value=\"1234\"/>\n");
|
||||
b.append(" </identifier>\n");
|
||||
b.append(" <name>\n");
|
||||
b.append(" <family value=\"Rossi\"/>\n");
|
||||
b.append(" <given value=\"Mario\"/>\n");
|
||||
b.append(" </name>\n");
|
||||
b.append("</Patient>");
|
||||
String input =
|
||||
b.toString();
|
||||
return input;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseBundleWithResourceDirective() {
|
||||
|
||||
String input = createBundle(createResource(false), createResource(true));
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
|
||||
|
||||
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, input);
|
||||
|
||||
Patient res0 = (Patient) bundle.getEntry().get(0).getResource();
|
||||
assertEquals(0, res0.getMeta().getProfile().size());
|
||||
List<org.hl7.fhir.dstu3.model.Extension> exts = res0.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(1, exts.size());
|
||||
assertEquals("185 cm", ((StringType)exts.get(0).getValue()).getValue());
|
||||
|
||||
MyCustomPatient res1 = (MyCustomPatient) bundle.getEntry().get(1).getResource();
|
||||
assertEquals(1, res1.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", res1.getMeta().getProfile().get(0).getValue());
|
||||
exts = res1.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(0, exts.size());
|
||||
assertEquals("185 cm", res1.getWeight().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourceWithDirective() {
|
||||
String input = createResource(true);
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
ctx.setDefaultTypeForProfile("http://example.com/foo", MyCustomPatient.class);
|
||||
|
||||
MyCustomPatient parsed = (MyCustomPatient) ctx.newXmlParser().parseResource(input);
|
||||
assertEquals(1, parsed.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
|
||||
|
||||
List<org.hl7.fhir.dstu3.model.Extension> exts = parsed.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(0, exts.size());
|
||||
|
||||
assertEquals("185 cm", parsed.getWeight().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourceWithNoDirective() {
|
||||
String input = createResource(true);
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
Patient parsed = (Patient) ctx.newXmlParser().parseResource(input);
|
||||
assertEquals(1, parsed.getMeta().getProfile().size());
|
||||
assertEquals("http://example.com/foo", parsed.getMeta().getProfile().get(0).getValue());
|
||||
|
||||
List<org.hl7.fhir.dstu3.model.Extension> exts = parsed.getExtensionsByUrl("http://example.com/Weight");
|
||||
assertEquals(1, exts.size());
|
||||
assertEquals("185 cm", ((StringType)exts.get(0).getValue()).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessEmptyMetaLists() {
|
||||
Patient p = new Patient();
|
||||
assertThat(p.getMeta().getProfile(), empty());
|
||||
assertThat(p.getMeta().getFormatCommentsPost(), empty());
|
||||
assertThat(p.getMeta().getFormatCommentsPre(), empty());
|
||||
assertThat(p.getMeta().getLastUpdated(), nullValue());
|
||||
assertThat(p.getMeta().getSecurity(), empty());
|
||||
assertThat(p.getMeta().getSecurity("foo", "bar"), nullValue());
|
||||
assertThat(p.getMeta().getTag(), empty());
|
||||
assertThat(p.getMeta().getTag("foo", "bar"), nullValue());
|
||||
assertThat(p.getMeta().getVersionId(), nullValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeCompleteMetaLists() {
|
||||
Patient p = new Patient();
|
||||
p.getMeta().addProfile("http://foo/profile1");
|
||||
p.getMeta().addProfile("http://foo/profile2");
|
||||
p.getMeta().addSecurity().setSystem("SEC_S1").setCode("SEC_C1").setDisplay("SED_D1");
|
||||
p.getMeta().addSecurity().setSystem("SEC_S2").setCode("SEC_C2").setDisplay("SED_D2");
|
||||
p.getMeta().addTag().setSystem("TAG_S1").setCode("TAG_C1").setDisplay("TAG_D1");
|
||||
p.getMeta().addTag().setSystem("TAG_S2").setCode("TAG_C2").setDisplay("TAG_D2");
|
||||
|
||||
String out = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(out);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(out, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://foo/profile1\"/>",
|
||||
"<profile value=\"http://foo/profile2\"/>",
|
||||
"<security>",
|
||||
"<system value=\"SEC_S1\"/>",
|
||||
"<code value=\"SEC_C1\"/>",
|
||||
"<display value=\"SED_D1\"/>",
|
||||
"</security>",
|
||||
"<security>",
|
||||
"<system value=\"SEC_S2\"/>",
|
||||
"<code value=\"SEC_C2\"/>",
|
||||
"<display value=\"SED_D2\"/>",
|
||||
"</security>",
|
||||
"<tag>",
|
||||
"<system value=\"TAG_S1\"/>",
|
||||
"<display value=\"TAG_D1\"/>",
|
||||
"</tag>",
|
||||
"<tag>",
|
||||
"<system value=\"TAG_S2\"/>",
|
||||
"<display value=\"TAG_D2\"/>",
|
||||
"</tag>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeWithCustomType() {
|
||||
|
||||
MyCustomPatient patient = new MyCustomPatient();
|
||||
|
||||
|
@ -36,17 +243,76 @@ public class CustomTypeDstu3Test {
|
|||
patient.setCholesterol(new Quantity());
|
||||
patient.setWeight(new StringDt("80 kg"));
|
||||
patient.setWeight(new StringDt("185 cm"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeType>());
|
||||
patient.getCheckDates().add(new DateTimeType("2014-01-26T11:11:11"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeDt>());
|
||||
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
|
||||
|
||||
IParser p = ctx.newXmlParser().setPrettyPrint(true);
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
|
||||
ourLog.info(messageString);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, not(stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"", "/>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>")));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient")
|
||||
@Test
|
||||
public void testEncodeWithCustomTypeAndAutoInsertedProfile() {
|
||||
|
||||
MyCustomPatient patient = new MyCustomPatient();
|
||||
|
||||
patient.getMeta().addProfile("http://example.com/foo");
|
||||
patient.getMeta().addProfile("http://example.com/bar");
|
||||
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("1234");
|
||||
patient.addName().addFamily("Rossi").addGiven("Mario");
|
||||
patient.setInsulinLevel(new Quantity());
|
||||
patient.setGlucoseLevel(new Quantity());
|
||||
patient.setHbA1c(new Quantity());
|
||||
patient.setBloodPressure(new Quantity());
|
||||
patient.setCholesterol(new Quantity());
|
||||
patient.setWeight(new StringDt("80 kg"));
|
||||
patient.setWeight(new StringDt("185 cm"));
|
||||
patient.setCheckDates(new ArrayList<DateTimeDt>());
|
||||
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
|
||||
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
String messageString = p.encodeResourceToString(patient);
|
||||
|
||||
ourLog.info(messageString);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"<profile value=\"http://example.com/bar\"/>",
|
||||
"</meta>"));
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
assertThat(messageString, not(stringContainsInOrder(
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/foo\"", "/>",
|
||||
"<profile value=\"http://example.com/foo\"/>",
|
||||
"</meta>")));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
|
||||
@ResourceDef(name = "Patient", profile = "http://example.com/foo")
|
||||
public static class MyCustomPatient extends Patient {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -60,7 +326,7 @@ public class CustomTypeDstu3Test {
|
|||
@Child(name = "CheckDates", max = Child.MAX_UNLIMITED)
|
||||
@Extension(url = "http://example.com/diabetes2", definedLocally = false, isModifier = true)
|
||||
@Description(shortDefinition = "Dates of periodic tests")
|
||||
private List<DateTimeType> myCheckDates;
|
||||
private List<DateTimeDt> myCheckDates;
|
||||
|
||||
@Child(name = "cholesterol") // once a year. The target is triglycerides =< 2 mmol/l e cholesterol =< 4 mmol/l
|
||||
@Extension(url = "http://example.com/Cholesterol", definedLocally = false, isModifier = false)
|
||||
|
@ -116,9 +382,9 @@ public class CustomTypeDstu3Test {
|
|||
return myBloodPressure;
|
||||
}
|
||||
|
||||
public List<DateTimeType> getCheckDates() {
|
||||
public List<DateTimeDt> getCheckDates() {
|
||||
if (myCheckDates == null) {
|
||||
myCheckDates = new ArrayList<DateTimeType>();
|
||||
myCheckDates = new ArrayList<DateTimeDt>();
|
||||
}
|
||||
return myCheckDates;
|
||||
}
|
||||
|
@ -182,9 +448,9 @@ public class CustomTypeDstu3Test {
|
|||
myBloodPressure.setCode("mmHg");
|
||||
}
|
||||
|
||||
public void setCheckDates(List<DateTimeType> theCheckDates) {
|
||||
public void setCheckDates(List<DateTimeDt> theCheckDates) {
|
||||
myCheckDates = theCheckDates;
|
||||
myCheckDates.add(new DateTimeType("2010-01-02"));
|
||||
myCheckDates.add(new DateTimeDt("2010-01-02"));
|
||||
}
|
||||
|
||||
public void setCholesterol(Quantity cholesterol) {
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hl7.fhir.dstu3.model.Binary;
|
||||
import org.hl7.fhir.dstu3.model.Conformance;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.util.VersionUtil;
|
||||
|
||||
public class ClientWithCustomTypeDstu3Test {
|
||||
private static FhirContext ourCtx;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ClientWithCustomTypeDstu3Test.class);
|
||||
private HttpClient myHttpClient;
|
||||
private HttpResponse myHttpResponse;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||
}
|
||||
|
||||
private byte[] extractBodyAsByteArray(ArgumentCaptor<HttpUriRequest> capt) throws IOException {
|
||||
byte[] body = IOUtils.toByteArray(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent());
|
||||
return body;
|
||||
}
|
||||
|
||||
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> capt) throws IOException {
|
||||
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(0)).getEntity().getContent(), "UTF-8");
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadCustomType() throws Exception {
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
|
||||
MyPatientWithExtensions response = new MyPatientWithExtensions();
|
||||
response.addName().addFamily("FAMILY");
|
||||
response.getStringExt().setValue("STRINGVAL");
|
||||
response.getDateExt().setValueAsString("2011-01-02");
|
||||
final String respString = p.encodeResourceToString(response);
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
|
||||
@Override
|
||||
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
//@formatter:off
|
||||
MyPatientWithExtensions value = client
|
||||
.read()
|
||||
.resource(MyPatientWithExtensions.class)
|
||||
.withId("123")
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
HttpUriRequest request = capt.getAllValues().get(0);
|
||||
|
||||
assertEquals("http://example.com/fhir/Patient/123", request.getURI().toASCIIString());
|
||||
assertEquals("GET", request.getMethod());
|
||||
|
||||
assertEquals(1, value.getName().size());
|
||||
assertEquals("FAMILY", value.getName().get(0).getFamilyAsSingleString());
|
||||
assertEquals("STRINGVAL", value.getStringExt().getValue());
|
||||
assertEquals("2011-01-02", value.getDateExt().getValueAsString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.BaseResource;
|
||||
import org.hl7.fhir.dstu3.model.DateType;
|
||||
import org.hl7.fhir.dstu3.model.DomainResource;
|
||||
import org.hl7.fhir.dstu3.model.HumanName;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.ResourceType;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
|
||||
@ResourceDef(name="Patient", profile="http://example.com/StructureDefinition/patient_with_extensions")
|
||||
public class MyPatientWithExtensions extends DomainResource {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Extension(url = "http://example.com/ext/date", definedLocally = false, isModifier = true)
|
||||
@Child(name = "modExt")
|
||||
private DateType myDateExt;
|
||||
|
||||
@Extension(url = "http://example.com/ext/string", definedLocally = false, isModifier = false)
|
||||
@Child(name = "extAtt")
|
||||
private StringType myStringExt;
|
||||
|
||||
@Child(name = "name", type = {HumanName.class}, min=0, max=Child.MAX_UNLIMITED, modifier=false, summary=true)
|
||||
@Description(shortDefinition="A name associated with the patient", formalDefinition="A name associated with the individual." )
|
||||
private List<HumanName> myName;
|
||||
|
||||
|
||||
public List<HumanName> getName() {
|
||||
if (myName == null) {
|
||||
myName = new ArrayList<HumanName>();
|
||||
}
|
||||
return myName;
|
||||
}
|
||||
|
||||
public void setName(List<HumanName> theName) {
|
||||
myName = theName;
|
||||
}
|
||||
|
||||
public DateType getDateExt() {
|
||||
if (myDateExt == null) {
|
||||
myDateExt = new DateType();
|
||||
}
|
||||
return myDateExt;
|
||||
}
|
||||
|
||||
public StringType getStringExt() {
|
||||
if (myStringExt == null) {
|
||||
myStringExt = new StringType();
|
||||
}
|
||||
return myStringExt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return super.isEmpty() && ElementUtil.isEmpty(myStringExt, myDateExt);
|
||||
}
|
||||
|
||||
public void setDateExt(DateType theDateExt) {
|
||||
myDateExt = theDateExt;
|
||||
}
|
||||
|
||||
public void setStringExt(StringType theStringExt) {
|
||||
myStringExt = theStringExt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResource copy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getResourceType() {
|
||||
return ResourceType.Patient;
|
||||
}
|
||||
|
||||
public HumanName addName() {
|
||||
HumanName retVal = new HumanName();
|
||||
getName().add(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
|
@ -10,120 +12,88 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.DateType;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
public class CreateDstu3Test {
|
||||
private static CloseableHttpClient ourClient;
|
||||
|
||||
private static String ourLastConditionalUrl;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CreateDstu3Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static IdType ourLastId;
|
||||
private static IdType ourLastIdParam;
|
||||
private static boolean ourLastRequestWasSearch;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastId = null;
|
||||
ourLastConditionalUrl = null;
|
||||
ourLastIdParam = null;
|
||||
ourLastRequestWasSearch = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInBody() throws Exception {
|
||||
public void testRead() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("2");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
// httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2?_format=xml&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", an ID element must not be supplied in the resource body on a create (POST) operation", oo.getIssue().get(0).getDiagnostics());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
//@formatter:off
|
||||
assertThat(responseContent, stringContainsInOrder("<Patient xmlns=\"http://hl7.org/fhir\">",
|
||||
"<id value=\"2\"/>",
|
||||
"<modifierExtension url=\"http://example.com/ext/date\">",
|
||||
"<valueDate value=\"2011-01-01\"/>",
|
||||
"</modifierExtension>",
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/StructureDefinition/patient_with_extensions\"/>",
|
||||
"</meta>",
|
||||
"</Patient>"));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInUrl() throws Exception {
|
||||
public void testSearch() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/2");
|
||||
// httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=xml&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInUrlForConditional() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/2");
|
||||
httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", oo.getIssue().get(0).getDiagnostics());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
//@formatter:off
|
||||
assertThat(responseContent, stringContainsInOrder("<Patient xmlns=\"http://hl7.org/fhir\">",
|
||||
"<id value=\"0\"/>",
|
||||
"<modifierExtension url=\"http://example.com/ext/date\">",
|
||||
"<valueDate value=\"2011-01-01\"/>",
|
||||
"</modifierExtension>",
|
||||
"<meta>",
|
||||
"<profile value=\"http://example.com/StructureDefinition/patient_with_extensions\"/>",
|
||||
"</meta>",
|
||||
"</Patient>"));
|
||||
//@formatter:on
|
||||
|
||||
assertThat(responseContent, not(containsString("http://hl7.org/fhir/")));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
@ -140,6 +110,7 @@ public class CreateDstu3Test {
|
|||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
|
@ -160,18 +131,29 @@ public class CreateDstu3Test {
|
|||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IResource> search(@OptionalParam(name = "foo") StringDt theString) {
|
||||
ourLastRequestWasSearch = true;
|
||||
return new ArrayList<IResource>();
|
||||
@Read()
|
||||
public MyPatientWithExtensions read(@IdParam IdType theIdParam) {
|
||||
MyPatientWithExtensions p0 = new MyPatientWithExtensions();
|
||||
p0.setId(theIdParam);
|
||||
p0.setDateExt(new DateType("2011-01-01"));
|
||||
return p0;
|
||||
}
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient, @ConditionalUrlParam String theConditional, @IdParam IdType theIdParam) {
|
||||
ourLastConditionalUrl = theConditional;
|
||||
ourLastId = thePatient.getIdElement();
|
||||
ourLastIdParam = theIdParam;
|
||||
return new MethodOutcome(new IdType("Patient/001/_history/002"));
|
||||
@Search
|
||||
public List<IBaseResource> search() {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
|
||||
MyPatientWithExtensions p0 = new MyPatientWithExtensions();
|
||||
p0.setId(new IdType("Patient/0"));
|
||||
p0.setDateExt(new DateType("2011-01-01"));
|
||||
retVal.add(p0);
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setId(new IdType("Patient/1"));
|
||||
p1.addName().addFamily("The Family");
|
||||
retVal.add(p1);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
public class CustomTypeServerDstu3 {
|
||||
private static CloseableHttpClient ourClient;
|
||||
|
||||
private static String ourLastConditionalUrl;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeServerDstu3.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static IdType ourLastId;
|
||||
private static IdType ourLastIdParam;
|
||||
private static boolean ourLastRequestWasSearch;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastId = null;
|
||||
ourLastConditionalUrl = null;
|
||||
ourLastIdParam = null;
|
||||
ourLastRequestWasSearch = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInBody() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId("2");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
// httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", an ID element must not be supplied in the resource body on a create (POST) operation", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInUrl() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/2");
|
||||
// httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithIdInUrlForConditional() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/2");
|
||||
httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?identifier=system%7C001");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent);
|
||||
assertEquals("Can not create resource with ID \"2\", ID must not be supplied on a create (POST) operation (use an HTTP PUT / update operation if you wish to supply an ID)", oo.getIssue().get(0).getDiagnostics());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
PatientProvider patientProvider = new PatientProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<IResource> search(@OptionalParam(name = "foo") StringDt theString) {
|
||||
ourLastRequestWasSearch = true;
|
||||
return new ArrayList<IResource>();
|
||||
}
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient, @ConditionalUrlParam String theConditional, @IdParam IdType theIdParam) {
|
||||
ourLastConditionalUrl = theConditional;
|
||||
ourLastId = thePatient.getIdElement();
|
||||
ourLastIdParam = theIdParam;
|
||||
return new MethodOutcome(new IdType("Patient/001/_history/002"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -48,10 +48,8 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.rest.server.BundleInclusionRule;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
@ -59,7 +57,6 @@ import ca.uhn.fhir.rest.server.IBundleProvider;
|
|||
import ca.uhn.fhir.rest.server.IPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.IRestfulServer;
|
||||
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
|
@ -298,7 +295,7 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer theServer, IBundleProvider theResult,
|
||||
public void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult,
|
||||
EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint,
|
||||
int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
||||
myBase = theServerBase;
|
||||
|
@ -344,15 +341,6 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
}
|
||||
|
||||
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
|
||||
for (IBaseResource nextRes : resourceList) {
|
||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
|
||||
RestfulServerUtils.addProfileToBundleEntry(theServer.getFhirContext(), nextRes, theServerBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addResourcesToBundle(resourceList, theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType,
|
||||
theResult.getPublished());
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.hl7.fhir.instance.model.StringType;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.INarrative;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.junit.After;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
@ -67,11 +68,11 @@ import org.xml.sax.SAXException;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.base.composite.BaseNarrativeDt;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.parser.JsonParserHl7OrgTest.MyPatientWithOneDeclaredAddressExtension;
|
||||
import ca.uhn.fhir.parser.JsonParserHl7OrgTest.MyPatientWithOneDeclaredEnumerationExtension;
|
||||
import ca.uhn.fhir.parser.JsonParserHl7OrgTest.MyPatientWithOneDeclaredExtension;
|
||||
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import net.sf.json.JSON;
|
||||
import net.sf.json.JSONSerializer;
|
||||
|
@ -81,33 +82,19 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
private static FhirContext ourCtx;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserHl7OrgDstu2Test.class);
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.ONLY_FOR_CUSTOM);
|
||||
}
|
||||
|
||||
private String fixDivNodeText(String htmlNoNs) {
|
||||
return htmlNoNs.replace("<div>", "<div xmlns=\"http://www.w3.org/1999/xhtml\">");
|
||||
}
|
||||
|
||||
private String fixDivNodeTextJson(String htmlNoNs) {
|
||||
private String fixDivNodeTextJson(String htmlNoNs) {
|
||||
return htmlNoNs.replace("<div>", "<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">");
|
||||
}
|
||||
|
||||
/**
|
||||
* See #216 - Profiled datatypes should use their unprofiled parent type as the choice[x] name
|
||||
*
|
||||
* Disabled after conversation with Grahame
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testEncodeAndParseProfiledDatatypeChoice() throws Exception {
|
||||
IParser xmlParser = ourCtx.newXmlParser();
|
||||
|
||||
String input = IOUtils.toString(XmlParser.class.getResourceAsStream("/medicationstatement_invalidelement.xml"));
|
||||
MedicationStatement ms = xmlParser.parseResource(MedicationStatement.class, input);
|
||||
SimpleQuantity q = (SimpleQuantity) ms.getDosage().get(0).getQuantity();
|
||||
assertEquals("1", q.getValueElement().getValueAsString());
|
||||
|
||||
String output = xmlParser.encodeResourceToString(ms);
|
||||
assertThat(output, containsString("<quantityQuantity><value value=\"1\"/></quantityQuantity>"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testComposition() {
|
||||
|
@ -575,6 +562,26 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #216 - Profiled datatypes should use their unprofiled parent type as the choice[x] name
|
||||
*
|
||||
* Disabled after conversation with Grahame
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testEncodeAndParseProfiledDatatypeChoice() throws Exception {
|
||||
IParser xmlParser = ourCtx.newXmlParser();
|
||||
|
||||
String input = IOUtils.toString(XmlParser.class.getResourceAsStream("/medicationstatement_invalidelement.xml"));
|
||||
MedicationStatement ms = xmlParser.parseResource(MedicationStatement.class, input);
|
||||
SimpleQuantity q = (SimpleQuantity) ms.getDosage().get(0).getQuantity();
|
||||
assertEquals("1", q.getValueElement().getValueAsString());
|
||||
|
||||
String output = xmlParser.encodeResourceToString(ms);
|
||||
assertThat(output, containsString("<quantityQuantity><value value=\"1\"/></quantityQuantity>"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryResource() {
|
||||
|
||||
|
@ -587,7 +594,6 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryWithNoContentType() {
|
||||
Binary b = new Binary();
|
||||
|
@ -613,7 +619,6 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
assertThat(val, containsString("home"));
|
||||
assertThat(val, containsString("male"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBundle() throws InterruptedException {
|
||||
Bundle b = new Bundle();
|
||||
|
@ -650,6 +655,7 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
assertThat(bundleString, StringContainsInOrder.stringContainsInOrder(strings));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBundleCategory() {
|
||||
|
||||
|
@ -676,7 +682,7 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
assertEquals("term", b.getEntry().get(0).getResource().getMeta().getTag().get(0).getCode());
|
||||
assertEquals("label", b.getEntry().get(0).getResource().getMeta().getTag().get(0).getDisplay());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeContainedAndIncludedResources() {
|
||||
|
||||
|
@ -718,6 +724,7 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeContainedWithNarrativeIsSuppresed() throws Exception {
|
||||
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
|
@ -745,7 +752,6 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeDeclaredExtensionWithAddressContent() {
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
|
@ -1110,6 +1116,7 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExtensionOnComposite() throws Exception {
|
||||
|
||||
|
@ -1133,7 +1140,6 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExtensionOnPrimitive() throws Exception {
|
||||
|
||||
|
@ -1215,10 +1221,11 @@ public class XmlParserHl7OrgDstu2Test {
|
|||
assertTrue(d.toString(), d.identical());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLoadAndEncodeDeclaredExtensions() throws ConfigurationException, DataFormatException, SAXException, IOException {
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.NEVER);
|
||||
|
||||
//@formatter:off
|
||||
String msg = "<ResourceWithExtensionsA xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
|
|
|
@ -26,9 +26,6 @@ import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
|||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class BundleTypeInResponseHl7OrgTest {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
|
|
|
@ -1,180 +0,0 @@
|
|||
package ca.uhn.fhir.model.dstu2.resource;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Structures - DSTU2 (FHIR v0.4.0)
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import ca.uhn.fhir.model.api.BaseElement;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.SearchParamDefinition;
|
||||
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
|
||||
import ca.uhn.fhir.model.dstu2.composite.ContainedDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.NarrativeDt;
|
||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
public abstract class BaseResource extends BaseElement implements IResource {
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_language</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" )
|
||||
public static final String SP_RES_LANGUAGE = "_language";
|
||||
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_id</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" )
|
||||
public static final String SP_RES_ID = "_id";
|
||||
|
||||
/**
|
||||
* <b>Fluent Client</b> search parameter constant for <b>_id</b>
|
||||
* <p>
|
||||
* Description: <b>the _id of a resource</b><br>
|
||||
* Type: <b>string</b><br>
|
||||
* Path: <b>Resource._id</b><br>
|
||||
* </p>
|
||||
*/
|
||||
public static final StringClientParam RES_ID = new StringClientParam(BaseResource.SP_RES_ID);
|
||||
|
||||
|
||||
@Child(name = "contained", order = 2, min = 0, max = 1)
|
||||
private ContainedDt myContained;
|
||||
|
||||
private IdDt myId;
|
||||
|
||||
@Child(name = "language", order = 0, min = 0, max = Child.MAX_UNLIMITED)
|
||||
private CodeDt myLanguage;
|
||||
|
||||
private ResourceMetadataMap myResourceMetadata;
|
||||
|
||||
@Child(name = "text", order = 1, min = 0, max = 1)
|
||||
private NarrativeDt myText;
|
||||
|
||||
@Override
|
||||
public ContainedDt getContained() {
|
||||
if (myContained == null) {
|
||||
myContained = new ContainedDt();
|
||||
}
|
||||
return myContained;
|
||||
}
|
||||
|
||||
public IdDt getId() {
|
||||
if (myId == null) {
|
||||
myId = new IdDt();
|
||||
}
|
||||
return myId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType getIdElement() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeDt getLanguage() {
|
||||
if (myLanguage == null) {
|
||||
myLanguage = new CodeDt();
|
||||
}
|
||||
return myLanguage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceMetadataMap getResourceMetadata() {
|
||||
if (myResourceMetadata == null) {
|
||||
myResourceMetadata = new ResourceMetadataMap();
|
||||
}
|
||||
return myResourceMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NarrativeDt getText() {
|
||||
if (myText == null) {
|
||||
myText = new NarrativeDt();
|
||||
}
|
||||
return myText;
|
||||
}
|
||||
|
||||
public void setContained(ContainedDt theContained) {
|
||||
myContained = theContained;
|
||||
}
|
||||
|
||||
public void setId(IdDt theId) {
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
public BaseResource setId(IIdType theId) {
|
||||
if (theId instanceof IdDt) {
|
||||
myId = (IdDt) theId;
|
||||
} else if (theId != null) {
|
||||
myId = new IdDt(theId.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseResource setId(String theId) {
|
||||
if (theId == null) {
|
||||
myId = null;
|
||||
} else {
|
||||
myId = new IdDt(theId);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLanguage(CodeDt theLanguage) {
|
||||
myLanguage = theLanguage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceMetadata(ResourceMetadataMap theMap) {
|
||||
Validate.notNull(theMap, "The Map must not be null");
|
||||
myResourceMetadata = theMap;
|
||||
}
|
||||
|
||||
public void setText(NarrativeDt theText) {
|
||||
myText = theText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
b.append("id", getId().toUnqualified());
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
|
||||
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isBaseEmpty() {
|
||||
return super.isBaseEmpty() && ElementUtil.isEmpty(myLanguage, myText, myId);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -51,6 +51,7 @@
|
|||
}
|
||||
|
||||
#foreach ( $child in $childElements )
|
||||
#if (${child.methodName} != 'Meta')
|
||||
/**
|
||||
* Gets the value(s) for <b>${child.elementName}</b> ($esc.html(${child.shortName})).
|
||||
* creating it if it does
|
||||
|
@ -73,7 +74,7 @@
|
|||
#end
|
||||
return ${child.variableName};
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
/**
|
||||
* Gets the value(s) for <b>${child.elementName}</b> ($esc.html(${child.shortName})).
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
<body>
|
||||
<release version="1.5" date="TBD">
|
||||
<action type="add">
|
||||
Bump the version of a few dependencies to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Hibernate (JPA, Web Tester): 5.0.7 -> 5.1.0</li>
|
||||
<li>Spring (JPA, Web Tester): 4.2.4 -> 4.2.5</li>
|
||||
Bump the version of a few dependencies to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Hibernate (JPA, Web Tester): 5.0.7 -> 5.1.0</li>
|
||||
<li>Spring (JPA, Web Tester): 4.2.4 -> 4.2.5</li>
|
||||
<li>SLF4j (All): 1.7.14 -> 1.7.16</li>
|
||||
</ul>
|
||||
]]>
|
||||
</ul>
|
||||
]]>
|
||||
</action>
|
||||
<action type="add">
|
||||
Support comments when parsing and encoding both JSON and XML. Comments are retrieved
|
||||
|
@ -119,7 +119,7 @@
|
|||
<action type="fix" issue="297">
|
||||
<![CDATA[When <code>IServerInterceptor#incomingRequestPreHandled()</code> is called
|
||||
for a <code>@Validate</code> method, the resource was not populated in the
|
||||
<code>ActionRequestDetails</code> argument. Thanks to Ravi Kuchi for reporting!
|
||||
<code>ActionRequestDetails</code> argument. Thanks to Ravi Kuchi for reporting!
|
||||
]]>
|
||||
</action>
|
||||
<action type="fix" issue="298">
|
||||
|
@ -261,21 +261,59 @@
|
|||
header containing "application/xml" as some browsers
|
||||
do.
|
||||
</action>
|
||||
<action type="add">
|
||||
DSTU2 resources now have a
|
||||
<![CDATA[<code>getMeta()</code>]]> method which returns a
|
||||
modifiable view of the resource metadata for convenience. This
|
||||
matches the equivalent method in the DSTU3 structures.
|
||||
</action>
|
||||
<action type="add" issue="315">
|
||||
Add a new method to FhirContext called
|
||||
<![CDATA[
|
||||
<code><a href="./apidocs/ca/uhn/fhir/context/FhirContext.html#setDefaultTypeForProfile-java.lang.String-java.lang.Class-">setDefaultTypeForProfile</a></code>
|
||||
]]>
|
||||
which can be used to specify that when recources are received which declare
|
||||
support for specific profiles, a specific custom structures should be used
|
||||
instead of the default. For example, if you have created a custom Observation
|
||||
class for a specific profile, you could use this method to cause your custom
|
||||
type to be used by the parser for resources in a search bundle you receive.
|
||||
<![CDATA[
|
||||
<br/><br/>
|
||||
See the documentation page on
|
||||
<a href="./doc_extensions.html">Profiles and Extensions</a>
|
||||
for more information.
|
||||
]]>
|
||||
</action>
|
||||
<action type="fix" issue="315">
|
||||
Parsing/Encoding a custom resource type which extends a
|
||||
base type sometimes caused the FhirContext to treat all future
|
||||
parses of the same resource as using the custom type even when
|
||||
this was not wanted.
|
||||
<![CDATA[<br/><br/>]]>
|
||||
Custom structures may now be explicitly declared by profile
|
||||
using the
|
||||
<![CDATA[
|
||||
<code><a href="./apidocs/ca/uhn/fhir/context/FhirContext.html#setDefaultTypeForProfile-java.lang.String-java.lang.Class-">setDefaultTypeForProfile</a></code>
|
||||
]]>
|
||||
method.
|
||||
<![CDATA[<br/><br/>]]>
|
||||
This issue was discovered and fixed as a part of the implementation of issue #315.
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.4" date="2016-02-04">
|
||||
<action type="add">
|
||||
Bump the version of a few dependencies to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Hibernate (JPA, Web Tester): 5.0.3 -> 5.0.7</li>
|
||||
<li>Springframework (JPA, Web Tester): 4.2.2 -> 4.2.4</li>
|
||||
Bump the version of a few dependencies to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Hibernate (JPA, Web Tester): 5.0.3 -> 5.0.7</li>
|
||||
<li>Springframework (JPA, Web Tester): 4.2.2 -> 4.2.4</li>
|
||||
<li>Phloc-Commons (Schematron Validator): 4.3.6 -> 4.4.4</li>
|
||||
<li>Apache httpclient (Client): 4.4 -> 4.5.1</li>
|
||||
<li>Apache httpcore (Client): 4.4 -> 4.4.4</li>
|
||||
<li>SLF4j (All): 1.7.13 -> 1.7.14</li>
|
||||
</ul>
|
||||
]]>
|
||||
</ul>
|
||||
]]>
|
||||
</action>
|
||||
<action type="fix">
|
||||
Remove a dependency on a Java 1.7 class
|
||||
|
@ -430,20 +468,20 @@
|
|||
</release>
|
||||
<release version="1.3" date="2015-11-14">
|
||||
<action type="add">
|
||||
Bump the version of a few dependencies to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Commons-lang3 (Core): 3.3.2 -> 3.4</li>
|
||||
<li>Logback (Core): 1.1.2 -> 1.1.3</li>
|
||||
<li>SLF4j (Core): 1.7.102 -> 1.7.12</li>
|
||||
<li>Springframework (JPA, Web Tester): 4.1.5 -> 4.2.2</li>
|
||||
<li>Hibernate (JPA, Web Tester): 4.2.17 -> 5."</li>
|
||||
<li>Hibernate Validator (JPA, Web Tester): 5.2.1 -> 5.2.2</li>
|
||||
<li>Derby (JPA, CLI, Public Server): 10.11.1.1 -> 10.12.1.1 </li>
|
||||
<li>Jetty (JPA, CLI, Public Server): 9.2.6.v20141205 -> 9.3.4.v20151007 </li>
|
||||
</ul>
|
||||
]]>
|
||||
Bump the version of a few dependencies to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Commons-lang3 (Core): 3.3.2 -> 3.4</li>
|
||||
<li>Logback (Core): 1.1.2 -> 1.1.3</li>
|
||||
<li>SLF4j (Core): 1.7.102 -> 1.7.12</li>
|
||||
<li>Springframework (JPA, Web Tester): 4.1.5 -> 4.2.2</li>
|
||||
<li>Hibernate (JPA, Web Tester): 4.2.17 -> 5."</li>
|
||||
<li>Hibernate Validator (JPA, Web Tester): 5.2.1 -> 5.2.2</li>
|
||||
<li>Derby (JPA, CLI, Public Server): 10.11.1.1 -> 10.12.1.1 </li>
|
||||
<li>Jetty (JPA, CLI, Public Server): 9.2.6.v20141205 -> 9.3.4.v20151007 </li>
|
||||
</ul>
|
||||
]]>
|
||||
</action>
|
||||
<action type="add">
|
||||
JPA and Tester Overlay now use Spring Java config files instead
|
||||
|
@ -500,7 +538,7 @@
|
|||
</action>
|
||||
<action type="fix">
|
||||
In server, if a client request is received and it has an Accept header indicating
|
||||
that it supports both XML and JSON with equal weight, the server's default is used instead of the first entry in the list.
|
||||
that it supports both XML and JSON with equal weight, the server's default is used instead of the first entry in the list.
|
||||
</action>
|
||||
<action type="add">
|
||||
JPA server now supports searching with sort by token, quantity,
|
||||
|
@ -780,7 +818,7 @@
|
|||
</action>
|
||||
<action type="add">
|
||||
Resource references using resource instance objects instead of resource IDs
|
||||
will correctly qualify the IDs with the resource type if they aren't already qualified
|
||||
will correctly qualify the IDs with the resource type if they aren't already qualified
|
||||
</action>
|
||||
<action type="add" issue="211">
|
||||
Testpage Overlay project now properly allows a custom client
|
||||
|
@ -1314,7 +1352,7 @@
|
|||
RestfulClientConfig. Thanks to Grahame Grieve for the suggestion!
|
||||
</action>
|
||||
<action type="add">
|
||||
JPA module now supports deleting resource via transaction
|
||||
JPA module now supports deleting resource via transaction
|
||||
</action>
|
||||
<action type="fix" issue="97" due-to="twilson650">
|
||||
DateClientParam#second() incorrectly used DAY precision instead
|
||||
|
@ -1359,15 +1397,15 @@
|
|||
<action type="add">
|
||||
Add support for FHIR "extended operations" as defined in the FHIR DSTU2
|
||||
specification, for the Generic Client, Annotation Client, and
|
||||
Server.
|
||||
Server.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Observation.applies[x] and other similar search fields with multiple allowable
|
||||
value types were not being correctly indexed in the JPA server.
|
||||
value types were not being correctly indexed in the JPA server.
|
||||
</action>
|
||||
<action type="fix" issue="122">
|
||||
DateClientParam.before() incorrectly placed "<=" instead of
|
||||
"<" in the request URL. Thanks to Ryan for reporting!
|
||||
"<" in the request URL. Thanks to Ryan for reporting!
|
||||
</action>
|
||||
<action type="add" issue="77" dev="wdebeau1">
|
||||
Server now only automatically adds _include resources which are provided
|
||||
|
@ -1396,7 +1434,7 @@
|
|||
own JAR, in order to allow support for DEV resources, and DSTU2 resources when thast
|
||||
version is finalized. See the
|
||||
<![CDATA[<a href="./doc_dstu2.html">DSTU2 page</a>]]>
|
||||
for more information.
|
||||
for more information.
|
||||
</action>
|
||||
<action type="fix">
|
||||
<![CDATA[
|
||||
|
@ -1435,7 +1473,7 @@
|
|||
</action>
|
||||
<action type="add" issue="44" dev="petromykhailysyn">
|
||||
Remove unnecessary IOException from narrative generator API. Thanks to
|
||||
Petro Mykhailysyn for the pull request!
|
||||
Petro Mykhailysyn for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="48" dev="wdebeau1">
|
||||
Introduced a new
|
||||
|
@ -1709,7 +1747,7 @@
|
|||
</action>
|
||||
<action type="add" issue="31" dev="preston">
|
||||
Add a
|
||||
<![CDATA[<a href="https://www.vagrantup.com/">Vagrant</a>]]>
|
||||
<![CDATA[<a href="https://www.vagrantup.com/">Vagrant</a>]]>
|
||||
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!
|
||||
|
@ -1726,19 +1764,19 @@
|
|||
<release version="0.6" date="2014-09-08" description="This release brings a number of new features and bug fixes!">
|
||||
<!--
|
||||
<action type="add">
|
||||
Allow generic client ... OAUTH
|
||||
Allow generic client ... OAUTH
|
||||
</action>
|
||||
-->
|
||||
<action type="add">
|
||||
Add server interceptor framework, and new interceptor for logging incoming
|
||||
requests.
|
||||
requests.
|
||||
</action>
|
||||
<action type="add">
|
||||
Add server validation framework for validating resources against the FHIR schemas and schematrons
|
||||
</action>
|
||||
<action type="fix">
|
||||
Tester UI created double _format and _pretty param entries in searches. Thanks to Gered King of University
|
||||
Health Network for reporting!
|
||||
Health Network for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="4">
|
||||
Create method was incorrectly returning an HTTP 204 on sucessful completion, but
|
||||
|
@ -1939,7 +1977,7 @@
|
|||
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!
|
||||
</action>
|
||||
</release>
|
||||
</release>
|
||||
<release version="0.4" date="2014-07-13">
|
||||
<action type="add">
|
||||
<![CDATA[<b>BREAKING CHANGE:</b>]]>: IdDt has been modified so that it
|
||||
|
|
|
@ -3,13 +3,20 @@
|
|||
|
||||
<properties>
|
||||
<title>Profiles and Extensions</title>
|
||||
<author email="jamesagnew@users.sourceforge.net">James Agnew</author>
|
||||
<author email="jamesagnew@gmail.com">James Agnew</author>
|
||||
</properties>
|
||||
|
||||
<body>
|
||||
|
||||
<section name="Undeclared Extensions">
|
||||
|
||||
<p class="doc_info_bubble">
|
||||
Note on FHIR Versions: Because of the differences in the way the structures
|
||||
work between DSTU2 and DSTU3, we have provided two versions of many of the
|
||||
examples on this page. See the <a href="./download.html">download page</a>
|
||||
for more information on FHIR versions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Extensions are a key part of the FHIR specification, providing a standardized
|
||||
way of placing additional data in a resource.
|
||||
|
@ -21,19 +28,42 @@
|
|||
Undeclared extensions can be added to any of the built in FHIR resource types that come with HAPI-FHIR.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>DSTU2</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="resourceExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/Extensions.java" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu2.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
<b>DSTU3</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="resourceExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
Undeclared extensions can also be added to datatypes (composite or primitive).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>DSTU2</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="resourceStringExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/Extensions.java" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu2.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
<b>DSTU3</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="resourceStringExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||
</macro>
|
||||
|
||||
<subsection name="Sub-Extensions">
|
||||
|
||||
<p>
|
||||
|
@ -41,24 +71,48 @@
|
|||
of a datatype. This is done by adding a child undeclared extension to the
|
||||
parent extension.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>DSTU2</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="subExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/Extensions.java" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu2.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
<b>DSTU3</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="subExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||
</macro>
|
||||
|
||||
</subsection>
|
||||
|
||||
<subsection name="Retrieving Extension Values">
|
||||
|
||||
<p>
|
||||
HAPI provides a few ways of accessing extension values in resources
|
||||
which are receieved from other sources (i.e. downloaded by a client).
|
||||
which are received from other sources (i.e. downloaded by a client).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>DSTU2</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="parseExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/Extensions.java" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu2.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
<b>DSTU3</b>
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="parseExtension" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||
</macro>
|
||||
|
||||
</subsection>
|
||||
|
||||
</section>
|
||||
|
@ -119,85 +173,44 @@
|
|||
<param name="file" value="examples/src/main/java/example/MyPatientUse.java" />
|
||||
</macro>
|
||||
|
||||
<subsection name="Documentation">
|
||||
<subsection name="Using Custom Types in a Client">
|
||||
|
||||
<p>
|
||||
Note in the example above the use of the <code>@Description</code>
|
||||
annotation on the extension fields. This documentation is important,
|
||||
as the FHIR Server will automatically add it to the generated Profile
|
||||
resources which are exported by the server.
|
||||
If you are using a client and wish to use a specific custom structure,
|
||||
you may simply use the custom structure as you would a build in
|
||||
HAPI type.
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="customTypeClientSimple" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
These bits of documentation will then be re-added to any automatically
|
||||
generated clients built using <a href="./doc_tinder.html">Tinder</a>
|
||||
against your server.
|
||||
Sometimes you may not know in advance exactly which
|
||||
type you will be receiving. For example, there are Patient resources
|
||||
which conform to several different profiles on a server and you
|
||||
aren't sure which profile you will get back for a specific read,
|
||||
you can declare the "primary" type for a given profile.
|
||||
</p>
|
||||
<macro name="snippet">
|
||||
<param name="id" value="customTypeClientDeclared" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||
</macro>
|
||||
|
||||
</subsection>
|
||||
|
||||
<subsection name="Using Custom Types in a Server">
|
||||
|
||||
<p>
|
||||
The following is a snippet from the generated Profile resource
|
||||
which is automatically created by a HAPI RESTful server using
|
||||
your new type. (Don't worry if this part doens't make sense to you
|
||||
yet, this is an advanced feature)
|
||||
If you are using a client and wish to use a specific custom structure,
|
||||
you may simply use the custom structure as you would a build in
|
||||
HAPI type.
|
||||
</p>
|
||||
|
||||
<source><![CDATA[<element>
|
||||
<path value="Patient.extension"/>
|
||||
<name value="extension"/>
|
||||
<slicing>
|
||||
<discriminator value="url"/>
|
||||
<ordered value="false"/>
|
||||
<rules value="open"/>
|
||||
</slicing>
|
||||
<definition>
|
||||
<type>
|
||||
<code value="Extension"/>
|
||||
</type>
|
||||
</definition>
|
||||
</element>
|
||||
<element>
|
||||
<path value="Patient.extension"/>
|
||||
<name value="extension"/>
|
||||
<definition>
|
||||
<short value="The name of the patient's favourite pet"/>
|
||||
<min value="0"/>
|
||||
<max value="1"/>
|
||||
<type>
|
||||
<code value="Extension"/>
|
||||
<profile value="http://example.com/dontuse#petname"/>
|
||||
</type>
|
||||
<isModifier value="false"/>
|
||||
</definition>
|
||||
</element>
|
||||
<element>
|
||||
<path value="Patient.modifierExtension"/>
|
||||
<name value="modifierExtension"/>
|
||||
<slicing>
|
||||
<discriminator value="url"/>
|
||||
<ordered value="false"/>
|
||||
<rules value="open"/>
|
||||
</slicing>
|
||||
<definition>
|
||||
<type>
|
||||
<code value="Extension"/>
|
||||
</type>
|
||||
</definition>
|
||||
</element>
|
||||
<element>
|
||||
<path value="Patient.modifierExtension"/>
|
||||
<name value="modifierExtension"/>
|
||||
<definition>
|
||||
<short value="Some dates of note for the patient"/>
|
||||
<min value="0"/>
|
||||
<max value="*"/>
|
||||
<type>
|
||||
<code value="Extension"/>
|
||||
<profile value="http://example.com/dontuse#importantDates"/>
|
||||
</type>
|
||||
<isModifier value="true"/>
|
||||
</definition>
|
||||
</element>]]></source>
|
||||
|
||||
<macro name="snippet">
|
||||
<param name="id" value="customTypeClientSimple" />
|
||||
<param name="file" value="examples/src/main/java/example/ExtensionsDstu3.java" />
|
||||
</macro>
|
||||
|
||||
</subsection>
|
||||
|
||||
</section>
|
||||
|
|
Loading…
Reference in New Issue