diff --git a/.gitignore b/.gitignore index 2a64f04d425..3f1190ec6c7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ Servers/ *.log* nohup.out .DS_Store +*.orig # Vagrant stuff. .vagrant diff --git a/examples/src/main/java/example/GenericClientExample.java b/examples/src/main/java/example/GenericClientExample.java index 1c0b4de6569..135253caf6e 100644 --- a/examples/src/main/java/example/GenericClientExample.java +++ b/examples/src/main/java/example/GenericClientExample.java @@ -74,30 +74,30 @@ public class GenericClientExample { // END SNIPPET: create } { - Patient patient = new Patient(); - // START SNIPPET: createConditional - // One form - MethodOutcome outcome = client.create() - .resource(patient) - .conditionalByUrl("Patient?identifier=system%7C00001") - .execute(); + Patient patient = new Patient(); + // START SNIPPET: createConditional + // One form + MethodOutcome outcome = client.create() + .resource(patient) + .conditionalByUrl("Patient?identifier=system%7C00001") + .execute(); - // Another form - MethodOutcome outcome2 = client.create() - .resource(patient) - .conditional() - .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001")) - .execute(); - - // This will return true if the server responded with an HTTP 201 created, - // otherwise it will return null. - Boolean created = outcome.getCreated(); - - // The ID of the created, or the pre-existing resource - IdDt id = outcome.getId(); - // END SNIPPET: createConditional + // Another form + MethodOutcome outcome2 = client.create() + .resource(patient) + .conditional() + .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001")) + .execute(); + + // This will return true if the server responded with an HTTP 201 created, + // otherwise it will return null. + Boolean created = outcome.getCreated(); + + // The ID of the created, or the pre-existing resource + IdDt id = outcome.getId(); + // END SNIPPET: createConditional } - { + { // START SNIPPET: update Patient patient = new Patient(); // ..populate the patient object.. @@ -125,21 +125,21 @@ public class GenericClientExample { // END SNIPPET: update } { - Patient patient = new Patient(); - // START SNIPPET: updateConditional - client.update() - .resource(patient) - .conditionalByUrl("Patient?identifier=system%7C00001") - .execute(); - - client.update() - .resource(patient) - .conditional() - .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001")) - .execute(); - // END SNIPPET: updateConditional + Patient patient = new Patient(); + // START SNIPPET: updateConditional + client.update() + .resource(patient) + .conditionalByUrl("Patient?identifier=system%7C00001") + .execute(); + + client.update() + .resource(patient) + .conditional() + .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001")) + .execute(); + // END SNIPPET: updateConditional } - { + { // START SNIPPET: etagupdate // First, let's retrive the latest version of a resource // from the server @@ -176,26 +176,26 @@ public class GenericClientExample { } { // START SNIPPET: delete - BaseOperationOutcome resp = client.delete().resourceById(new IdDt("Patient", "1234")).execute(); + BaseOperationOutcome resp = client.delete().resourceById(new IdDt("Patient", "1234")).execute(); // outcome may be null if the server didn't return one - if (resp != null) { - OperationOutcome outcome = (OperationOutcome) resp; + if (resp != null) { + OperationOutcome outcome = (OperationOutcome) resp; System.out.println(outcome.getIssueFirstRep().getDetailsElement().getValue()); } // END SNIPPET: delete } - { - // START SNIPPET: deleteConditional - client.delete() - .resourceConditionalByUrl("Patient?identifier=system%7C00001") - .execute(); - - client.delete() - .resourceConditionalByType("Patient") - .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001")) - .execute(); - // END SNIPPET: deleteConditional + { + // START SNIPPET: deleteConditional + client.delete() + .resourceConditionalByUrl("Patient?identifier=system%7C00001") + .execute(); + + client.delete() + .resourceConditionalByType("Patient") + .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001")) + .execute(); + // END SNIPPET: deleteConditional } { // START SNIPPET: search diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 5ec4621fa18..906337f3cd4 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -63,20 +63,22 @@ org.slf4j slf4j-android ${slf4j_version} - provided - - + + org.slf4j + slf4j-api + ${slf4j_version} + test + commons-io commons-io ${commons_io_version} + test - + javax.servlet javax.servlet-api @@ -135,11 +137,10 @@ true - + commons-codec:commons-codec - commons-io:commons-io ca.uhn.hapi.fhir:hapi-fhir-base ca.uhn.hapi.fhir:hapi-fhir-structures-dstu ca.uhn.hapi.fhir:hapi-fhir-structures-dstu2 @@ -148,7 +149,7 @@ javax.xml.stream:stax-api javax.servlet:javax.servlet-api org.codehaus.woodstox:stax2-api - + org.apache.commons:* org.apache.httpcomponents:* org.glassfish:javax.json @@ -179,7 +180,7 @@ - + DIST @@ -208,5 +209,5 @@ - + diff --git a/hapi-fhir-android/src/main/java/ca/uhn/fhir/android/AndroidLoader.java b/hapi-fhir-android/src/main/java/ca/uhn/fhir/android/AndroidLoader.java new file mode 100644 index 00000000000..f7e1b685601 --- /dev/null +++ b/hapi-fhir-android/src/main/java/ca/uhn/fhir/android/AndroidLoader.java @@ -0,0 +1,14 @@ +package ca.uhn.fhir.android; + +import ca.uhn.fhir.context.FhirContext; + +public class AndroidLoader { + + public static void main(String[] theArgs) { + FhirContext ctx = FhirContext.forDstu2(); + ctx.newJsonParser(); + ctx.newXmlParser(); + ctx.newRestfulGenericClient(""); + } + +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java index d9c574f2675..00765a8ce83 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildChoiceDefinition.java @@ -85,29 +85,34 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini for (Class next : myChoiceTypes) { String elementName; - String alternateElementName = null; BaseRuntimeElementDefinition nextDef; if (IBaseResource.class.isAssignableFrom(next)) { elementName = getElementName() + StringUtils.capitalize(next.getSimpleName()); - alternateElementName = getElementName() + "Reference"; List> types = new ArrayList>(); types.add((Class) next); nextDef = new RuntimeResourceReferenceDefinition(elementName, types); nextDef.sealAndInitialize(theContext, theClassToElementDefinitions); + + myNameToChildDefinition.put(getElementName() + "Reference", nextDef); + myNameToChildDefinition.put(getElementName() + "Resource", nextDef); + } else { nextDef = theClassToElementDefinitions.get(next); elementName = getElementName() + StringUtils.capitalize(nextDef.getName()); } myNameToChildDefinition.put(elementName, nextDef); - if (alternateElementName != null) { - myNameToChildDefinition.put(alternateElementName, nextDef); - } if (IBaseResource.class.isAssignableFrom(next)) { Class refType = theContext.getVersion().getResourceReferenceType(); myDatatypeToElementDefinition.put(refType, nextDef); - alternateElementName = getElementName() + "Reference"; + + String alternateElementName; + if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) { + alternateElementName = getElementName() + "Resource"; + } else { + alternateElementName = getElementName() + "Reference"; + } myDatatypeToElementName.put(refType, alternateElementName); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildUndeclaredExtensionDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildUndeclaredExtensionDefinition.java index 0beae3a5f75..95418e9832c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildUndeclaredExtensionDefinition.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/RuntimeChildUndeclaredExtensionDefinition.java @@ -38,6 +38,8 @@ import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildDefinition { + private static final String VALUE_REFERENCE = "valueReference"; + private static final String VALUE_RESOURCE = "valueResource"; private Map> myAttributeNameToDefinition; private Map, String> myDatatypeToAttributeName; private Map, BaseRuntimeElementDefinition> myDatatypeToDefinition; @@ -53,7 +55,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD public List getValues(Object theTarget) { ExtensionDt target = (ExtensionDt) theTarget; if (target.getValue() != null) { - return Collections.singletonList((IBase)target.getValue()); + return Collections.singletonList((IBase) target.getValue()); } ArrayList retVal = new ArrayList(target.getUndeclaredExtensions()); return retVal; @@ -118,10 +120,10 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD for (BaseRuntimeElementDefinition next : theClassToElementDefinitions.values()) { if (next instanceof IRuntimeDatatypeDefinition) { -// if (next.getName().equals("CodeableConcept")) { -// System.out.println(); -// } - + // if (next.getName().equals("CodeableConcept")) { + // System.out.println(); + // } + if (!((IRuntimeDatatypeDefinition) next).isSpecialization()) { String attrName = createExtensionChildName(next); datatypeAttributeNameToDefinition.put(attrName, next); @@ -142,22 +144,29 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD } /* - * Resource reference - The correct name is 'valueReference', but - * we allow for valueResource because some incorrect parsers may use this + * Resource reference - The correct name is 'valueReference' in DSTU2 and 'valueResource' in DSTU1 */ - addReferenceBinding(theContext, theClassToElementDefinitions, "valueResource"); - addReferenceBinding(theContext, theClassToElementDefinitions, "valueReference"); + addReferenceBinding(theContext, theClassToElementDefinitions, VALUE_RESOURCE); + addReferenceBinding(theContext, theClassToElementDefinitions, VALUE_REFERENCE); } private void addReferenceBinding(FhirContext theContext, Map, BaseRuntimeElementDefinition> theClassToElementDefinitions, String value) { - myDatatypeToAttributeName.put(theContext.getVersion().getResourceReferenceType(), value); List> types = new ArrayList>(); types.add(IBaseResource.class); RuntimeResourceReferenceDefinition def = new RuntimeResourceReferenceDefinition(value, types); def.sealAndInitialize(theContext, theClassToElementDefinitions); + myAttributeNameToDefinition.put(value, def); - myDatatypeToDefinition.put(BaseResourceReferenceDt.class, def); - myDatatypeToDefinition.put(theContext.getVersion().getResourceReferenceType(), def); + /* + * Resource reference - The correct name is 'valueReference' in DSTU2 and 'valueResource' in DSTU1 + */ + boolean dstu1 = (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)); + if ((dstu1 && (value != VALUE_REFERENCE)) || (!dstu1 && (value != VALUE_RESOURCE))) { + myDatatypeToAttributeName.put(theContext.getVersion().getResourceReferenceType(), value); + myDatatypeToDefinition.put(BaseResourceReferenceDt.class, def); + myDatatypeToDefinition.put(theContext.getVersion().getResourceReferenceType(), def); + } + } public static String createExtensionChildName(BaseRuntimeElementDefinition next) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java index a57b1f79c96..285307e5adc 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/Bundle.java @@ -293,6 +293,7 @@ public class Bundle extends BaseBundle /* implements IElement */{ return myLinkSelf; } + /* public InstantDt getPublished() { InstantDt retVal = (InstantDt) getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); if (retVal == null) { @@ -301,6 +302,7 @@ public class Bundle extends BaseBundle /* implements IElement */{ } return retVal; } + */ /** * Retrieves a resource from a bundle given its logical ID. @@ -394,9 +396,11 @@ public class Bundle extends BaseBundle /* implements IElement */{ myCategories = theCategories; } + /* public void setPublished(InstantDt thePublished) { getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, thePublished); } + /* public void setType(BoundCodeDt theType) { myType = theType; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java index e8e7917b247..212e6234e07 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java @@ -20,7 +20,7 @@ package ca.uhn.fhir.model.api; * #L% */ -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.util.ArrayList; import java.util.Collections; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index a5ac3b2a5ca..d446148bf6b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -95,19 +95,20 @@ import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.model.base.composite.BaseContainedDt; import ca.uhn.fhir.model.base.composite.BaseNarrativeDt; import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; +import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.model.primitive.DecimalDt; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.IntegerDt; import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.model.primitive.XhtmlDt; import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.util.ElementUtil; import ca.uhn.fhir.util.UrlUtil; /** - * This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use - * {@link FhirContext#newJsonParser()} to get an instance. + * This class is the FHIR JSON parser/encoder. Users should not interact with this class directly, but should use {@link FhirContext#newJsonParser()} to get an instance. */ public class JsonParser extends BaseParser implements IParser { @@ -196,7 +197,6 @@ public class JsonParser extends BaseParser implements IParser { writeTagWithTextNode(eventWriter, "title", theBundle.getTitle()); writeTagWithTextNode(eventWriter, "id", theBundle.getBundleId()); writeOptionalTagWithTextNode(eventWriter, "updated", theBundle.getUpdated()); - writeOptionalTagWithTextNode(eventWriter, "published", theBundle.getPublished()); boolean linkStarted = false; linkStarted = writeAtomLinkInDstu1Format(eventWriter, "self", theBundle.getLinkSelf(), linkStarted); @@ -353,7 +353,8 @@ public class JsonParser extends BaseParser implements IParser { theEventWriter.writeEnd(); } - private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, BaseRuntimeElementDefinition theChildDef, String theChildName, boolean theIsSubElementWithinResource) throws IOException { + private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theWriter, IBase theNextValue, + BaseRuntimeElementDefinition theChildDef, String theChildName, boolean theContainedResource) throws IOException { switch (theChildDef.getChildType()) { case ID_DATATYPE: { @@ -414,7 +415,7 @@ public class JsonParser extends BaseParser implements IParser { if (theNextValue instanceof IBaseExtension) { theWriter.write("url", ((IBaseExtension) theNextValue).getUrl()); } - encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theWriter, childCompositeDef, theIsSubElementWithinResource); + encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theWriter, childCompositeDef, theContainedResource); theWriter.writeEnd(); break; } @@ -488,7 +489,8 @@ public class JsonParser extends BaseParser implements IParser { } - private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, List theChildren, boolean theIsSubElementWithinResource) throws IOException { + private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, + List theChildren, boolean theContainedResource) throws IOException { for (BaseRuntimeChildDefinition nextChild : theChildren) { if (nextChild.getElementName().equals("extension") || nextChild.getElementName().equals("modifierExtension")) { continue; @@ -507,15 +509,15 @@ public class JsonParser extends BaseParser implements IParser { RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild; String childName = nextChild.getChildNameByDatatype(child.getDatatype()); BaseRuntimeElementDefinition type = child.getChildByName(childName); - encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theIsSubElementWithinResource); + encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theContainedResource); continue; } } } else if (nextChild instanceof RuntimeChildContainedResources) { - if (theIsSubElementWithinResource == false) { + if (theContainedResource == false) { String childName = nextChild.getValidChildNames().iterator().next(); BaseRuntimeElementDefinition child = nextChild.getChildByName(childName); - encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theIsSubElementWithinResource); + encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theContainedResource); } continue; } @@ -535,7 +537,7 @@ public class JsonParser extends BaseParser implements IParser { for (IBase nextValue : values) { if (nextValue == null || nextValue.isEmpty()) { if (nextValue instanceof BaseContainedDt) { - if (theIsSubElementWithinResource || getContainedResources().isEmpty()) { + if (theContainedResource || getContainedResources().isEmpty()) { continue; } } else { @@ -551,7 +553,7 @@ public class JsonParser extends BaseParser implements IParser { } boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE; - if ((childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES||childDef.getChildType()==ChildTypeEnum.CONTAINED_RESOURCE_LIST) && theIsSubElementWithinResource) { + if ((childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES||childDef.getChildType()==ChildTypeEnum.CONTAINED_RESOURCE_LIST) && theContainedResource) { continue; } @@ -573,15 +575,15 @@ public class JsonParser extends BaseParser implements IParser { if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) { theEventWriter.writeStartArray(childName); inArray = true; - encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theIsSubElementWithinResource); - } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theIsSubElementWithinResource) { + encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource); + } else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) { // suppress narratives from contained resources } else { - encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theIsSubElementWithinResource); + encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource); } currentChildName = childName; } else { - encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theIsSubElementWithinResource); + encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource); } if (primitive) { @@ -655,13 +657,15 @@ public class JsonParser extends BaseParser implements IParser { } } - private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition resDef, boolean theIsSubElementWithinResource) throws IOException, DataFormatException { + private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter, + BaseRuntimeElementCompositeDefinition resDef, boolean theContainedResource) throws IOException, DataFormatException { extractAndWriteExtensionsAsDirectChild(theNextValue, theEventWriter, resDef, theResDef, theResource, null); - encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theIsSubElementWithinResource); - encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theIsSubElementWithinResource); + encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getExtensions(), theContainedResource); + encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, resDef.getChildren(), theContainedResource); } - private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource) throws IOException { + private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theContainedResource) + throws IOException { String resourceId = null; if (theResource instanceof IResource) { IResource res = (IResource) theResource; @@ -702,20 +706,22 @@ public class JsonParser extends BaseParser implements IParser { if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) { IResource resource = (IResource) theResource; + // Object securityLabelRawObj = + List securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS); + List profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES); + TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(resource); InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); IdDt resourceId = resource.getId(); String versionIdPart = resourceId.getVersionIdPart(); if (isBlank(versionIdPart)) { versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource); } - List securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS); - List profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES); - TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(resource); + if (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, profiles) == false) { theEventWriter.writeStartObject("meta"); - writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart()); - writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource)); + writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart); + writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated); if (profiles != null && profiles.isEmpty() == false) { theEventWriter.writeStartArray("profile"); @@ -1175,31 +1181,30 @@ public class JsonParser extends BaseParser implements IParser { } } - private void parseExtensionInDstu2Style(boolean theModifier, ParserState theState, String theParentExtensionUrl, String theExtensionUrl, JsonArray theValues) { - String extUrl = UrlUtil.constructAbsoluteUrl(theParentExtensionUrl, theExtensionUrl); - theState.enteringNewElementExtension(null, extUrl, theModifier); - - for (int extIdx = 0; extIdx < theValues.size(); extIdx++) { - JsonObject nextExt = theValues.getJsonObject(extIdx); - for (String nextKey : nextExt.keySet()) { - // if (nextKey.startsWith("value") && nextKey.length() > 5 && - // myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildByName(nextKey) != null) { - JsonValue jsonVal = nextExt.get(nextKey); - if (jsonVal.getValueType() == ValueType.ARRAY) { - /* - * Extension children which are arrays are sub-extensions. Any other value type should be treated as - * a value. - */ - JsonArray arrayValue = (JsonArray) jsonVal; - parseExtensionInDstu2Style(theModifier, theState, extUrl, nextKey, arrayValue); - } else { - parseChildren(theState, nextKey, jsonVal, null, null); - } - } - } - - theState.endingElement(); - } + // private void parseExtensionInDstu2Style(boolean theModifier, ParserState theState, String theParentExtensionUrl, String theExtensionUrl, JsonArray theValues) { + // String extUrl = UrlUtil.constructAbsoluteUrl(theParentExtensionUrl, theExtensionUrl); + // theState.enteringNewElementExtension(null, extUrl, theModifier); + // + // for (int extIdx = 0; extIdx < theValues.size(); extIdx++) { + // JsonObject nextExt = theValues.getJsonObject(extIdx); + // for (String nextKey : nextExt.keySet()) { + // // if (nextKey.startsWith("value") && nextKey.length() > 5 && + // // myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildByName(nextKey) != null) { + // JsonValue jsonVal = nextExt.get(nextKey); + // if (jsonVal.getValueType() == ValueType.ARRAY) { + // /* + // * Extension children which are arrays are sub-extensions. Any other value type should be treated as a value. + // */ + // JsonArray arrayValue = (JsonArray) jsonVal; + // parseExtensionInDstu2Style(theModifier, theState, extUrl, nextKey, arrayValue); + // } else { + // parseChildren(theState, nextKey, jsonVal, null, null); + // } + // } + // } + // + // theState.endingElement(); + // } @Override public T doParseResource(Class theResourceType, Reader theReader) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index 9e6fd5ef497..52d365804b8 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -683,8 +683,6 @@ class ParserState { public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException { if ("entry".equals(theLocalPart) && verifyNamespace(XmlParser.ATOM_NS, theNamespaceURI)) { push(new AtomEntryState(myInstance, myResourceType)); - } else if (theLocalPart.equals("published")) { - push(new AtomPrimitiveState(myInstance.getPublished())); } else if (theLocalPart.equals("title")) { push(new AtomPrimitiveState(myInstance.getTitle())); } else if ("id".equals(theLocalPart)) { @@ -900,7 +898,7 @@ class ParserState { if (myInstance instanceof IIdentifiableElement) { ((IIdentifiableElement) myInstance).setElementSpecificId((theValue)); } else { - ((IResource)myInstance).setId(new IdDt(theValue)); + ((IResource) myInstance).setId(new IdDt(theValue)); } } else if ("contentType".equals(theName)) { myInstance.setContentType(theValue); @@ -1393,7 +1391,7 @@ class ParserState { res.getId().setValue('#' + res.getId().getIdPart()); } } - + IBaseResource preResCurrentElement = getPreResourceState().getCurrentElement(); RuntimeResourceDefinition def = myContext.getResourceDefinition(preResCurrentElement); def.getChildByName("contained").getMutator().addValue(preResCurrentElement, res); @@ -1496,6 +1494,7 @@ class ParserState { private class ElementCompositeState extends BaseState { private BaseRuntimeElementCompositeDefinition myDefinition; + public BaseRuntimeElementCompositeDefinition getDefinition() { return myDefinition; } @@ -1623,8 +1622,8 @@ class ParserState { ParserState.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null); push(state); } else { - ParserState.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null); - push(state); + ParserState.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null); + push(state); } return; } @@ -1729,10 +1728,9 @@ class ParserState { } - private class SecurityLabelElementStateHapi extends ElementCompositeState { - public SecurityLabelElementStateHapi(ParserState.PreResourceState thePreResourceState,BaseRuntimeElementCompositeDefinition theDef, BaseCodingDt codingDt) { + public SecurityLabelElementStateHapi(ParserState.PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition theDef, BaseCodingDt codingDt) { super(thePreResourceState, theDef, codingDt); } @@ -1741,7 +1739,6 @@ class ParserState { pop(); } - } private class MetaElementState extends BaseState { @@ -1761,8 +1758,8 @@ class ParserState { public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException { if (theLocalPart.equals("versionId")) { push(new MetaVersionElementState(getPreResourceState(), myMap)); -// } else if (theLocalPart.equals("profile")) { -// + // } else if (theLocalPart.equals("profile")) { + // } else if (theLocalPart.equals("lastUpdated")) { InstantDt updated = new InstantDt(); push(new PrimitiveState(getPreResourceState(), updated)); @@ -1774,7 +1771,7 @@ class ParserState { securityLabels = new ArrayList(); myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels); } - BaseCodingDt securityLabel= myContext.getVersion().newCodingDt(); + BaseCodingDt securityLabel = myContext.getVersion().newCodingDt(); BaseRuntimeElementCompositeDefinition codinfDef = (BaseRuntimeElementCompositeDefinition) myContext.getElementDefinition(securityLabel.getClass()); push(new SecurityLabelElementStateHapi(getPreResourceState(), codinfDef, securityLabel)); securityLabels.add(securityLabel); @@ -1903,33 +1900,30 @@ class ParserState { if (myEntry == null) { myObject = (T) getCurrentElement(); } - + IResource nextResource = (IResource) getCurrentElement(); String version = ResourceMetadataKeyEnum.VERSION.get(nextResource); String resourceName = myContext.getResourceDefinition(nextResource).getName(); String bundleIdPart = nextResource.getId().getIdPart(); if (isNotBlank(bundleIdPart)) { -// if (isNotBlank(entryBaseUrl)) { -// nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version)); -// } else { - nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version)); -// } + // if (isNotBlank(entryBaseUrl)) { + // nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version)); + // } else { + nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version)); + // } } - } - - @Override public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException { super.enteringNewElement(theNamespaceURI, theLocalPart); if (myEntry != null) { myEntry.setResource((IResource) getCurrentElement()); } - if (myMutator != null) { - myMutator.addValue(myTarget, getCurrentElement()); - } + if (myMutator != null) { + myMutator.addValue(myTarget, getCurrentElement()); + } } } @@ -1956,13 +1950,15 @@ class ParserState { if (myTarget == null) { myObject = (T) getCurrentElement(); } - + if (getCurrentElement() instanceof IDomainResource) { IDomainResource elem = (IDomainResource) getCurrentElement(); String resourceName = myContext.getResourceDefinition(elem).getName(); String versionId = elem.getMeta().getVersionId(); - if (StringUtils.isNotBlank(versionId)) { - elem.getIdElement().setValue(resourceName + "/" + elem.getId().getIdPart() + "/_history/" + versionId); + if (StringUtils.isBlank(elem.getId().getIdPart())) { + // Resource has no ID + } else if (StringUtils.isNotBlank(versionId)) { + elem.getIdElement().setValue(resourceName + "/" + elem.getId().getIdPart() + "/_history/" + versionId); } else { elem.getIdElement().setValue(resourceName + "/" + elem.getId().getIdPart()); } @@ -2063,12 +2059,12 @@ class ParserState { @Override public void wereBack() { final boolean bundle = "Bundle".equals(myContext.getResourceDefinition(myInstance).getName()); - + FhirTerser terser = myContext.newTerser(); terser.visit(myInstance, new IModelVisitor() { @Override - public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { if (theElement instanceof BaseResourceReferenceDt) { BaseResourceReferenceDt nextRef = (BaseResourceReferenceDt) theElement; String ref = nextRef.getReference().getValue(); @@ -2082,7 +2078,7 @@ class ParserState { } } } - }else if (theElement instanceof IReference) { + } else if (theElement instanceof IReference) { IReference nextRef = (IReference) theElement; String ref = nextRef.getReference().getValue(); if (isNotBlank(ref)) { @@ -2099,8 +2095,8 @@ class ParserState { } @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { - acceptElement(theNextExt.getValue(), null, null); + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { + acceptElement(theNextExt.getValue(), null, null, null); } }); @@ -2132,7 +2128,7 @@ class ParserState { } } - + } } @@ -2547,13 +2543,12 @@ class ParserState { // TODO: this is not very efficient String value = getDt().getValueAsString(); myHl7OrgDatatype.setValueAsString(value); - + super.doPop(); } - - + } - + private class XhtmlState extends BaseState { private int myDepth; private XhtmlDt myDt; @@ -2583,7 +2578,7 @@ class ParserState { protected void doPop() { pop(); } - + @Override public void endingElement() throws DataFormatException { if (myJsonMode) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index e513f6035f9..7f304958395 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -271,7 +271,6 @@ public class XmlParser extends BaseParser implements IParser { } writeOptionalTagWithTextNode(eventWriter, "updated", theBundle.getUpdated()); - writeOptionalTagWithTextNode(eventWriter, "published", theBundle.getPublished()); if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) { eventWriter.writeStartElement("author"); @@ -804,6 +803,7 @@ public class XmlParser extends BaseParser implements IParser { if (updated != null) { writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString()); } + for (IdDt profile : profiles) { theEventWriter.writeStartElement("profile"); theEventWriter.writeAttribute("value", profile.getValue()); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java index 63e58755f95..70cf63a0f84 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/MethodOutcome.java @@ -135,7 +135,7 @@ public class MethodOutcome { } /** - * This will be set to {@link Boolean#TRUE} for instance of MethodOutcome which are + * This will be set to {@link Boolean#TRUE} for instance of MethodOutcome which are * returned to client instances, if the server has responded with an HTTP 201 Created. */ public Boolean getCreated() { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java index c2a595f64b6..f3d0a392719 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java @@ -20,8 +20,7 @@ package ca.uhn.fhir.rest.client; * #L% */ -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.io.IOException; import java.io.Reader; @@ -1413,7 +1412,7 @@ public class GenericClient extends BaseClient implements IGenericClient { + "the bundle return type for the client by adding \".returnBundle(org.hl7.fhir.instance.model.Bundle.class)\" to your search method call before the \".execute()\" method"); } - IClientResponseHandler binding; + IClientResponseHandler binding; if (myReturnBundleType != null) { binding = new ResourceResponseHandler(myReturnBundleType, null); } else { @@ -1581,8 +1580,8 @@ public class GenericClient extends BaseClient implements IGenericClient { myBundle = theResources; } - public TransactionExecutable(List theResources) { - myResources = theResources; + public TransactionExecutable(List theResources) { + myResources = new ArrayList(theResources); } public TransactionExecutable(IBaseBundle theBundle) { @@ -1619,7 +1618,7 @@ public class GenericClient extends BaseClient implements IGenericClient { } @Override - public ITransactionTyped> withResources(List theResources) { + public ITransactionTyped> withResources(List theResources) { Validate.notNull(theResources, "theResources must not be null"); return new TransactionExecutable>(theResources); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java index cbed783919a..4ffa1ef4dfe 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ITransaction.java @@ -32,7 +32,7 @@ public interface ITransaction { /** * Use a list of resources as the transaction input */ - ITransactionTyped> withResources(List theResources); + ITransactionTyped> withResources(List theResources); /** * Use a DSTU1 Bundle (Atom) as the transaction input diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java index aa86fdc744d..b1580912fd2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java @@ -279,7 +279,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding includes = getRequestIncludesFromParams(params); @@ -312,7 +312,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding resourceType) { - this.myDeclaredResourceType = resourceType; - } - @Override - public String toString() { - return getMethod().toString(); + protected boolean isAddContentLocationHeader() { + return false; } private List processWhitelistAndBlacklist(List theQualifiedNames, Set theQualifierWhitelist, Set theQualifierBlacklist) { @@ -313,6 +314,15 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding { return retVal; } + public void setResourceType(Class resourceType) { + this.myDeclaredResourceType = resourceType; + } + + @Override + public String toString() { + return getMethod().toString(); + } + public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map> theParameters, IdDt theId, String theCompartmentName, SearchStyleEnum theSearchStyle) { SearchStyleEnum searchStyle = theSearchStyle; @@ -473,9 +483,4 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding { } - @Override - protected BundleTypeEnum getResponseBundleType() { - return BundleTypeEnum.SEARCHSET; - } - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java index f27e6c5bc39..9bd60ec57c6 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java @@ -203,8 +203,6 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory { addResourcesToBundle(new ArrayList(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes); addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType); - myBundle.setPublished(theResult.getPublished()); - if (theServer.getPagingProvider() != null) { int limit; limit = theLimit != null ? theLimit : theServer.getPagingProvider().getDefaultPageSize(); @@ -232,10 +230,6 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory { myBundle.getBundleId().setValue(UUID.randomUUID().toString()); } - if (myBundle.getPublished().isEmpty()) { - myBundle.getPublished().setToCurrentTimeInLocalTimeZone(); - } - if (myBundle.getLinkBase().isEmpty()) { myBundle.getLinkBase().setValue(theServerBase); } @@ -269,7 +263,6 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory { myBundle.getAuthorName().setValue(theAuthor); myBundle.getBundleId().setValue(UUID.randomUUID().toString()); - myBundle.getPublished().setToCurrentTimeInLocalTimeZone(); myBundle.getLinkBase().setValue(theServerBase); myBundle.getLinkSelf().setValue(theCompleteUrl); myBundle.getType().setValueAsEnum(theBundleType); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java index 6bcdacd5b22..793e80e23bd 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategy.java @@ -30,10 +30,19 @@ import org.apache.commons.lang3.StringUtils; */ public class IncomingRequestAddressStrategy implements IServerAddressStrategy { + private String myServletPath; + @Override public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) { String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI()); - String servletPath = StringUtils.defaultString(theRequest.getServletPath()); + + String servletPath; + if (myServletPath != null) { + servletPath = myServletPath; + } else { + servletPath = StringUtils.defaultString(theRequest.getServletPath()); + } + StringBuffer requestUrl = theRequest.getRequestURL(); String servletContextPath = ""; if (theServletContext != null) { @@ -48,7 +57,9 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy { } int startOfPath = requestUrl.indexOf("//"); - if (startOfPath != -1 && (startOfPath + 2) < requestUrl.length()) { + int requestUrlLength = requestUrl.length(); + + if (startOfPath != -1 && (startOfPath + 2) < requestUrlLength) { startOfPath = requestUrl.indexOf("/", startOfPath + 2); } if (startOfPath == -1) { @@ -56,9 +67,9 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy { } int contextIndex; - if (servletPath.length() == 0) { + if (servletPath.length() == 0 || servletPath.equals("/")) { if (requestPath.length() == 0) { - contextIndex = requestUrl.length(); + contextIndex = requestUrlLength; } else { contextIndex = requestUrl.indexOf(requestPath, startOfPath); } @@ -68,8 +79,30 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy { String fhirServerBase; int length = contextIndex + servletPath.length(); + if (length > requestUrlLength) { + length = requestUrlLength; + } fhirServerBase = requestUrl.substring(0, length); return fhirServerBase; } + /** + * If set to a non-null value (default is null), this address strategy assumes that the FHIR endpoint is deployed to the given servlet path within the context. This is useful in some + * deployments where it isn't obvious to the servlet which part of the path is actually the root path to reach the servlet. + *

+ * Example values could be: + *

    + *
  • null
  • + *
  • /
  • + *
  • /base
  • + *
+ *

+ *

+ * Wildcards are not supported! + *

+ */ + public void setServletPath(String theServletPath) { + myServletPath = theServletPath; + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java index 557a2d10b3e..5580492d90f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java @@ -490,7 +490,7 @@ public class RestfulServer extends HttpServlet { return; } } - RestfulServerUtils.streamResponseAsResource(this, theResponse, (IResource) resBundle, responseEncoding, prettyPrint, requestIsBrowser, narrativeMode, Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), theRequest.getFhirServerBase()); + RestfulServerUtils.streamResponseAsResource(this, theResponse, (IResource) resBundle, responseEncoding, prettyPrint, requestIsBrowser, narrativeMode, Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), theRequest.getFhirServerBase(), false); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java index 26daa5255cd..87df3587f3d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java @@ -76,10 +76,10 @@ public class RestfulServerUtils { } public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IBaseResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint, - boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, int stausCode, boolean theRespondGzip, String theServerBase) throws IOException { + boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, int stausCode, boolean theRespondGzip, String theServerBase, boolean theAddContentLocationHeader) throws IOException { theHttpResponse.setStatus(stausCode); - if (theResource.getId() != null && theResource.getId().hasIdPart() && isNotBlank(theServerBase)) { + if (theAddContentLocationHeader && theResource.getId() != null && theResource.getId().hasIdPart() && isNotBlank(theServerBase)) { String resName = theServer.getFhirContext().getResourceDefinition(theResource).getName(); IIdType fullId = theResource.getId().withServerBase(theServerBase, resName); theHttpResponse.addHeader(Constants.HEADER_CONTENT_LOCATION, fullId.getValue()); @@ -413,12 +413,12 @@ public class RestfulServerUtils { } } - public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IBaseResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint, - boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, boolean theRespondGzip, String theServerBase) throws IOException { - int stausCode = 200; - RestfulServerUtils.streamResponseAsResource(theServer, theHttpResponse, theResource, theResponseEncoding, thePrettyPrint, theRequestIsBrowser, theNarrativeMode, stausCode, theRespondGzip, - theServerBase); - } +// public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint, +// boolean theRequestIsBrowser, RestfulServer.NarrativeModeEnum theNarrativeMode, boolean theRespondGzip, String theServerBase) throws IOException { +// int stausCode = 200; +// RestfulServerUtils.streamResponseAsResource(theServer, theHttpResponse, theResource, theResponseEncoding, thePrettyPrint, theRequestIsBrowser, theNarrativeMode, stausCode, theRespondGzip, +// theServerBase); +// } public static void validateResourceListNotNull(List theResourceList) { if (theResourceList == null) { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java index a8987477d3c..8737104ff11 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java @@ -129,7 +129,7 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter { boolean requestIsBrowser = RestfulServer.requestIsBrowser(theRequest); String fhirServerBase = ((Request) theRequestDetails).getFhirServerBase(); RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), theResponse, oo, RestfulServerUtils.determineResponseEncodingNoDefault(theRequest), true, requestIsBrowser, - NarrativeModeEnum.NORMAL, statusCode, false, fhirServerBase); + NarrativeModeEnum.NORMAL, statusCode, false, fhirServerBase, false); // theResponse.setStatus(statusCode); // theRequestDetails.getServer().addHeadersToResponse(theResponse); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java.orig b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java.orig deleted file mode 100644 index 9e81a04ae44..00000000000 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/ExceptionHandlingInterceptor.java.orig +++ /dev/null @@ -1,172 +0,0 @@ -package ca.uhn.fhir.rest.server.interceptor; - -/* - * #%L - * HAPI FHIR - Core Library - * %% - * 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 static org.apache.commons.lang3.StringUtils.isNotBlank; - -import java.io.IOException; -import java.util.Map; -import java.util.Map.Entry; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang3.exception.ExceptionUtils; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; -import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue; -import ca.uhn.fhir.rest.method.Request; -import ca.uhn.fhir.rest.method.RequestDetails; -import ca.uhn.fhir.rest.server.Constants; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.RestfulServer.NarrativeModeEnum; -import ca.uhn.fhir.rest.server.RestfulServerUtils; -import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; - -public class ExceptionHandlingInterceptor extends InterceptorAdapter { - - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExceptionHandlingInterceptor.class); - private Class[] myReturnStackTracesForExceptionTypes; - - /** - * If any server methods throw an exception which extends any of the given exception types, the exception - * stack trace will be returned to the user. This can be useful for helping to diagnose issues, but may - * not be desirable for production situations. - * - * @param theExceptionTypes The exception types for which to return the stack trace to the user. - * @return Returns an instance of this interceptor, to allow for easy method chaining. - */ - public ExceptionHandlingInterceptor setReturnStackTracesForExceptionTypes(Class... theExceptionTypes) { - myReturnStackTracesForExceptionTypes = theExceptionTypes; - return this; - } - - @Override -<<<<<<< HEAD - public boolean handleException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException { -======= - public boolean handleException(RestfulServer theRestfulServer, RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException { - ourLog.error("AA", theException); ->>>>>>> 5956ab75fd9186ccc8b9836b60bc421b19d3d288 - BaseOperationOutcome oo = null; - int statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR; - - FhirContext ctx = theRestfulServer.getFhirContext(); - - if (theException instanceof BaseServerResponseException) { - oo = ((BaseServerResponseException) theException).getOperationOutcome(); - statusCode = ((BaseServerResponseException) theException).getStatusCode(); - } - - /* - * Generate an OperationOutcome to return, unless the exception throw by the resource provider had one - */ - if (oo == null) { - try { - oo = (BaseOperationOutcome) ctx.getResourceDefinition("OperationOutcome").getImplementingClass().newInstance(); - } catch (Exception e1) { - ourLog.error("Failed to instantiate OperationOutcome resource instance", e1); - throw new ServletException("Failed to instantiate OperationOutcome resource instance", e1); - } - - BaseIssue issue = oo.addIssue(); - issue.getSeverityElement().setValue("error"); - if (theException instanceof InternalErrorException) { - ourLog.error("Failure during REST processing", theException); - populateDetails(theException, issue); - } else if (theException instanceof BaseServerResponseException) { - ourLog.warn("Failure during REST processing: {}", theException); - BaseServerResponseException baseServerResponseException = (BaseServerResponseException) theException; - statusCode = baseServerResponseException.getStatusCode(); - populateDetails(theException, issue); - if (baseServerResponseException.getAdditionalMessages() != null) { - for (String next : baseServerResponseException.getAdditionalMessages()) { - BaseIssue issue2 = oo.addIssue(); - issue2.getSeverityElement().setValue("error"); - issue2.setDetails(next); - } - } - } else { - ourLog.error("Failure during REST processing: " + theException.toString(), theException); - populateDetails(theException, issue); - statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR; - } - } else { - ourLog.error("Unknown error during processing", theException); - } - - // Add headers associated with the specific error code - if (theException instanceof BaseServerResponseException) { - Map additional = ((BaseServerResponseException) theException).getAssociatedHeaders(); - if (additional != null) { - for (Entry next : additional.entrySet()) { - if (isNotBlank(next.getKey()) && next.getValue() != null) { - String nextKey = next.getKey(); - for (String nextValue : next.getValue()) { - theResponse.addHeader(nextKey, nextValue); - } - } - } - } - } - - boolean requestIsBrowser = RestfulServer.requestIsBrowser(theRequest); - String fhirServerBase = theRestfulServer.getServerBaseForRequest(theRequest); - - RestfulServerUtils.streamResponseAsResource(theRestfulServer, theResponse, oo, RestfulServerUtils.determineResponseEncodingNoDefault(theRequest), true, requestIsBrowser, - NarrativeModeEnum.NORMAL, statusCode, false, fhirServerBase); - -<<<<<<< HEAD -// theResponse.setStatus(statusCode); -// theRequestDetails.getServer().addHeadersToResponse(theResponse); -// theResponse.setContentType("text/plain"); -// theResponse.setCharacterEncoding("UTF-8"); -// theResponse.getWriter().append(theException.getMessage()); -// theResponse.getWriter().close(); -======= - theResponse.setStatus(statusCode); - theRestfulServer.addHeadersToResponse(theResponse); - theResponse.setContentType("text/plain"); - theResponse.setCharacterEncoding("UTF-8"); - theResponse.getWriter().append(theException.getMessage()); - theResponse.getWriter().close(); ->>>>>>> 5956ab75fd9186ccc8b9836b60bc421b19d3d288 - - return false; - } - - private void populateDetails(Throwable theException, BaseIssue issue) { - if (myReturnStackTracesForExceptionTypes != null) { - for (Class next : myReturnStackTracesForExceptionTypes) { - if (next.isAssignableFrom(theException.getClass())) { - issue.getDetailsElement().setValue(theException.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(theException)); - return; - } - } - } - - issue.getDetailsElement().setValue(theException.getMessage()); - } - -} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java index f3d5a40984c..ee43923212b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java @@ -61,7 +61,7 @@ public class FhirTerser { if (theElement instanceof ISupportsUndeclaredExtensions) { ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement; for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) { - theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt); + theCallback.acceptUndeclaredExtension(containingElement, null, theChildDefinition, theDefinition, nextExt); addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback); } } @@ -90,10 +90,10 @@ public class FhirTerser { public List getAllPopulatedChildElementsOfType(IBaseResource theResource, final Class theType) { final ArrayList retVal = new ArrayList(); BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, new IModelVisitor() { + visit(theResource, null, null, def, new IModelVisitor() { @SuppressWarnings("unchecked") @Override - public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { if (theElement == null || theElement.isEmpty()) { return; } @@ -105,7 +105,8 @@ public class FhirTerser { @SuppressWarnings("unchecked") @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, + ExtensionDt theNextExt) { if (theType.isAssignableFrom(theNextExt.getClass())) { retVal.add((T) theNextExt); } @@ -117,39 +118,34 @@ public class FhirTerser { return retVal; } - public List getAllResourceReferences(final IBaseResource theResource) { - final ArrayList retVal = new ArrayList(); - BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, new IModelVisitor() { - @Override - public void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { - if (theElement == null || theElement.isEmpty()) { - return; - } - String name = null; - if (theChildDefinition != null) { - name = theChildDefinition.getElementName(); - } - if (BaseResourceReferenceDt.class.isAssignableFrom(theElement.getClass())) { - retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt) theElement)); - } - } + public List getAllResourceReferences(final IBaseResource theResource) { + final ArrayList retVal = new ArrayList(); + BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); + visit(theResource, null, null, def, new IModelVisitor() { + @SuppressWarnings("unchecked") + @Override + public void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + if (theElement == null || theElement.isEmpty()) { + return; + } + if (BaseResourceReferenceDt.class.isAssignableFrom(theElement.getClass())) { + retVal.add(new ResourceReferenceInfo(theResource, thePathToElement, (BaseResourceReferenceDt)theElement)); + } + } - @Override - public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt) { - String name = null; - if (theChildDefinition != null) { - name = theChildDefinition.getElementName(); - } - if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) { - retVal.add(new ResourceReferenceInfo(theResource, name, (BaseResourceReferenceDt) theNextExt.getValue())); - } - } - }); - return retVal; - } + @SuppressWarnings("unchecked") + @Override + public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, + ExtensionDt theNextExt) { + if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) { + retVal.add(new ResourceReferenceInfo(theResource, thePathToElement, (BaseResourceReferenceDt)theNextExt.getValue())); + } + } + }); + return retVal; + } - private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition theCurrentDef, List theSubList) { + private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition theCurrentDef, List theSubList) { BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0)); if (theSubList.size() == 1) { @@ -222,8 +218,19 @@ public class FhirTerser { } - private void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, IModelVisitor theCallback) { - theCallback.acceptElement(theElement, theChildDefinition, theDefinition); + private List addNameToList(List theCurrentList, BaseRuntimeChildDefinition theChildDefinition) { + if (theChildDefinition == null) + return null; + if (theCurrentList== null || theCurrentList.isEmpty()) + return new ArrayList(Arrays.asList(theChildDefinition.getElementName())); + List newList = new ArrayList(theCurrentList); + newList.add(theChildDefinition.getElementName()); + return newList; + } + + private void visit(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, IModelVisitor theCallback) { + List pathToElement = addNameToList(thePathToElement, theChildDefinition); + theCallback.acceptElement(theElement, pathToElement, theChildDefinition, theDefinition); addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback); // if (theElement.isEmpty()) { @@ -243,7 +250,7 @@ public class FhirTerser { IBaseResource theResource = resRefDt.getResource(); if (theResource.getId() == null || theResource.getId().isEmpty() || theResource.getId().isLocal()) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, theCallback); + visit(theResource, pathToElement, null, def, theCallback); } } break; @@ -285,9 +292,9 @@ public class FhirTerser { if (nextChild instanceof RuntimeChildDirectResource) { // Don't descend into embedded resources - theCallback.acceptElement(nextValue, nextChild, childElementDef); + theCallback.acceptElement(nextValue, null, nextChild, childElementDef); } else { - visit(nextValue, nextChild, childElementDef, theCallback); + visit(nextValue, pathToElement, nextChild, childElementDef, theCallback); } } } @@ -298,7 +305,7 @@ public class FhirTerser { BaseContainedDt value = (BaseContainedDt) theElement; for (IResource next : value.getContainedResources()) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(next); - visit(next, null, def, theCallback); + visit(next, pathToElement, null, def, theCallback); } break; } @@ -309,7 +316,7 @@ public class FhirTerser { case CONTAINED_RESOURCE_LIST: if (theElement != null) { BaseRuntimeElementDefinition def = myContext.getElementDefinition(theElement.getClass()); - visit(theElement, null, def, theCallback); + visit(theElement, pathToElement, null, def, theCallback); } break; } @@ -454,7 +461,7 @@ public class FhirTerser { */ public void visit(IBaseResource theResource, IModelVisitor theVisitor) { BaseRuntimeElementCompositeDefinition def = myContext.getResourceDefinition(theResource); - visit(theResource, null, def, theVisitor); + visit(theResource, null, null, def, theVisitor); } /** diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java index f183f8ee4d4..518080aab93 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor.java @@ -28,6 +28,8 @@ import ca.uhn.fhir.context.BaseRuntimeElementDefinition; import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; +import java.util.List; + /** * @see FhirTerser#visit(IBaseResource, IModelVisitor) */ @@ -39,7 +41,7 @@ public interface IModelVisitor { * @param theChildDefinition May be null if this is a root element * @param theDefinition */ - void acceptElement(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition); + void acceptElement(IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition); /** * @@ -48,7 +50,7 @@ public interface IModelVisitor { * @param theDefinition * @param theNextExt */ - void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt); + void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition, ExtensionDt theNextExt); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java index 1c634d695fa..fd50f9f5a81 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ResourceReferenceInfo.java @@ -28,58 +28,71 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.hl7.fhir.instance.model.IBaseResource; +import java.util.Iterator; +import java.util.List; import java.util.Set; /** * Created by Bill de Beaubien on 2/26/2015. */ public class ResourceReferenceInfo { - private String myOwningResource; - private String myName; - private BaseResourceReferenceDt myResource; + private String myOwningResource; + private String myName; + private BaseResourceReferenceDt myResource; - public ResourceReferenceInfo(IBaseResource theOwningResource, String theName, BaseResourceReferenceDt theResource) { - myOwningResource = theOwningResource.getClass().getAnnotation(ResourceDef.class).name(); - myName = theName; - myResource = theResource; - } + public ResourceReferenceInfo(IBaseResource theOwningResource, List thePathToElement, BaseResourceReferenceDt theResource) { + myOwningResource = theOwningResource.getClass().getAnnotation(ResourceDef.class).name(); + myResource = theResource; + if (thePathToElement != null && !thePathToElement.isEmpty()) { + StringBuilder sb = new StringBuilder(); + thePathToElement.iterator(); + for (Iterator iterator = thePathToElement.iterator(); iterator.hasNext(); ) { + sb.append(iterator.next()); + if (iterator.hasNext()) + sb.append("."); + } + myName = sb.toString(); + } else { + myName = null; + } + } - @Override - public String toString() { - ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); - b.append("name", myName); - b.append("resource", myResource.getReference()); - return b.build(); - } + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); + b.append("name", myName); + b.append("resource", myResource.getReference()); + return b.build(); + } - public String getName() { - return myName; - } + public String getName() { + return myName; + } - public BaseResourceReferenceDt getResourceReference() { - return myResource; - } + public BaseResourceReferenceDt getResourceReference() { + return myResource; + } - public boolean matchesIncludeSet(Set theIncludes) { - if (theIncludes == null) - return false; - for (Include include : theIncludes) { - if (matchesInclude(include)) - return true; - } - return false; - } + public boolean matchesIncludeSet(Set theIncludes) { + if (theIncludes == null) + return false; + for (Include include : theIncludes) { + if (matchesInclude(include)) + return true; + } + return false; + } - public boolean matchesInclude(Include theInclude) { - if (theInclude.getValue().equals("*")) { - return true; - } - if (theInclude.getValue().indexOf(':') != -1) { - // DSTU2 style - return (theInclude.getValue().equals(myOwningResource + ':' + myName)); - } else { - // DSTU1 style - return (theInclude.getValue().equals(myOwningResource + '.' + myName)); - } - } + public boolean matchesInclude(Include theInclude) { + if (theInclude.getValue().equals("*")) { + return true; + } + if (theInclude.getValue().indexOf(':') != -1) { + // DSTU2 style + return (theInclude.getValue().equals(myOwningResource + ':' + myName)); + } else { + // DSTU1 style + return (theInclude.getValue().equals(myOwningResource + '.' + myName)); + } + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java index 6f9b45405c2..b4a58ff2c61 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirDao.java @@ -20,8 +20,7 @@ package ca.uhn.fhir.jpa.dao; * #L% */ -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -444,12 +443,12 @@ public abstract class BaseFhirDao implements IDao { } @Override - public List getResources(final int theFromIndex, final int theToIndex) { + public List getResources(final int theFromIndex, final int theToIndex) { final StopWatch timer = new StopWatch(); TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager); - return template.execute(new TransactionCallback>() { + return template.execute(new TransactionCallback>() { @Override - public List doInTransaction(TransactionStatus theStatus) { + public List doInTransaction(TransactionStatus theStatus) { List resEntities = Lists.newArrayList(); List tupleSubList = tuples.subList(theFromIndex, theToIndex); @@ -471,7 +470,7 @@ public abstract class BaseFhirDao implements IDao { resEntities = resEntities.subList(0, limit); } - ArrayList retVal = new ArrayList(); + ArrayList retVal = new ArrayList(); for (BaseHasResource next : resEntities) { RuntimeResourceDefinition type; try { @@ -514,7 +513,7 @@ public abstract class BaseFhirDao implements IDao { return true; } - protected List loadResourcesById(Set theIncludePids) { + protected List loadResourcesById(Set theIncludePids) { Set pids = new HashSet(); for (IdDt next : theIncludePids) { if (next.isIdPartValidLong()) { @@ -528,6 +527,10 @@ public abstract class BaseFhirDao implements IDao { } } + if (pids.isEmpty()) { + return new ArrayList(); + } + CriteriaBuilder builder = myEntityManager.getCriteriaBuilder(); CriteriaQuery cq = builder.createQuery(ResourceTable.class); Root from = cq.from(ResourceTable.class); @@ -538,7 +541,7 @@ public abstract class BaseFhirDao implements IDao { // } TypedQuery q = myEntityManager.createQuery(cq); - ArrayList retVal = new ArrayList(); + ArrayList retVal = new ArrayList(); for (ResourceTable next : q.getResultList()) { IResource resource = (IResource) toResource(next); retVal.add(resource); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java index 935df209c6d..b530d8901e3 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseFhirResourceDao.java @@ -20,8 +20,7 @@ package ca.uhn.fhir.jpa.dao; * #L% */ -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.*; import java.math.BigDecimal; import java.util.ArrayList; @@ -660,12 +659,12 @@ public abstract class BaseFhirResourceDao extends BaseFhirD return new HashSet(q.getResultList()); } - private List addResourcesAsIncludesById(List theListToPopulate, Set includePids, List resources) { + private List addResourcesAsIncludesById(List theListToPopulate, Set includePids, List resources) { if (!includePids.isEmpty()) { ourLog.info("Loading {} included resources", includePids.size()); resources = loadResourcesById(includePids); - for (IResource next : resources) { - ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(next, BundleEntrySearchModeEnum.INCLUDE); + for (IBaseResource next : resources) { + ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put((IResource) next, BundleEntrySearchModeEnum.INCLUDE); } theListToPopulate.addAll(resources); } @@ -1000,7 +999,7 @@ public abstract class BaseFhirResourceDao extends BaseFhirD return tags; } - protected abstract List getIncludeValues(FhirTerser theTerser, Include theInclude, IResource theResource, RuntimeResourceDefinition theResourceDef); + protected abstract List getIncludeValues(FhirTerser theTerser, Include theInclude, IBaseResource theResource, RuntimeResourceDefinition theResourceDef); public Class getResourceType() { return myResourceType; @@ -1074,8 +1073,8 @@ public abstract class BaseFhirResourceDao extends BaseFhirD } @Override - public List getResources(int theFromIndex, int theToIndex) { - ArrayList retVal = new ArrayList(); + public List getResources(int theFromIndex, int theToIndex) { + List retVal = new ArrayList(); if (theFromIndex == 0 && current != null) { retVal.add(current); } @@ -1128,7 +1127,7 @@ public abstract class BaseFhirResourceDao extends BaseFhirD return retVal; } - private void loadResourcesByPid(Collection theIncludePids, List theResourceListToPopulate, BundleEntrySearchModeEnum theBundleEntryStatus) { + private void loadResourcesByPid(Collection theIncludePids, List theResourceListToPopulate, BundleEntrySearchModeEnum theBundleEntryStatus) { if (theIncludePids.isEmpty()) { return; } @@ -1520,15 +1519,15 @@ public abstract class BaseFhirResourceDao extends BaseFhirD } @Override - public List getResources(final int theFromIndex, final int theToIndex) { + public List getResources(final int theFromIndex, final int theToIndex) { TransactionTemplate template = new TransactionTemplate(myPlatformTransactionManager); - return template.execute(new TransactionCallback>() { + return template.execute(new TransactionCallback>() { @Override - public List doInTransaction(TransactionStatus theStatus) { + public List doInTransaction(TransactionStatus theStatus) { List pidsSubList = pids.subList(theFromIndex, theToIndex); // Execute the query and make sure we return distinct results - List retVal = new ArrayList(); + List retVal = new ArrayList(); loadResourcesByPid(pidsSubList, retVal, BundleEntrySearchModeEnum.MATCH); /* @@ -1538,18 +1537,18 @@ public abstract class BaseFhirResourceDao extends BaseFhirD */ if (theParams.getIncludes() != null && theParams.getIncludes().isEmpty() == false) { Set previouslyLoadedPids = new HashSet(); - for (IResource next : retVal) { - previouslyLoadedPids.add(next.getId().toUnqualifiedVersionless()); + for (IBaseResource next : retVal) { + previouslyLoadedPids.add((IdDt) next.getId().toUnqualifiedVersionless()); } Set includePids = new HashSet(); - List resources = retVal; + List resources = retVal; do { includePids.clear(); FhirTerser t = getContext().newTerser(); for (Include next : theParams.getIncludes()) { - for (IResource nextResource : resources) { + for (IBaseResource nextResource : resources) { RuntimeResourceDefinition def = getContext().getResourceDefinition(nextResource); List values = getIncludeValues(t, next, nextResource, def); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu1.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu1.java index aca6944ae15..ed62cab3467 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu1.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu1.java @@ -24,6 +24,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.hl7.fhir.instance.model.IBaseResource; + import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.Include; @@ -32,7 +34,7 @@ import ca.uhn.fhir.util.FhirTerser; public class FhirResourceDaoDstu1 extends BaseFhirResourceDao { - protected List getIncludeValues(FhirTerser t, Include next, IResource nextResource, RuntimeResourceDefinition def) { + protected List getIncludeValues(FhirTerser t, Include next, IBaseResource nextResource, RuntimeResourceDefinition def) { List values; if ("*".equals(next.getValue())) { values = new ArrayList(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java index 56eeeddc196..074439e1b94 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2.java @@ -24,6 +24,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.hl7.fhir.instance.model.IBaseResource; + import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.model.api.IResource; @@ -33,7 +35,7 @@ import ca.uhn.fhir.util.FhirTerser; public class FhirResourceDaoDstu2 extends BaseFhirResourceDao { - protected List getIncludeValues(FhirTerser theTerser, Include theInclude, IResource theResource, RuntimeResourceDefinition theResourceDef) { + protected List getIncludeValues(FhirTerser theTerser, Include theInclude, IBaseResource theResource, RuntimeResourceDefinition theResourceDef) { List values; if ("*".equals(theInclude.getValue())) { values = new ArrayList(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java index 779dee09501..d8401aa03d4 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java @@ -31,6 +31,7 @@ import java.util.Set; import javax.persistence.TypedQuery; +import org.hl7.fhir.instance.model.IBaseResource; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -241,9 +242,9 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao { if (bundle.size() > configuredMax) { oo.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDetails("Search nested within transaction found more than " + configuredMax + " matches, but paging is not supported in nested transactions"); } - List resourcesToAdd = bundle.getResources(0, Math.min(bundle.size(), configuredMax)); - for (IResource next : resourcesToAdd) { - searchBundle.addEntry().setResource(next); + List resourcesToAdd = bundle.getResources(0, Math.min(bundle.size(), configuredMax)); + for (IBaseResource next : resourcesToAdd) { + searchBundle.addEntry().setResource((IResource) next); } response.addEntry().setResource(searchBundle); diff --git a/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml b/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml index dc3d023d2c3..d1068797968 100644 --- a/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml +++ b/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml @@ -39,9 +39,11 @@ + + \ No newline at end of file diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java index 654dd8e442b..50f226d7dc9 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java @@ -27,6 +27,7 @@ import java.util.Set; import org.apache.commons.lang3.RandomStringUtils; import org.hamcrest.core.StringContains; +import org.hl7.fhir.instance.model.IBaseResource; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -453,8 +454,8 @@ public class FhirResourceDaoDstu2Test { IBundleProvider history = ourPatientDao.history(null); assertEquals(4 + initialHistory, history.size()); - List resources = history.getResources(0, 4); - assertNotNull(resources.get(0).getResourceMetadata().get(ResourceMetadataKeyEnum.DELETED_AT)); + List resources = history.getResources(0, 4); + assertNotNull(((IResource) resources.get(0)).getResourceMetadata().get(ResourceMetadataKeyEnum.DELETED_AT)); try { ourPatientDao.delete(id2); @@ -534,9 +535,9 @@ public class FhirResourceDaoDstu2Test { IBundleProvider history = ourPatientDao.history(id, null); assertEquals(2, history.size()); - assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0))); - assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0)).getValue()); - assertNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(1, 1).get(0))); + assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(0, 0).get(0))); + assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(0, 0).get(0)).getValue()); + assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(1, 1).get(0))); } @@ -879,7 +880,7 @@ public class FhirResourceDaoDstu2Test { map.setRevIncludes(Collections.singleton(Patient.INCLUDE_ORGANIZATION)); IBundleProvider resultsP = ourOrganizationDao.search(map); assertEquals(2, resultsP.size()); - List results = resultsP.getResources(0, resultsP.size()); + List results = resultsP.getResources(0, resultsP.size()); assertEquals(2, results.size()); assertEquals(Organization.class, results.get(0).getClass()); assertEquals(Patient.class, results.get(1).getClass()); @@ -2162,15 +2163,15 @@ public class FhirResourceDaoDstu2Test { assertEquals(2, historyBundle.size()); - List history = historyBundle.getResources(0, 2); + List history = historyBundle.getResources(0, 2); assertEquals("1", history.get(1).getId().getVersionIdPart()); assertEquals("2", history.get(0).getId().getVersionIdPart()); - assertEquals(published, history.get(1).getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED)); - assertEquals(published, history.get(1).getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED)); - assertEquals(updated, history.get(1).getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED)); + assertEquals(published, ((IResource)history.get(1)).getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED)); + assertEquals(published, ((IResource)history.get(1)).getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED)); + assertEquals(updated, ((IResource)history.get(1)).getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED)); assertEquals("001", ((Patient) history.get(1)).getIdentifierFirstRep().getValue()); - assertEquals(published2, history.get(0).getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED)); - assertEquals(updated2, history.get(0).getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED)); + assertEquals(published2, ((IResource)history.get(0)).getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED)); + assertEquals(updated2, ((IResource)history.get(0)).getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED)); assertEquals("002", ((Patient) history.get(0)).getIdentifierFirstRep().getValue()); } @@ -2313,8 +2314,8 @@ public class FhirResourceDaoDstu2Test { private List toUnqualifiedVersionlessIds(IBundleProvider theFound) { List retVal = new ArrayList(); - for (IResource next : theFound.getResources(0, theFound.size())) { - retVal.add(next.getId().toUnqualifiedVersionless()); + for (IBaseResource next : theFound.getResources(0, theFound.size())) { + retVal.add((IdDt) next.getId().toUnqualifiedVersionless()); } return retVal; } @@ -2353,9 +2354,9 @@ public class FhirResourceDaoDstu2Test { IBundleProvider value = ourDeviceDao.search(new SearchParameterMap()); ourLog.info("Initial size: " + value.size()); - for (IResource next : value.getResources(0, value.size())) { + for (IBaseResource next : value.getResources(0, value.size())) { ourLog.info("Deleting: {}", next.getId()); - ourDeviceDao.delete(next.getId()); + ourDeviceDao.delete((IdDt) next.getId()); } value = ourDeviceDao.search(new SearchParameterMap()); @@ -2365,7 +2366,7 @@ public class FhirResourceDaoDstu2Test { } assertEquals(0, value.size()); - List res = value.getResources(0, 0); + List res = value.getResources(0, 0); assertTrue(res.isEmpty()); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java index 1bc0af2afb3..e853bacf26f 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1Test.java @@ -11,6 +11,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +import org.hl7.fhir.instance.model.IBaseResource; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -93,7 +94,7 @@ public class FhirSystemDaoDstu1Test { IBundleProvider values = ourSystemDao.history(start); assertEquals(4, values.size()); - List res = values.getResources(0, 4); + List res = values.getResources(0, 4); assertEquals(newpid3, res.get(0).getId()); assertEquals(newpid2, res.get(1).getId()); assertEquals(newpid, res.get(2).getId()); @@ -146,7 +147,7 @@ public class FhirSystemDaoDstu1Test { IBundleProvider patResults = ourPatientDao.search(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01")); assertEquals(1, obsResults.size()); - IdDt foundPatientId = patResults.getResources(0, 1).get(0).getId(); + IdDt foundPatientId = (IdDt) patResults.getResources(0, 1).get(0).getId(); ResourceReferenceDt subject = obs.getSubject(); assertEquals(foundPatientId.getIdPart(), subject.getReference().getIdPart()); @@ -371,7 +372,7 @@ public class FhirSystemDaoDstu1Test { */ res = new ArrayList(); - List existing = results.getResources(0, 3); + List existing = results.getResources(0, 3); p1 = new Patient(); p1.setId(existing.get(0).getId()); @@ -391,7 +392,7 @@ public class FhirSystemDaoDstu1Test { IBundleProvider results2 = ourPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete")); assertEquals(1, results2.size()); - List existing2 = results2.getResources(0, 1); + List existing2 = results2.getResources(0, 1); assertEquals(existing2.get(0).getId(), existing.get(2).getId()); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java index bf55e35584e..dff192df5dc 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2Test.java @@ -14,6 +14,7 @@ import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.List; +import org.hl7.fhir.instance.model.IBaseResource; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -262,9 +263,9 @@ public class FhirSystemDaoDstu2Test { IBundleProvider history = ourPatientDao.history(id, null); assertEquals(2, history.size()); - assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0))); - assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0)).getValue()); - assertNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(1, 1).get(0))); + assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(0, 0).get(0))); + assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(0, 0).get(0)).getValue()); + assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) history.getResources(1, 1).get(0))); } @@ -769,9 +770,9 @@ public class FhirSystemDaoDstu2Test { static void doDeleteEverything(IFhirSystemDao systemDao) { IBundleProvider all = systemDao.history(null); - List allRes = all.getResources(0, all.size()); - for (IResource iResource : allRes) { - if (ResourceMetadataKeyEnum.DELETED_AT.get(iResource) == null) { + List allRes = all.getResources(0, all.size()); + for (IBaseResource iResource : allRes) { + if (ResourceMetadataKeyEnum.DELETED_AT.get((IResource) iResource) == null) { ourLog.info("Deleting: {}", iResource.getId()); Bundle b = new Bundle(); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java index 567d8b1899f..7dd00272657 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java @@ -26,6 +26,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.instance.model.IBaseResource; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -126,12 +127,7 @@ public class ResourceProviderDstu2Test { CloseableHttpResponse response = ourHttpClient.execute(post); try { - - assertEquals(201, response.getStatusLine().getStatusCode()); - assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), startsWith(ourServerBase + "/Patient/")); - assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), endsWith("/_history/1")); - assertThat(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(), not(containsString("1777"))); - + assertEquals(400, response.getStatusLine().getStatusCode()); } finally { response.close(); } @@ -452,7 +448,7 @@ public class ResourceProviderDstu2Test { // NB this does not get used- The paging provider has its own limits built in ourDaoConfig.setHardSearchLimit(100); - List resources = new ArrayList(); + List resources = new ArrayList(); for (int i = 0; i < 100; i++) { Organization org = new Organization(); org.setName("rpdstu2_testCountParam_01"); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderTest.java index 974b0564bc9..062af213dce 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SystemProviderTest.java @@ -7,6 +7,7 @@ import java.util.List; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.hl7.fhir.instance.model.IBaseResource; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; diff --git a/hapi-fhir-jpaserver-example/pom.xml b/hapi-fhir-jpaserver-example/pom.xml index 26d7232c7c4..50908be378c 100644 --- a/hapi-fhir-jpaserver-example/pom.xml +++ b/hapi-fhir-jpaserver-example/pom.xml @@ -2,22 +2,25 @@ 4.0.0 + ca.uhn.hapi.example hapi-fhir-jpaserver-example - 0.9-SNAPSHOT + 1.0-SNAPSHOT war HAPI FHIR JPA Server - Example diff --git a/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java b/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java index d989d6aaa60..a204a42f37d 100644 --- a/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java +++ b/hapi-fhir-jpaserver-example/src/main/java/ca/uhn/fhir/jpa/demo/JpaServerDemo.java @@ -4,12 +4,11 @@ import java.util.List; import javax.servlet.ServletException; -import ca.uhn.fhir.context.FhirVersionEnum; - import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.WebApplicationContext; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu1; import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2; @@ -23,7 +22,7 @@ import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; public class JpaServerDemo extends RestfulServer { @@ -123,12 +122,12 @@ public class JpaServerDemo extends RestfulServer { setPagingProvider(new FifoMemoryPagingProvider(10)); /* - * Do some fancy logging to create a nice access log that has details about each incoming request. + * Load interceptors for the server from Spring (these are defined in hapi-fhir-server-config.xml */ - LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); - loggingInterceptor.setLoggerName("fhir.access"); - loggingInterceptor.setMessageFormat("Path[${servletPath}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]"); - this.registerInterceptor(loggingInterceptor); + List interceptorBeans = myAppCtx.getBean("myServerInterceptors", List.class); + for (IServerInterceptor interceptor : interceptorBeans) { + this.registerInterceptor(interceptor); + } } diff --git a/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml b/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml index 3922d51ebb8..6b039d4bdf5 100644 --- a/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml +++ b/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml @@ -21,4 +21,18 @@ + + + + + + + + + + \ No newline at end of file diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java index 33cab9ca62f..1ea6366ceec 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/TestRestfulServer.java @@ -7,17 +7,16 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; -import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2; - import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; import org.springframework.web.context.ContextLoaderListener; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; -import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2; import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu1; +import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2; import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1; +import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.server.ETagSupportEnum; import ca.uhn.fhir.rest.server.EncodingEnum; @@ -25,7 +24,7 @@ import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; public class TestRestfulServer extends RestfulServer { @@ -164,13 +163,12 @@ public class TestRestfulServer extends RestfulServer { setPagingProvider(new FifoMemoryPagingProvider(10)); /* - * Do some fancy logging to create a nice access log that has details - * about each incoming request. + * Load interceptors for the server from Spring (these are defined in hapi-fhir-server-config.xml */ - LoggingInterceptor loggingInterceptor = new LoggingInterceptor(); - loggingInterceptor.setLoggerName("fhirtest.access"); - loggingInterceptor.setMessageFormat("Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]"); - this.registerInterceptor(loggingInterceptor); + List interceptorBeans = myAppCtx.getBean("myServerInterceptors", List.class); + for (IServerInterceptor interceptor : interceptorBeans) { + this.registerInterceptor(interceptor); + } } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml index 3922d51ebb8..26eb7b9c7cf 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml @@ -21,4 +21,18 @@ + + + + + + + + + + \ No newline at end of file diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java b/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java index 5a6aa244fd1..1958fd78b37 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java +++ b/hapi-fhir-jpaserver-uhnfhirtest/src/test/java/ca/uhn/fhirtest/UhnFhirTestApp.java @@ -1,10 +1,12 @@ package ca.uhn.fhirtest; +import java.util.ArrayList; import java.util.List; import org.apache.commons.io.IOUtils; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.webapp.WebAppContext; +import org.hl7.fhir.instance.model.IBaseResource; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.IResource; @@ -65,7 +67,8 @@ public class UhnFhirTestApp { ResourceMetadataKeyEnum.TAG_LIST.put(p1, list); client.create(p1); - List resources = ctx.newJsonParser().parseBundle(IOUtils.toString(UhnFhirTestApp.class.getResourceAsStream("/test-server-seed-bundle.json"))).toListOfResources(); + List resources; + resources = new ArrayList(ctx.newJsonParser().parseBundle(IOUtils.toString(UhnFhirTestApp.class.getResourceAsStream("/test-server-seed-bundle.json"))).toListOfResources()); client.transaction(resources); // for (int i = 0; i < 1000; i++) { diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java index f1503066ac6..da8fe43f99f 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -782,13 +782,13 @@ public class JsonParserTest { private void parseAndEncode(String name) throws IOException { String msg = IOUtils.toString(XmlParser.class.getResourceAsStream(name)); - ourLog.info(msg); +// ourLog.info(msg); IParser p = ourCtx.newJsonParser(); Profile res = p.parseResource(Profile.class, msg); String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res); - ourLog.info(encoded); +// ourLog.info(encoded); JSON expected = JSONSerializer.toJSON(msg.trim()); JSON actual = JSONSerializer.toJSON(encoded.trim()); @@ -1219,7 +1219,6 @@ public class JsonParserTest { Bundle b = new Bundle(); InstantDt pub = InstantDt.withCurrentTime(); - b.setPublished(pub); Thread.sleep(2); Patient p1 = new Patient(); @@ -1245,7 +1244,6 @@ public class JsonParserTest { ourLog.info(bundleString); List strings = new ArrayList(); - strings.addAll(Arrays.asList("\"published\":\"" + pub.getValueAsString() + "\"")); strings.addAll(Arrays.asList("\"id\":\"1\"")); strings.addAll(Arrays.asList("this is the summary")); strings.addAll(Arrays.asList("\"id\":\"2\"", "\"rel\":\"alternate\"", "\"href\":\"http://foo/bar\"")); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java index ab7dd48a646..db0fbce13e5 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java @@ -314,7 +314,6 @@ public class XmlParserTest { b.getCategories().addTag("http://hl7.org/fhir/tag", "http://hl7.org/fhir/tag/message", "Message"); InstantDt pub = InstantDt.withCurrentTime(); - b.setPublished(pub); Thread.sleep(2); Patient p1 = new Patient(); @@ -340,7 +339,6 @@ public class XmlParserTest { ourLog.info(bundleString); List strings = new ArrayList(); - strings.addAll(Arrays.asList("", pub.getValueAsString(), "")); strings.add(""); strings.addAll(Arrays.asList("", "1", "", "", "")); strings.addAll(Arrays.asList("", "2", "", "", "")); @@ -380,7 +378,6 @@ public class XmlParserTest { b.getCategories().addTag("http://hl7.org/fhir/tag", "http://hl7.org/fhir/tag/message", "Message"); InstantDt pub = InstantDt.withCurrentTime(); - b.setPublished(pub); Thread.sleep(2); Patient p1 = new Patient(); @@ -406,7 +403,6 @@ public class XmlParserTest { ourLog.info(bundleString); List strings = new ArrayList(); - strings.addAll(Arrays.asList("", pub.getValueAsString(), "")); strings.add(""); strings.addAll(Arrays.asList("", "1", "", "", "")); strings.addAll(Arrays.asList("", "2", "", "", "")); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java index 11f66b0026d..7376a97b5b7 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java @@ -102,8 +102,7 @@ public class ClientTest { "\n" + "<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" + "<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" + - "<published>2014-03-11T16:35:07-04:00</published>\n" + - "<author>\n" + + "<author>\n" + "<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" + "</author>\n" + "<entry>\n" + @@ -301,7 +300,6 @@ public class ClientTest { String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\"><title/><id>6c1d93be-027f-468d-9d47-f826cd15cf42</id>" + "<link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/>" + "<link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>" - + "<published>2014-04-13T18:24:50-04:00</published>" + "<author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author>" + "<entry><title>Patient 222222" + ""+date1.getValueAsString()+"" @@ -374,7 +372,6 @@ public class ClientTest { String msg = "<id>6c1d93be-027f-468d-9d47-f826cd15cf42</id>" + "<link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/>" + "<link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>" - + "<published>2014-04-13T18:24:50-04:00</published>" + "<author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author>" + "<entry><title>Patient 222222" + ""+date1.getValueAsString()+"" @@ -446,7 +443,6 @@ public class ClientTest { String msg = "<id>6c1d93be-027f-468d-9d47-f826cd15cf42</id>" + "<link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/>" + "<link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>" - + "<published>2014-04-13T18:24:50-04:00</published>" + "<author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author>" + "<entry><title>Patient 222222" + ""+date1.getValueAsString()+"" @@ -511,7 +507,7 @@ public class ClientTest { public void testHistoryWithParams() throws Exception { //@formatter:off - final String msg = "<id>6c1d93be-027f-468d-9d47-f826cd15cf42</id><link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/><link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults><published>2014-04-13T18:24:50-04:00</published><author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author><entry><title>Patient 2222221969-12-31T19:00:20.000-05:001969-12-31T19:00:10.000-05:00Patient 2222221969-12-31T19:00:30.000-05:001969-12-31T19:00:10.000-05:00"; + final String msg = "<id>6c1d93be-027f-468d-9d47-f826cd15cf42</id><link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/><link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults><author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author><entry><title>Patient 2222221969-12-31T19:00:20.000-05:001969-12-31T19:00:10.000-05:00Patient 2222221969-12-31T19:00:30.000-05:001969-12-31T19:00:10.000-05:00"; //@formatter:on ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java index e20ca86e6ca..ad9b9d1df8b 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java @@ -85,8 +85,7 @@ public class GenericClientTest { "\n" + "<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" + "<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" + - "<published>2014-03-11T16:35:07-04:00</published>\n" + - "<author>\n" + + "<author>\n" + "<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" + "</author>\n" + "<entry>\n" + @@ -132,7 +131,7 @@ public class GenericClientTest { ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); - when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") }); + when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")}); when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); @@ -141,14 +140,14 @@ public class GenericClientTest { when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); MethodOutcome resp = client.create().resource(ourCtx.newXmlParser().encodeResourceToString(p1)).execute(); assertTrue(resp.getCreated()); - + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); resp = client.create().resource(ourCtx.newXmlParser().encodeResourceToString(p1)).execute(); assertNull(resp.getCreated()); - + } - - + + @Test public void testCreateWithStringAutoDetectsEncoding() throws Exception { diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/IncludedResourceStitchingClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/IncludedResourceStitchingClientTest.java index 697c06340c9..3068f3674eb 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/IncludedResourceStitchingClientTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/IncludedResourceStitchingClientTest.java @@ -114,8 +114,7 @@ public class IncludedResourceStitchingClientTest { " <link rel=\"self\" href=\"http://localhost:49782/Patient?_query=declaredExtInclude&_pretty=true\"/>\n" + " <link rel=\"fhir-base\" href=\"http://localhost:49782\"/>\n" + " <os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>\n" + - " <published>2014-08-12T10:22:19.097-04:00</published>\n" + - " <author>\n" + + " <author>\n" + " <name>HAPI FHIR Server</name>\n" + " </author>\n" + " <entry>\n" + @@ -192,8 +191,7 @@ public class IncludedResourceStitchingClientTest { " <link rel=\"self\" href=\"http://localhost:49627/Patient?_query=extInclude&_pretty=true\"/>\n" + " <link rel=\"fhir-base\" href=\"http://localhost:49627\"/>\n" + " <os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>\n" + - " <published>2014-08-05T15:22:08.512-04:00</published>\n" + - " <author>\n" + + " <author>\n" + " <name>HAPI FHIR Server</name>\n" + " </author>\n" + " <entry>\n" + diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SearchTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SearchTest.java index 5c0e3fcde54..7ed69d040bc 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SearchTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SearchTest.java @@ -63,7 +63,7 @@ public class SearchTest { @Test public void testPostOnLongParamsList() throws Exception { - String retVal = "<feed xmlns=\"http://www.w3.org/2005/Atom\"><title/><id>bc59fca7-0a8f-4caf-abef-45c8d53ece6a</id><link rel=\"self\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter?identifier=urn%3Aoid%3A1.3.6.1.4.1.12201.2%7C11410000159&_include=Encounter.participant&_include=Encounter.location.location&_include=Encounter.subject\"/><link rel=\"fhir-base\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults><published>2014-08-08T14:46:16.497-04:00</published><author><name>HAPI FHIR Server</name></author><entry><title>Encounter 5994268http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter/59942682014-08-05T12:00:11.000-04:002014-08-05T11:59:21.000-04:00
No narrative template available for resource profile: http://fhir.connectinggta.ca/Profile/encounter
Patient 5993715http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Patient/59937152014-08-08T14:46:16-04:00
Person CHA
IdentifierUHN MRN 7018614
Address100 Dundas street west
Toronto ON Can
Date of birth01 January 1988
Practitioner Practitioner/5738815http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Practitioner/57388152014-08-08T13:53:52.000-04:002009-12-04T13:43:11.000-05:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Practitioner
Location Location/5994269http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Location/59942692014-08-08T14:46:16-04:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Location
"; + String retVal = "<id>bc59fca7-0a8f-4caf-abef-45c8d53ece6a</id><link rel=\"self\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter?identifier=urn%3Aoid%3A1.3.6.1.4.1.12201.2%7C11410000159&_include=Encounter.participant&_include=Encounter.location.location&_include=Encounter.subject\"/><link rel=\"fhir-base\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults><author><name>HAPI FHIR Server</name></author><entry><title>Encounter 5994268http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter/59942682014-08-05T12:00:11.000-04:002014-08-05T11:59:21.000-04:00
No narrative template available for resource profile: http://fhir.connectinggta.ca/Profile/encounter
Patient 5993715http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Patient/59937152014-08-08T14:46:16-04:00
Person CHA
IdentifierUHN MRN 7018614
Address100 Dundas street west
Toronto ON Can
Date of birth01 January 1988
Practitioner Practitioner/5738815http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Practitioner/57388152014-08-08T13:53:52.000-04:002009-12-04T13:43:11.000-05:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Practitioner
Location Location/5994269http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Location/59942692014-08-08T14:46:16-04:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Location
"; ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse); @@ -97,7 +97,7 @@ public class SearchTest { @Test public void testReturnTypedList() throws Exception { - String retVal = "<id>bc59fca7-0a8f-4caf-abef-45c8d53ece6a</id><link rel=\"self\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter?identifier=urn%3Aoid%3A1.3.6.1.4.1.12201.2%7C11410000159&_include=Encounter.participant&_include=Encounter.location.location&_include=Encounter.subject\"/><link rel=\"fhir-base\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults><published>2014-08-08T14:46:16.497-04:00</published><author><name>HAPI FHIR Server</name></author><entry><title>Encounter 5994268http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter/59942682014-08-05T12:00:11.000-04:002014-08-05T11:59:21.000-04:00
No narrative template available for resource profile: http://fhir.connectinggta.ca/Profile/encounter
Patient 5993715http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Patient/59937152014-08-08T14:46:16-04:00
Person CHA
IdentifierUHN MRN 7018614
Address100 Dundas street west
Toronto ON Can
Date of birth01 January 1988
Practitioner Practitioner/5738815http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Practitioner/57388152014-08-08T13:53:52.000-04:002009-12-04T13:43:11.000-05:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Practitioner
Location Location/5994269http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Location/59942692014-08-08T14:46:16-04:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Location
"; + String retVal = "<id>bc59fca7-0a8f-4caf-abef-45c8d53ece6a</id><link rel=\"self\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter?identifier=urn%3Aoid%3A1.3.6.1.4.1.12201.2%7C11410000159&_include=Encounter.participant&_include=Encounter.location.location&_include=Encounter.subject\"/><link rel=\"fhir-base\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults><author><name>HAPI FHIR Server</name></author><entry><title>Encounter 5994268http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter/59942682014-08-05T12:00:11.000-04:002014-08-05T11:59:21.000-04:00
No narrative template available for resource profile: http://fhir.connectinggta.ca/Profile/encounter
Patient 5993715http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Patient/59937152014-08-08T14:46:16-04:00
Person CHA
IdentifierUHN MRN 7018614
Address100 Dundas street west
Toronto ON Can
Date of birth01 January 1988
Practitioner Practitioner/5738815http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Practitioner/57388152014-08-08T13:53:52.000-04:002009-12-04T13:43:11.000-05:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Practitioner
Location Location/5994269http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Location/59942692014-08-08T14:46:16-04:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Location
"; ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java index 404564532be..d6177356b67 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/Dstu1BundleFactoryTest.java @@ -20,6 +20,7 @@ import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.Medication; import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.dstu.resource.Practitioner; @@ -86,6 +87,23 @@ public class Dstu1BundleFactoryTest { myBundleFactory = new Dstu1BundleFactory(ourCtx); } + @Test + public void whenMedicationHasIngredients_include_shouldIncludeThem() throws Exception { + Medication medication = new Medication(); + medication.setName("Main Medication"); + medication.setId("Medication/1"); + Medication ingredientMedication = new Medication(); + ingredientMedication.setName("Ingredient"); + ingredientMedication.setId("Medication/2"); + Medication.ProductIngredient ingredient = new Medication.ProductIngredient(); + ingredient.setItem(new ResourceReferenceDt(ingredientMedication)); + medication.getProduct().getIngredient().add(ingredient); + + myResourceList = Arrays.asList(new IBaseResource[]{medication}); + Bundle bundle = makeBundle(BundleInclusionRule.BASED_ON_INCLUDES, includes("Medication.product.ingredient.item")); + assertEquals(2, bundle.getEntries().size()); + } + @Test public void whenIncludeIsAsterisk_bundle_shouldContainAllReferencedResources() throws Exception { Bundle bundle = makeBundle(BundleInclusionRule.BASED_ON_INCLUDES, includes("*")); diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategyTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategyTest.java index 9e96a5100f4..6164f1c8b8d 100644 --- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategyTest.java +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategyTest.java @@ -1,30 +1,236 @@ package ca.uhn.fhir.rest.server; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +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.ServletHolder; +import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; +import ca.uhn.fhir.util.RandomServerPortProvider; + public class IncomingRequestAddressStrategyTest { + private static CloseableHttpClient ourClient; + private static String ourLastBase; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncomingRequestAddressStrategyTest.class); + private static IncomingRequestAddressStrategy ourStrategy; + + private Server myServer; + + public void after() throws Exception { + if (myServer != null) { + myServer.stop(); + } + } + + @Before + public void before() { + ourLastBase = null; + ourStrategy = new IncomingRequestAddressStrategy(); + } + + private void httpGet(String url) throws IOException, ClientProtocolException { + ourLastBase = null; + + HttpGet httpPost = new HttpGet(url); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info(responseContent); + } + + private void startServer(int port, String contextPath, String servletPath) throws Exception { + myServer = new Server(port); + + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); + proxyHandler.setContextPath(contextPath); + + ServletHolder handler = new ServletHolder(); + handler.setServlet(new MyServlet()); + proxyHandler.addServlet(handler, servletPath); + + myServer.setHandler(proxyHandler); + myServer.start(); + } + /** - * This is an incoming request from an instance of Tomcat on AWS, provided by - * Simon Ling of Systems Made Simple + * This is an incoming request from an instance of Tomcat on AWS, provided by Simon Ling of Systems Made Simple */ @Test public void testAwsUrl() { - + HttpServletRequest req = mock(HttpServletRequest.class); when(req.getRequestURI()).thenReturn("/FhirStorm/fhir/Patient/_search"); when(req.getServletPath()).thenReturn("/fhir"); when(req.getRequestURL()).thenReturn(new StringBuffer().append("http://fhirstorm.dyndns.org:8080/FhirStorm/fhir/Patient/_search")); when(req.getContextPath()).thenReturn("/FhirStorm"); - + IncomingRequestAddressStrategy incomingRequestAddressStrategy = new IncomingRequestAddressStrategy(); - String actual = incomingRequestAddressStrategy.determineServerBase(null,req); + String actual = incomingRequestAddressStrategy.determineServerBase(null, req); assertEquals("http://fhirstorm.dyndns.org:8080/FhirStorm/fhir", actual); } + + @Test + public void testUnderJettyWithContextPathServletRoot() throws Exception { + int port = RandomServerPortProvider.findFreePort(); + + String contextPath = "/ctx"; + String servletPath = "/*"; + + startServer(port, contextPath, servletPath); + + httpGet("http://localhost:" + port + "/ctx"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/Patient?_pretty=true"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/Patient/123/_history/222"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port); + assertEquals(null, ourLastBase); + + } + + @Test + public void testUnderJettyWithContextPathServletRootContextOnly() throws Exception { + int port = RandomServerPortProvider.findFreePort(); + + String contextPath = "/ctx"; + String servletPath = "/"; + + startServer(port, contextPath, servletPath); + ourStrategy.setServletPath(""); + + httpGet("http://localhost:" + port + "/ctx"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/Patient?_pretty=true"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/Patient/123/_history/222"); + assertEquals("http://localhost:" + port + "/ctx/", ourLastBase); + + httpGet("http://localhost:" + port); + assertEquals(null, ourLastBase); + + } + + @Test + public void testUnderJettyWithContextPathServletRoot2() throws Exception { + int port = RandomServerPortProvider.findFreePort(); + + String contextPath = "/ctx"; + String servletPath = "/foo/bar/*"; // not /* but still this should work + + startServer(port, contextPath, servletPath); + + httpGet("http://localhost:" + port + "/ctx/foo/bar/Patient?_pretty=true"); + assertEquals("http://localhost:" + port + "/ctx/foo/bar", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/foo/bar"); + assertEquals("http://localhost:" + port + "/ctx/foo/bar", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/foo/bar/"); + assertEquals("http://localhost:" + port + "/ctx/foo/bar", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/foo/bar/Patient/123/_history/222"); + assertEquals("http://localhost:" + port + "/ctx/foo/bar", ourLastBase); + + httpGet("http://localhost:" + port); + assertEquals(null, ourLastBase); + + } + + @Test + public void testUnderJettyWithContextPathServletPath() throws Exception { + int port = RandomServerPortProvider.findFreePort(); + + String contextPath = "/ctx"; + String servletPath = "/servlet/*"; + + startServer(port, contextPath, servletPath); + + httpGet("http://localhost:" + port); + assertEquals(null, ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/servlet/"); + assertEquals("http://localhost:" + port + "/ctx/servlet", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/servlet/Patient?_pretty=true"); + assertEquals("http://localhost:" + port + "/ctx/servlet", ourLastBase); + + httpGet("http://localhost:" + port + "/ctx/servlet/Patient/123/_history/222"); + assertEquals("http://localhost:" + port + "/ctx/servlet", ourLastBase); + } + + @Test + public void testUnderJettyWithContextRootServletRoot() throws Exception { + int port = RandomServerPortProvider.findFreePort(); + + String contextPath = "/"; + String servletPath = "/*"; + + startServer(port, contextPath, servletPath); + + httpGet("http://localhost:" + port); + assertEquals("http://localhost:" + port + contextPath, ourLastBase); + + httpGet("http://localhost:" + port + "/Patient?_pretty=true"); + assertEquals("http://localhost:" + port + contextPath, ourLastBase); + + httpGet("http://localhost:" + port + "/Patient/123/_history/222"); + assertEquals("http://localhost:" + port + contextPath, ourLastBase); + } + + @BeforeClass + public static void beforeClass() { + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + } + + private static class MyServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException { + +// ourLog.info("Ctx: {}", theReq.) + + ourLastBase = ourStrategy.determineServerBase(getServletContext(), theReq); + theResp.setContentType("text/plain"); + theResp.getWriter().append("Success"); + theResp.getWriter().close(); + } + + } + } diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/RandomServerPortProvider.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/RandomServerPortProvider.java new file mode 100644 index 00000000000..4747b741847 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/RandomServerPortProvider.java @@ -0,0 +1,36 @@ +package ca.uhn.fhir.util; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.List; + +/** + * Provides server ports + */ +public class RandomServerPortProvider { + + private static List ourPorts = new ArrayList(); + + public static int findFreePort() { + ServerSocket server; + try { + server = new ServerSocket(0); + int port = server.getLocalPort(); + ourPorts.add(port); + server.close(); + Thread.sleep(500); + return port; + } catch (IOException e) { + throw new Error(e); + } catch (InterruptedException e) { + throw new Error(e); + } + } + + public static List list() { + return ourPorts; + } + +} + \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/mixed-return-bundle.xml b/hapi-fhir-structures-dstu/src/test/resources/mixed-return-bundle.xml index 9bee3ae5f64..3f51cb117f4 100644 --- a/hapi-fhir-structures-dstu/src/test/resources/mixed-return-bundle.xml +++ b/hapi-fhir-structures-dstu/src/test/resources/mixed-return-bundle.xml @@ -4,7 +4,6 @@ 2 - 2014-06-22T21:37:05-04:00 HAPI FHIR Server diff --git a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java index 5480b4a40dd..a4210031bb2 100644 --- a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java +++ b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/FhirDstu2.java @@ -105,7 +105,7 @@ public class FhirDstu2 implements IFhirVersion { public Class getContainedType() { return ContainedDt.class; } - + @Override public BaseCodingDt newCodingDt() { return new CodingDt(); diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java index d701f863529..106194af662 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java @@ -468,7 +468,7 @@ public class XmlParserDstu2Test { //@formatter:on Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res); - assertEquals(htmlNoNs, p.getText().getDiv().getValueAsString()); + assertEquals(htmlNs, p.getText().getDiv().getValueAsString()); } /** diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java index 3976340b623..cd0686f8de5 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java @@ -1,6 +1,6 @@ package ca.uhn.fhir.rest.server; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.util.concurrent.TimeUnit; @@ -49,6 +49,7 @@ public class SearchDstu2Test { Patient patient = (Patient) ourCtx.newXmlParser().parseResource(Bundle.class, responseContent).getEntry().get(0).getResource(); String ref = patient.getManagingOrganization().getReference().getValue(); assertEquals("Organization/555", ref); + assertNull(status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION)); } diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java index c991ce59458..b78d77004a0 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java @@ -1062,7 +1062,7 @@ public class XmlParserHl7OrgDstu2Test { Patient patient = ourCtx.newXmlParser().parseResource(Patient.class, msg); assertEquals(NarrativeStatus.GENERATED, patient.getText().getStatus()); - assertEquals("
John Cardinal: 444333333
", patient.getText().getDiv().getValueAsString()); + assertEquals("
John Cardinal: 444333333
", patient.getText().getDiv().getValueAsString()); assertEquals("PRP1660", patient.getIdentifier().get(0).getValue()); String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); @@ -1197,6 +1197,8 @@ public class XmlParserHl7OrgDstu2Test { Patient patient1 = ourCtx.newXmlParser().parseResource(Patient.class, msg); String encoded1 = ourCtx.newXmlParser().encodeResourceToString(patient1); + ourLog.info(encoded1); + Diff d = new Diff(new StringReader(msg), new StringReader(encoded1)); assertTrue(d.toString(), d.identical()); diff --git a/hapi-fhir-testpage-overlay/.gitignore b/hapi-fhir-testpage-overlay/.gitignore index 84c048a73cc..0c06d203331 100644 --- a/hapi-fhir-testpage-overlay/.gitignore +++ b/hapi-fhir-testpage-overlay/.gitignore @@ -1 +1,128 @@ +/target/ + +# Created by https://www.gitignore.io + +### Java ### +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties + + +### Vim ### +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist +*~ + + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties + + + +### Eclipse ### +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse + /build/ diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java index e4ee3857861..5ac3dfbcd18 100644 --- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java +++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java @@ -1203,7 +1203,7 @@ public class Controller { private String parseNarrative(HomeRequest theRequest, EncodingEnum theCtEnum, String theResultBody) { try { - IResource resource = theCtEnum.newParser(getContext(theRequest)).parseResource(theResultBody); + IResource resource = (IResource) theCtEnum.newParser(getContext(theRequest)).parseResource(theResultBody); String retVal = resource.getText().getDiv().getValueAsString(); return StringUtils.defaultString(retVal); } catch (Exception e) { diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/model/HomeRequest.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/model/HomeRequest.java index 1bfe9011c9c..e437212c65d 100644 --- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/model/HomeRequest.java +++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/model/HomeRequest.java @@ -49,7 +49,9 @@ public class HomeRequest { } if (retVal.contains("${serverBase}")) { - String base = new IncomingRequestAddressStrategy().determineServerBase(theRequest.getServletContext(), theRequest); + IncomingRequestAddressStrategy strategy = new IncomingRequestAddressStrategy(); + strategy.setServletPath(""); + String base = strategy.determineServerBase(theRequest.getServletContext(), theRequest); if (base.endsWith("/")) { base = base.substring(0, base.length() - 1); } diff --git a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java index f7a5833fbc4..fe543b0ea14 100644 --- a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java +++ b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java @@ -8,6 +8,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.webapp.WebAppContext; +import org.hl7.fhir.instance.model.IBaseResource; import org.springframework.context.support.ClassPathXmlApplicationContext; import ca.uhn.fhir.context.FhirContext; @@ -129,7 +130,7 @@ public class OverlayTestApp { client.create(p1); List resources = restServerDstu1.getFhirContext().newJsonParser().parseBundle(IOUtils.toString(OverlayTestApp.class.getResourceAsStream("/test-server-seed-bundle.json"))).toListOfResources(); - client.transaction(resources); + client.transaction(new ArrayList(resources)); client.create(p1); client.create(p1); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java new file mode 100644 index 00000000000..c7331cc8649 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java @@ -0,0 +1,175 @@ +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 _language + */ + @SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" ) + public static final String SP_RES_LANGUAGE = "_language"; + + + /** + * Search parameter constant for _id + */ + @SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" ) + public static final String SP_RES_ID = "_id"; + + /** + * Fluent Client search parameter constant for _id + *

+ * Description: the _id of a resource
+ * Type: string
+ * Path: Resource._id
+ *

+ */ + 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 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 true 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); + } + +} diff --git a/restful-server-example-test/pom.xml b/restful-server-example-test/pom.xml index 4032503e6c4..1fa97305206 100644 --- a/restful-server-example-test/pom.xml +++ b/restful-server-example-test/pom.xml @@ -21,7 +21,7 @@ ca.uhn.hapi.fhir - hapi-fhir-structures-dstu + hapi-fhir-structures-dstu2 1.0-SNAPSHOT test diff --git a/restful-server-example-test/src/test/java/ca/uhn/example/ExampleTest.java b/restful-server-example-test/src/test/java/ca/uhn/example/ExampleTest.java index 7e939ce5a56..98be299b205 100644 --- a/restful-server-example-test/src/test/java/ca/uhn/example/ExampleTest.java +++ b/restful-server-example-test/src/test/java/ca/uhn/example/ExampleTest.java @@ -1,7 +1,6 @@ package ca.uhn.example; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.webapp.WebAppContext; @@ -12,7 +11,7 @@ import org.junit.Test; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; -import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.rest.client.IGenericClient; public class ExampleTest { diff --git a/restful-server-example/pom.xml b/restful-server-example/pom.xml index 588f8fcae4b..5aa6eb7e33c 100644 --- a/restful-server-example/pom.xml +++ b/restful-server-example/pom.xml @@ -14,7 +14,7 @@ ca.uhn.hapi.example restful-server-example - 0.8-SNAPSHOT + 1.0-SNAPSHOT war HAPI FHIR Sample RESTful Server @@ -40,7 +40,7 @@ ca.uhn.hapi.fhir - hapi-fhir-structures-dstu + hapi-fhir-structures-dstu2 1.0-SNAPSHOT diff --git a/restful-server-example/src/main/java/ca/uhn/example/model/MyOrganization.java b/restful-server-example/src/main/java/ca/uhn/example/model/MyOrganization.java index be42ea5fa6b..4981bced11f 100644 --- a/restful-server-example/src/main/java/ca/uhn/example/model/MyOrganization.java +++ b/restful-server-example/src/main/java/ca/uhn/example/model/MyOrganization.java @@ -3,7 +3,6 @@ package ca.uhn.example.model; import java.util.ArrayList; import java.util.List; -import ca.uhn.fhir.model.api.BaseElement; import ca.uhn.fhir.model.api.BaseIdentifiableElement; import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IExtension; @@ -12,8 +11,8 @@ 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.dstu.composite.ContactDt; -import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu2.composite.ContactPointDt; +import ca.uhn.fhir.model.dstu2.resource.Organization; import ca.uhn.fhir.model.primitive.BooleanDt; import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.util.ElementUtil; @@ -115,7 +114,7 @@ public class MyOrganization extends Organization { @Description(shortDefinition = "Contains the actual contact details") @Extension(url = "http://foo#emergencyContactContact", isModifier = false, definedLocally = true) @Child(name = "contact") - private ContactDt myContact; + private ContactPointDt myContact; /* ***************************** * Getters and setters @@ -132,14 +131,14 @@ public class MyOrganization extends Organization { myActive = theActive; } - public ContactDt getContact() { + public ContactPointDt getContact() { if (myContact == null) { - myContact = new ContactDt(); + myContact = new ContactPointDt(); } return myContact; } - public void setContact(ContactDt theContact) { + public void setContact(ContactPointDt theContact) { myContact = theContact; } diff --git a/restful-server-example/src/main/java/ca/uhn/example/provider/OrganizationResourceProvider.java b/restful-server-example/src/main/java/ca/uhn/example/provider/OrganizationResourceProvider.java index 8553ad21dbd..0ed7006751e 100644 --- a/restful-server-example/src/main/java/ca/uhn/example/provider/OrganizationResourceProvider.java +++ b/restful-server-example/src/main/java/ca/uhn/example/provider/OrganizationResourceProvider.java @@ -1,9 +1,8 @@ package ca.uhn.example.provider; import ca.uhn.example.model.MyOrganization; -import ca.uhn.example.model.MyOrganization.EmergencyContact; -import ca.uhn.fhir.model.dstu.composite.ContactDt; -import ca.uhn.fhir.model.dstu.valueset.ContactUseEnum; +import ca.uhn.fhir.model.dstu2.composite.ContactPointDt; +import ca.uhn.fhir.model.dstu2.valueset.ContactPointUseEnum; import ca.uhn.fhir.model.primitive.BooleanDt; import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.model.primitive.IdDt; @@ -51,9 +50,9 @@ public class OrganizationResourceProvider implements IResourceProvider { MyOrganization retVal = new MyOrganization(); retVal.setId("1"); - retVal.addIdentifier("urn:example:orgs", "FooOrganization"); + retVal.addIdentifier().setSystem("urn:example:orgs").setValue("FooOrganization"); retVal.addAddress().addLine("123 Fake Street").setCity("Toronto"); - retVal.addTelecom().setUse(ContactUseEnum.WORK).setValue("1-888-123-4567"); + retVal.addTelecom().setUse(ContactPointUseEnum.WORK).setValue("1-888-123-4567"); // Populate the first, primitive extension retVal.setBillingCode(new CodeDt("00102-1")); @@ -61,7 +60,7 @@ public class OrganizationResourceProvider implements IResourceProvider { // The second extension is repeatable and takes a block type MyOrganization.EmergencyContact contact = new MyOrganization.EmergencyContact(); contact.setActive(new BooleanDt(true)); - contact.setContact(new ContactDt()); + contact.setContact(new ContactPointDt()); retVal.getEmergencyContact().add(contact); return retVal; diff --git a/restful-server-example/src/main/java/ca/uhn/example/provider/PatientResourceProvider.java b/restful-server-example/src/main/java/ca/uhn/example/provider/PatientResourceProvider.java index e063fd4119e..ebac390e1cf 100644 --- a/restful-server-example/src/main/java/ca/uhn/example/provider/PatientResourceProvider.java +++ b/restful-server-example/src/main/java/ca/uhn/example/provider/PatientResourceProvider.java @@ -7,11 +7,11 @@ import java.util.List; import java.util.Map; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; -import ca.uhn.fhir.model.dstu.composite.HumanNameDt; -import ca.uhn.fhir.model.dstu.resource.OperationOutcome; -import ca.uhn.fhir.model.dstu.resource.Patient; -import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum; -import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum; +import ca.uhn.fhir.model.dstu2.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu2.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum; +import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.StringDt; @@ -59,7 +59,7 @@ public class PatientResourceProvider implements IResourceProvider { patient.getIdentifier().get(0).setValue("00002"); patient.addName().addFamily("Test"); patient.getName().get(0).addGiven("PatientOne"); - patient.setGender(AdministrativeGenderCodesEnum.F); + patient.setGender(AdministrativeGenderEnum.FEMALE); LinkedList list = new LinkedList(); list.add(patient); diff --git a/restful-server-example/src/main/java/ca/uhn/example/servlet/ExampleRestfulServlet.java b/restful-server-example/src/main/java/ca/uhn/example/servlet/ExampleRestfulServlet.java index 56348540288..245e70df665 100644 --- a/restful-server-example/src/main/java/ca/uhn/example/servlet/ExampleRestfulServlet.java +++ b/restful-server-example/src/main/java/ca/uhn/example/servlet/ExampleRestfulServlet.java @@ -5,6 +5,7 @@ import java.util.List; import ca.uhn.example.provider.OrganizationResourceProvider; import ca.uhn.example.provider.PatientResourceProvider; +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.rest.server.IResourceProvider; @@ -23,6 +24,7 @@ public class ExampleRestfulServlet extends RestfulServer { */ @Override public void initialize() { + setFhirContext(FhirContext.forDstu2());// Support DSTU2 /* * Two resource providers are defined. Each one handles a specific diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 3d051bb05fc..1e06616de75 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -136,6 +136,16 @@ configures the parser to preserve versions in resource reference links when encoding. By default, these are removed. + + Terser's IModelVisitor now supplies to the path to the element. This is + an API change, but I don't think there are many users of the IModelVisitor yet. + Please let us know if this is a big hardship and we can find an alternate way + of making this change. + + + Prevent server from returning a Content-Location header for search + response when using the DSTU2 bundle format + diff --git a/src/site/xdoc/doc_rest_client.xml b/src/site/xdoc/doc_rest_client.xml index 8128e6a589f..40e2cb8dc7b 100644 --- a/src/site/xdoc/doc_rest_client.xml +++ b/src/site/xdoc/doc_rest_client.xml @@ -165,8 +165,10 @@

Search - Using HTTP POST

- The FHIR specification allows the use of an HTTP POST to transmit a search to a server instead of using - an HTTP GET. With this style of search, the search parameters are included in the request body instead + The FHIR specification allows the use of an HTTP POST to transmit a search to a server instead of + using + an HTTP GET. With this style of search, the search parameters are included in the request body + instead of the request URL, which can be useful if you need to transmit a search with a large number of parameters.

@@ -176,7 +178,7 @@ case the client automatically switches to POST.

- An alternate form of the search URL (using a URL ending with _search) was also + An alternate form of the search URL (using a URL ending with_search) was also supported in FHIR DSTU1. This form is no longer valid in FHIR DSTU2, but HAPI retains support for using this form in order to interoperate with servers which use it.

@@ -211,18 +213,18 @@ - +

Conditional Creates

FHIR also specifies a type of update called "conditional create", where a set of search parameters are provided and a new resource is only - created if no existing resource matches those parameters. See the - FHIR specification for more information on conditional creation. + created if no existing resource matches those parameters. See the + FHIR specification for more information on conditional creation.

- + + value="examples/src/main/java/example/GenericClientExample.java"/> @@ -276,7 +278,7 @@

Conditional Deletes

- Conditional deletions are also possible, which is a form where + Conditional deletions are also possible, which is a form where instead of deleting a resource using its logical ID, you specify a set of search criteria and a single resource is deleted if it matches that criteria. Note that this is not a mechanism @@ -284,9 +286,9 @@ on conditional deletes and how they are used.

- + + value="examples/src/main/java/example/GenericClientExample.java"/> @@ -305,19 +307,19 @@ - +

Conditional Updates

FHIR also specifies a type of update called "conditional updates", where insetad of using the logical ID of a resource to update, a set of search parameters is provided. If a single resource matches that set of - parameters, that resource is updated. See the FHIR specification for + parameters, that resource is updated. See the FHIR specification for information on how conditional updates work.

- + + value="examples/src/main/java/example/GenericClientExample.java"/>

ETags and Resource Contention