A number of bugfixes around parsing and client implementation

This commit is contained in:
jamesagnew 2014-04-30 18:39:33 -04:00
parent f737797d7a
commit 63c9fb466c
26 changed files with 978 additions and 421 deletions

View File

@ -7,7 +7,7 @@
</properties>
<body>
<release version="0.3" date="TBD">
<action type="fix" dev="Josh Mandel">
<action type="add">
Make it easier to add HTTP Basic Authorization headers to RESTful client requests
and <![CDATA[<a href="./doc_rest_client.html#HTTP_Basic_Authorization">an example</a>]]>
illustrating how it works
@ -15,6 +15,10 @@
<action type="fix" dev="Josh Mandel">
Correct a dependency on commons-io that was causing issues with the Tinder build
</action>
<action type="fix">
Fix an issue where extensions with a resource reference as the value show up incorrectly
(wrong element name for undeclared extensions, and empty content for declared extensions)
</action>
</release>
</body>
</document>

View File

@ -23,12 +23,15 @@ package ca.uhn.fhir.context;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
@ -133,7 +136,15 @@ public class RuntimeChildDeclaredExtensionDefinition extends BaseRuntimeDeclared
BaseRuntimeElementDefinition<?> elementDef = theClassToElementDefinitions.get(myChildType);
if (elementDef instanceof RuntimePrimitiveDatatypeDefinition || elementDef instanceof RuntimeCompositeDatatypeDefinition) {
myDatatypeChildName = "value" + elementDef.getName().substring(0, 1).toUpperCase() + elementDef.getName().substring(1);
myChildDef = elementDef;
if ("valueResourceReference".equals(myDatatypeChildName)) {
// Per one of the examples here: http://hl7.org/implement/standards/fhir/extensibility.html#extension
myDatatypeChildName = "valueResource";
List<Class<? extends IResource>> types = new ArrayList<Class<? extends IResource>>();
types.add(IResource.class);
myChildDef = new RuntimeResourceReferenceDefinition("valueResource", types);
}else {
myChildDef = elementDef;
}
} else {
RuntimeResourceBlockDefinition extDef = ((RuntimeResourceBlockDefinition) elementDef);
for (RuntimeChildDeclaredExtensionDefinition next : extDef.getExtensions()) {

View File

@ -94,7 +94,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
}
// Resource Reference
myDatatypeToAttributeName.put(ResourceReferenceDt.class, "valueReference");
myDatatypeToAttributeName.put(ResourceReferenceDt.class, "valueResource");
List<Class<? extends IResource>> types = new ArrayList<Class<? extends IResource>>();
types.add(IResource.class);
RuntimeResourceReferenceDefinition def = new RuntimeResourceReferenceDefinition("valueResource", types);

View File

@ -26,7 +26,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value= {ElementType.FIELD, ElementType.TYPE})
@Target(value= {ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
public @interface Description {
/**

View File

@ -59,6 +59,11 @@ public abstract class BaseParser implements IParser {
return parseResource(null, theMessageString);
}
@Override
public Bundle parseBundle(Reader theReader) {
return parseBundle(null, theReader);
}
@Override
public IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException {
return parseResource(null, theReader);

View File

@ -38,17 +38,19 @@ public interface IParser {
void encodeResourceToWriter(IResource theResource, Writer stringWriter) throws IOException, DataFormatException;
<T extends IResource> Bundle parseBundle(Class<T> theResourceType, Reader theReader);
Bundle parseBundle(Reader theReader);
Bundle parseBundle(String theMessageString) throws ConfigurationException, DataFormatException;
IResource parseResource(String theMessageString) throws ConfigurationException, DataFormatException;
IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException;
<T extends IResource> T parseResource(Class<T> theResourceType, Reader theReader);
<T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString);
<T extends IResource> T parseResource(Class<T> theResourceType, Reader theReader);
IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException;
IResource parseResource(String theMessageString) throws ConfigurationException, DataFormatException;
IParser setPrettyPrint(boolean thePrettyPrint);

View File

@ -56,9 +56,11 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition;
import ca.uhn.fhir.context.RuntimeChildNarrativeDefinition;
import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.BaseBundle;
import ca.uhn.fhir.model.api.Bundle;
@ -83,13 +85,66 @@ import ca.uhn.fhir.narrative.INarrativeGenerator;
public class JsonParser extends BaseParser implements IParser {
private static final Set<String> BUNDLE_TEXTNODE_CHILDREN;
static {
HashSet<String> hashSet = new HashSet<String>();
hashSet.add("title");
hashSet.add("id");
hashSet.add("updated");
hashSet.add("published");
BUNDLE_TEXTNODE_CHILDREN = Collections.unmodifiableSet(hashSet);
}
private FhirContext myContext;
private boolean myPrettyPrint;
public JsonParser(FhirContext theContext) {
myContext = theContext;
}
private void addToHeldExtensions(int valueIdx, ArrayList<ArrayList<HeldExtension>> list, RuntimeChildDeclaredExtensionDefinition theDef, IElement theValue) {
list.ensureCapacity(valueIdx);
while (list.size() <= valueIdx) {
list.add(null);
}
if (list.get(valueIdx) == null) {
list.set(valueIdx, new ArrayList<JsonParser.HeldExtension>());
}
list.get(valueIdx).add(new HeldExtension(theDef, theValue));
}
private void addToHeldExtensions(int valueIdx, List<ExtensionDt> ext, ArrayList<ArrayList<HeldExtension>> list) {
if (ext.size() > 0) {
list.ensureCapacity(valueIdx);
while (list.size() <= valueIdx) {
list.add(null);
}
if (list.get(valueIdx) == null) {
list.set(valueIdx, new ArrayList<JsonParser.HeldExtension>());
}
for (ExtensionDt next : ext) {
list.get(valueIdx).add(new HeldExtension(next));
}
}
}
private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) {
if (theResourceTypeObj.getValueType() != theValueType) {
throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType);
}
}
private JsonGenerator createJsonGenerator(Writer theWriter) {
Map<String, Object> properties = new HashMap<String, Object>(1);
if (myPrettyPrint) {
properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint);
}
JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
JsonGenerator eventWriter = jgf.createGenerator(theWriter);
return eventWriter;
}
@Override
public String encodeBundleToString(Bundle theBundle) throws DataFormatException, IOException {
if (theBundle == null) {
@ -154,324 +209,6 @@ public class JsonParser extends BaseParser implements IParser {
eventWriter.close();
}
@Override
public String encodeResourceToString(IResource theResource) throws DataFormatException, IOException {
Writer stringWriter = new StringWriter();
encodeResourceToWriter(theResource, stringWriter);
return stringWriter.toString();
}
@Override
public void encodeResourceToWriter(IResource theResource, Writer theWriter) throws IOException {
Validate.notNull(theResource, "Resource can not be null");
JsonGenerator eventWriter = createJsonGenerator(theWriter);
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null);
eventWriter.flush();
}
@Override
public Bundle parseBundle(Reader theReader) {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
String resourceType = ((JsonString) resourceTypeObj).getString();
if (!"Bundle".equals(resourceType)) {
throw new DataFormatException("Trying to parse bundle but found resourceType other than 'Bundle'. Found: '" + resourceType + "'");
}
ParserState<Bundle> state = ParserState.getPreAtomInstance(myContext, true);
state.enteringNewElement(null, "feed");
parseBundleChildren(object, state);
state.endingElement();
Bundle retVal = state.getObject();
return retVal;
}
@Override
public <T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString) {
return parseResource(theResourceType, new StringReader(theMessageString));
}
@Override
public <T extends IResource> T parseResource(Class<T> theResourceType, Reader theReader) {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
String resourceType = ((JsonString) resourceTypeObj).getString();
RuntimeResourceDefinition def;
if (theResourceType != null) {
def = myContext.getResourceDefinition(theResourceType);
} else {
def = myContext.getResourceDefinition(resourceType);
}
ParserState<? extends IResource> state = ParserState.getPreResourceInstance(def.getImplementingClass(), myContext, true);
state.enteringNewElement(null, def.getName());
parseChildren(object, state);
state.endingElement();
@SuppressWarnings("unchecked")
T retVal = (T) state.getObject();
return retVal;
}
private void parseChildren(JsonObject theObject, ParserState<?> theState) {
String elementId = null;
for (String nextName : theObject.keySet()) {
if ("resourceType".equals(nextName)) {
continue;
} else if ("id".equals(nextName)) {
elementId = theObject.getString(nextName);
continue;
} else if ("extension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, false);
continue;
} else if ("modifierExtension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, true);
continue;
} else if (nextName.charAt(0) == '_') {
continue;
}
JsonValue nextVal = theObject.get(nextName);
JsonValue alternateVal = theObject.get('_' + nextName);
parseChildren(theState, nextName, nextVal, alternateVal);
}
if (elementId != null) {
IElement object = theState.getObject();
if (object instanceof IIdentifiableElement) {
((IIdentifiableElement) object).setId(new IdDt(elementId));
}
}
}
private static final Set<String> BUNDLE_TEXTNODE_CHILDREN;
static {
HashSet<String> hashSet = new HashSet<String>();
hashSet.add("title");
hashSet.add("id");
hashSet.add("updated");
hashSet.add("published");
BUNDLE_TEXTNODE_CHILDREN = Collections.unmodifiableSet(hashSet);
}
private void parseBundleChildren(JsonObject theObject, ParserState<?> theState) {
for (String nextName : theObject.keySet()) {
if ("resourceType".equals(nextName)) {
continue;
} else if ("link".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName);
for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "link");
JsonObject linkObj = (JsonObject) jsonValue;
String rel = linkObj.getString("rel", null);
String href = linkObj.getString("href", null);
theState.attributeValue("rel", rel);
theState.attributeValue("href", href);
theState.endingElement();
}
continue;
} else if ("entry".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName);
for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "entry");
parseBundleChildren((JsonObject) jsonValue, theState);
theState.endingElement();
}
continue;
} else if (BUNDLE_TEXTNODE_CHILDREN.contains(nextName)) {
theState.enteringNewElement(null, nextName);
theState.string(theObject.getString(nextName, null));
theState.endingElement();
continue;
}
JsonValue nextVal = theObject.get(nextName);
parseChildren(theState, nextName, nextVal, null);
}
}
private void parseChildren(ParserState<?> theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal) {
switch (theJsonVal.getValueType()) {
case ARRAY: {
JsonArray nextArray = (JsonArray) theJsonVal;
JsonArray nextAlternateArray = (JsonArray) theAlternateVal;
for (int i = 0; i < nextArray.size(); i++) {
JsonValue nextObject = nextArray.get(i);
JsonValue nextAlternate = null;
if (nextAlternateArray != null) {
nextAlternate = nextAlternateArray.get(i);
}
parseChildren(theState, theName, nextObject, nextAlternate);
}
break;
}
case OBJECT: {
theState.enteringNewElement(null, theName);
parseAlternates(theAlternateVal, theState);
JsonObject nextObject = (JsonObject) theJsonVal;
boolean preResource = false;
if (theState.isPreResource()) {
String resType = nextObject.getString("resourceType");
if (isBlank(resType)) {
throw new DataFormatException("Missing 'resourceType' from resource");
}
theState.enteringNewElement(null, resType);
preResource = true;
}
parseChildren(nextObject, theState);
if (preResource) {
theState.endingElement();
}
theState.endingElement();
break;
}
case STRING: {
JsonString nextValStr = (JsonString) theJsonVal;
theState.enteringNewElement(null, theName);
theState.attributeValue("value", nextValStr.getString());
parseAlternates(theAlternateVal, theState);
theState.endingElement();
break;
}
case NUMBER:
case FALSE:
case TRUE:
theState.enteringNewElement(null, theName);
theState.attributeValue("value", theJsonVal.toString());
parseAlternates(theAlternateVal, theState);
theState.endingElement();
break;
case NULL:
break;
}
}
private void parseAlternates(JsonValue theAlternateVal, ParserState<?> theState) {
if (theAlternateVal == null || theAlternateVal.getValueType() == ValueType.NULL) {
return;
}
JsonObject alternate = (JsonObject) theAlternateVal;
for (Entry<String, JsonValue> nextEntry : alternate.entrySet()) {
String nextKey = nextEntry.getKey();
JsonValue nextVal = nextEntry.getValue();
if ("extension".equals(nextKey)) {
boolean isModifier = false;
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier);
} else if ("modifierExtension".equals(nextKey)) {
boolean isModifier = true;
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier);
} else if ("id".equals(nextKey)) {
switch (nextVal.getValueType()) {
case STRING:
theState.attributeValue("id", ((JsonString) nextVal).getString());
break;
case NULL:
break;
default:
break;
}
}
}
}
private void parseExtension(ParserState<?> theState, JsonArray array, boolean theIsModifier) {
// TODO: use theIsModifier
for (int i = 0; i < array.size(); i++) {
JsonObject nextExtObj = array.getJsonObject(i);
String url = nextExtObj.getString("url");
theState.enteringNewElementExtension(null, url, theIsModifier);
for (Iterator<String> iter = nextExtObj.keySet().iterator(); iter.hasNext();) {
String next = iter.next();
if ("url".equals(next)) {
continue;
} else if ("extension".equals(next)) {
JsonArray jsonVal = (JsonArray) nextExtObj.get(next);
parseExtension(theState, jsonVal, false);
} else if ("modifierExtension".equals(next)) {
JsonArray jsonVal = (JsonArray) nextExtObj.get(next);
parseExtension(theState, jsonVal, true);
} else {
JsonValue jsonVal = nextExtObj.get(next);
parseChildren(theState, next, jsonVal, null);
}
}
theState.endingElement();
}
}
@Override
public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
return this;
}
private void addToHeldExtensions(int valueIdx, List<ExtensionDt> ext, ArrayList<ArrayList<HeldExtension>> list) {
if (ext.size() > 0) {
list.ensureCapacity(valueIdx);
while (list.size() <= valueIdx) {
list.add(null);
}
if (list.get(valueIdx) == null) {
list.set(valueIdx, new ArrayList<JsonParser.HeldExtension>());
}
for (ExtensionDt next : ext) {
list.get(valueIdx).add(new HeldExtension(next));
}
}
}
private void addToHeldExtensions(int valueIdx, ArrayList<ArrayList<HeldExtension>> list, RuntimeChildDeclaredExtensionDefinition theDef, IElement theValue) {
list.ensureCapacity(valueIdx);
while (list.size() <= valueIdx) {
list.add(null);
}
if (list.get(valueIdx) == null) {
list.set(valueIdx, new ArrayList<JsonParser.HeldExtension>());
}
list.get(valueIdx).add(new HeldExtension(theDef, theValue));
}
private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) {
if (theResourceTypeObj.getValueType() != theValueType) {
throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType);
}
}
private JsonGenerator createJsonGenerator(Writer theWriter) {
Map<String, Object> properties = new HashMap<String, Object>(1);
if (myPrettyPrint) {
properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint);
}
JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
JsonGenerator eventWriter = jgf.createGenerator(theWriter);
return eventWriter;
}
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition<?> theChildDef,
String theChildName) throws IOException {
@ -736,6 +473,24 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeEnd();
}
@Override
public String encodeResourceToString(IResource theResource) throws DataFormatException, IOException {
Writer stringWriter = new StringWriter();
encodeResourceToWriter(theResource, stringWriter);
return stringWriter.toString();
}
@Override
public void encodeResourceToWriter(IResource theResource, Writer theWriter) throws IOException {
Validate.notNull(theResource, "Resource can not be null");
JsonGenerator eventWriter = createJsonGenerator(theWriter);
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null);
eventWriter.flush();
}
/**
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object called _name): resource extensions, and extension extensions
*/
@ -754,21 +509,20 @@ public class JsonParser extends BaseParser implements IParser {
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
}
private void writeExtensionsAsDirectChild(IResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions,
List<HeldExtension> modifierExtensions) throws IOException {
if (extensions.isEmpty() == false) {
theEventWriter.writeStartArray("extension");
for (HeldExtension next : extensions) {
next.write(resDef, theResource, theEventWriter);
private void extractDeclaredExtensions(IElement theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) {
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsNonModifier()) {
for (IElement nextValue : nextDef.getAccessor().getValues(theResource)) {
if (nextValue != null) {
extensions.add(new HeldExtension(nextDef, nextValue));
}
}
theEventWriter.writeEnd();
}
if (modifierExtensions.isEmpty() == false) {
theEventWriter.writeStartArray("modifierExtension");
for (HeldExtension next : modifierExtensions) {
next.write(resDef, theResource, theEventWriter);
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsModifier()) {
for (IElement nextValue : nextDef.getAccessor().getValues(theResource)) {
if (nextValue != null) {
modifierExtensions.add(new HeldExtension(nextDef, nextValue));
}
}
theEventWriter.writeEnd();
}
}
@ -786,23 +540,254 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void extractDeclaredExtensions(IElement theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) {
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsNonModifier()) {
for (IElement nextValue : nextDef.getAccessor().getValues(theResource)) {
if (nextValue != null) {
extensions.add(new HeldExtension(nextDef, nextValue));
private void parseAlternates(JsonValue theAlternateVal, ParserState<?> theState) {
if (theAlternateVal == null || theAlternateVal.getValueType() == ValueType.NULL) {
return;
}
JsonObject alternate = (JsonObject) theAlternateVal;
for (Entry<String, JsonValue> nextEntry : alternate.entrySet()) {
String nextKey = nextEntry.getKey();
JsonValue nextVal = nextEntry.getValue();
if ("extension".equals(nextKey)) {
boolean isModifier = false;
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier);
} else if ("modifierExtension".equals(nextKey)) {
boolean isModifier = true;
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier);
} else if ("id".equals(nextKey)) {
switch (nextVal.getValueType()) {
case STRING:
theState.attributeValue("id", ((JsonString) nextVal).getString());
break;
case NULL:
break;
default:
break;
}
}
}
for (RuntimeChildDeclaredExtensionDefinition nextDef : resDef.getExtensionsModifier()) {
for (IElement nextValue : nextDef.getAccessor().getValues(theResource)) {
if (nextValue != null) {
modifierExtensions.add(new HeldExtension(nextDef, nextValue));
}
@Override
public <T extends IResource> Bundle parseBundle(Class<T> theResourceType, Reader theReader) {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
String resourceType = ((JsonString) resourceTypeObj).getString();
if (!"Bundle".equals(resourceType)) {
throw new DataFormatException("Trying to parse bundle but found resourceType other than 'Bundle'. Found: '" + resourceType + "'");
}
ParserState<Bundle> state = ParserState.getPreAtomInstance(myContext, theResourceType, true);
state.enteringNewElement(null, "feed");
parseBundleChildren(object, state);
state.endingElement();
Bundle retVal = state.getObject();
return retVal;
}
private void parseBundleChildren(JsonObject theObject, ParserState<?> theState) {
for (String nextName : theObject.keySet()) {
if ("resourceType".equals(nextName)) {
continue;
} else if ("link".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName);
for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "link");
JsonObject linkObj = (JsonObject) jsonValue;
String rel = linkObj.getString("rel", null);
String href = linkObj.getString("href", null);
theState.attributeValue("rel", rel);
theState.attributeValue("href", href);
theState.endingElement();
}
continue;
} else if ("entry".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName);
for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "entry");
parseBundleChildren((JsonObject) jsonValue, theState);
theState.endingElement();
}
continue;
} else if (BUNDLE_TEXTNODE_CHILDREN.contains(nextName)) {
theState.enteringNewElement(null, nextName);
theState.string(theObject.getString(nextName, null));
theState.endingElement();
continue;
}
JsonValue nextVal = theObject.get(nextName);
parseChildren(theState, nextName, nextVal, null);
}
}
private void parseChildren(JsonObject theObject, ParserState<?> theState) {
String elementId = null;
for (String nextName : theObject.keySet()) {
if ("resourceType".equals(nextName)) {
continue;
} else if ("id".equals(nextName)) {
elementId = theObject.getString(nextName);
continue;
} else if ("extension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, false);
continue;
} else if ("modifierExtension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, true);
continue;
} else if (nextName.charAt(0) == '_') {
continue;
}
JsonValue nextVal = theObject.get(nextName);
JsonValue alternateVal = theObject.get('_' + nextName);
parseChildren(theState, nextName, nextVal, alternateVal);
}
if (elementId != null) {
IElement object = theState.getObject();
if (object instanceof IIdentifiableElement) {
((IIdentifiableElement) object).setId(new IdDt(elementId));
}
}
}
private void parseChildren(ParserState<?> theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal) {
switch (theJsonVal.getValueType()) {
case ARRAY: {
JsonArray nextArray = (JsonArray) theJsonVal;
JsonArray nextAlternateArray = (JsonArray) theAlternateVal;
for (int i = 0; i < nextArray.size(); i++) {
JsonValue nextObject = nextArray.get(i);
JsonValue nextAlternate = null;
if (nextAlternateArray != null) {
nextAlternate = nextAlternateArray.get(i);
}
parseChildren(theState, theName, nextObject, nextAlternate);
}
break;
}
case OBJECT: {
theState.enteringNewElement(null, theName);
parseAlternates(theAlternateVal, theState);
JsonObject nextObject = (JsonObject) theJsonVal;
boolean preResource = false;
if (theState.isPreResource()) {
String resType = nextObject.getString("resourceType");
if (isBlank(resType)) {
throw new DataFormatException("Missing 'resourceType' from resource");
}
theState.enteringNewElement(null, resType);
preResource = true;
}
parseChildren(nextObject, theState);
if (preResource) {
theState.endingElement();
}
theState.endingElement();
break;
}
case STRING: {
JsonString nextValStr = (JsonString) theJsonVal;
theState.enteringNewElement(null, theName);
theState.attributeValue("value", nextValStr.getString());
parseAlternates(theAlternateVal, theState);
theState.endingElement();
break;
}
case NUMBER:
case FALSE:
case TRUE:
theState.enteringNewElement(null, theName);
theState.attributeValue("value", theJsonVal.toString());
parseAlternates(theAlternateVal, theState);
theState.endingElement();
break;
case NULL:
break;
}
}
private void parseExtension(ParserState<?> theState, JsonArray array, boolean theIsModifier) {
// TODO: use theIsModifier
for (int i = 0; i < array.size(); i++) {
JsonObject nextExtObj = array.getJsonObject(i);
String url = nextExtObj.getString("url");
theState.enteringNewElementExtension(null, url, theIsModifier);
for (Iterator<String> iter = nextExtObj.keySet().iterator(); iter.hasNext();) {
String next = iter.next();
if ("url".equals(next)) {
continue;
} else if ("extension".equals(next)) {
JsonArray jsonVal = (JsonArray) nextExtObj.get(next);
parseExtension(theState, jsonVal, false);
} else if ("modifierExtension".equals(next)) {
JsonArray jsonVal = (JsonArray) nextExtObj.get(next);
parseExtension(theState, jsonVal, true);
} else {
JsonValue jsonVal = nextExtObj.get(next);
parseChildren(theState, next, jsonVal, null);
}
}
theState.endingElement();
}
}
@Override
public <T extends IResource> T parseResource(Class<T> theResourceType, Reader theReader) {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
String resourceType = ((JsonString) resourceTypeObj).getString();
RuntimeResourceDefinition def;
if (theResourceType != null) {
def = myContext.getResourceDefinition(theResourceType);
} else {
def = myContext.getResourceDefinition(resourceType);
}
ParserState<? extends IResource> state = ParserState.getPreResourceInstance(def.getImplementingClass(), myContext, true);
state.enteringNewElement(null, def.getName());
parseChildren(object, state);
state.endingElement();
@SuppressWarnings("unchecked")
T retVal = (T) state.getObject();
return retVal;
}
@Override
public <T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString) {
return parseResource(theResourceType, new StringReader(theMessageString));
}
@Override
public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
return this;
}
private void writeAtomLink(JsonGenerator theEventWriter, String theRel, StringDt theLink) {
if (isNotBlank(theLink.getValue())) {
theEventWriter.writeStartObject();
@ -823,6 +808,24 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void writeExtensionsAsDirectChild(IResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions,
List<HeldExtension> modifierExtensions) throws IOException {
if (extensions.isEmpty() == false) {
theEventWriter.writeStartArray("extension");
for (HeldExtension next : extensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
}
if (modifierExtensions.isEmpty() == false) {
theEventWriter.writeStartArray("modifierExtension");
for (HeldExtension next : modifierExtensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
}
}
private void writeOptionalTagWithTextNode(JsonGenerator theEventWriter, String theElementName, IPrimitiveDatatype<?> theInstantDt) {
String str = theInstantDt.getValueAsString();
if (StringUtils.isNotBlank(str)) {
@ -830,14 +833,6 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
if (StringUtils.isNotBlank(theStringDt.getValue())) {
theEventWriter.write(theElementName, theStringDt.getValue());
} else {
theEventWriter.writeNull(theElementName);
}
}
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, IdDt theIdDt) {
if (StringUtils.isNotBlank(theIdDt.getValue())) {
theEventWriter.write(theElementName, theIdDt.getValue());
@ -846,10 +841,18 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
if (StringUtils.isNotBlank(theStringDt.getValue())) {
theEventWriter.write(theElementName, theStringDt.getValue());
} else {
theEventWriter.writeNull(theElementName);
}
}
private class HeldExtension {
private ExtensionDt myUndeclaredExtension;
private RuntimeChildDeclaredExtensionDefinition myDef;
private ExtensionDt myUndeclaredExtension;
private IElement myValue;
public HeldExtension(ExtensionDt theUndeclaredExtension) {
@ -875,7 +878,9 @@ public class JsonParser extends BaseParser implements IParser {
if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource);
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, "value" + WordUtils.capitalize(def.getName()));
// encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, "value" + WordUtils.capitalize(def.getName()));
String childName = myDef.getChildNameByDatatype(myValue.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName);
}
// theEventWriter.name(myUndeclaredExtension.get);
@ -898,9 +903,13 @@ public class JsonParser extends BaseParser implements IParser {
}
theEventWriter.writeEnd();
} else {
BaseRuntimeElementDefinition<?> def = myContext.getElementDefinition(value.getClass());
// theEventWriter.writeName("value" + def.getName());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, def, "value" + WordUtils.capitalize(def.getName()));
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(value.getClass());
if (childName == null) {
throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + value.getClass().getCanonicalName());
}
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName);
}
// theEventWriter.name(myUndeclaredExtension.get);

View File

@ -131,9 +131,9 @@ class ParserState<T extends IElement> {
myState = theState;
}
public static ParserState<Bundle> getPreAtomInstance(FhirContext theContext, boolean theJsonMode) throws DataFormatException {
public static ParserState<Bundle> getPreAtomInstance(FhirContext theContext, Class<? extends IResource> theResourceType, boolean theJsonMode) throws DataFormatException {
ParserState<Bundle> retVal = new ParserState<Bundle>(theContext, theJsonMode);
retVal.push(retVal.new PreAtomState());
retVal.push(retVal.new PreAtomState(theResourceType));
return retVal;
}
@ -209,10 +209,12 @@ class ParserState<T extends IElement> {
public class AtomEntryState extends BaseState {
private BundleEntry myEntry;
private Class<? extends IResource> myResourceType;
public AtomEntryState(Bundle theInstance) {
public AtomEntryState(Bundle theInstance, Class<? extends IResource> theResourceType) {
super(null);
myEntry = new BundleEntry();
myResourceType = theResourceType;
theInstance.getEntries().add(myEntry);
}
@ -275,7 +277,7 @@ class ParserState<T extends IElement> {
} else if ("author".equals(theLocalPart)) {
push(new AtomAuthorState(myEntry));
} else if ("content".equals(theLocalPart)) {
push(new PreResourceState(myEntry));
push(new PreResourceState(myEntry, myResourceType));
} else if ("summary".equals(theLocalPart)) {
push(new XhtmlState(getPreResourceState(), myEntry.getSummary(), false));
} else if ("category".equals(theLocalPart)) {
@ -387,10 +389,12 @@ class ParserState<T extends IElement> {
private class AtomState extends BaseState {
private Bundle myInstance;
private Class<? extends IResource> myResourceType;
public AtomState(Bundle theInstance) {
public AtomState(Bundle theInstance, Class<? extends IResource> theResourceType) {
super(null);
myInstance = theInstance;
myResourceType = theResourceType;
}
@Override
@ -401,7 +405,7 @@ class ParserState<T extends IElement> {
@Override
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
if ("entry".equals(theLocalPart) && verifyNamespace(XmlParser.ATOM_NS, theNamespaceURI)) {
push(new AtomEntryState(myInstance));
push(new AtomEntryState(myInstance, myResourceType));
} else if (theLocalPart.equals("published")) {
push(new AtomPrimitiveState(myInstance.getPublished()));
} else if (theLocalPart.equals("title")) {
@ -829,9 +833,11 @@ class ParserState<T extends IElement> {
private class PreAtomState extends BaseState {
private Bundle myInstance;
private Class<? extends IResource> myResourceType;
public PreAtomState() {
public PreAtomState(Class<? extends IResource> theResourceType) {
super(null);
myResourceType = theResourceType;
}
@Override
@ -846,7 +852,7 @@ class ParserState<T extends IElement> {
}
myInstance = new Bundle();
push(new AtomState(myInstance));
push(new AtomState(myInstance, myResourceType));
}
@ -877,9 +883,10 @@ class ParserState<T extends IElement> {
return true;
}
public PreResourceState(BundleEntry theEntry) {
public PreResourceState(BundleEntry theEntry, Class<? extends IResource> theResourceType) {
super(null);
myEntry = theEntry;
myResourceType=theResourceType;
}
/**

View File

@ -193,8 +193,9 @@ public class XmlParser extends BaseParser implements IParser {
}
}
@Override
public Bundle parseBundle(Reader theReader) {
public <T extends IResource> Bundle parseBundle(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader;
try {
streamReader = myXmlInputFactory.createXMLEventReader(theReader);
@ -204,7 +205,7 @@ public class XmlParser extends BaseParser implements IParser {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
return parseBundle(streamReader);
return parseBundle(streamReader, theResourceType);
}
@Override
@ -590,8 +591,8 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private Bundle parseBundle(XMLEventReader theStreamReader) {
ParserState<Bundle> parserState = ParserState.getPreAtomInstance(myContext, false);
private Bundle parseBundle(XMLEventReader theStreamReader, Class<? extends IResource> theResourceType) {
ParserState<Bundle> parserState = ParserState.getPreAtomInstance(myContext, theResourceType, false);
return doXmlLoop(theStreamReader, parserState);
}

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.client;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 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 java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.client;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 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 java.io.IOException;
import java.io.Reader;
import java.util.List;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.client;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 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 ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.client.exceptions;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 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 ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;

View File

@ -77,7 +77,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
private MethodReturnTypeEnum myMethodReturnType;
private String myResourceName;
private Class<? extends IResource> myResourceType;
public BaseResourceReturningMethodBinding(Class<? extends IResource> theReturnResourceType, Method theMethod, FhirContext theConetxt, Object theProvider) {
super(theMethod, theConetxt, theProvider);
@ -90,9 +90,11 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
} else if (Bundle.class.isAssignableFrom(methodReturnType)) {
myMethodReturnType = MethodReturnTypeEnum.BUNDLE;
} else {
throw new ConfigurationException("Invalid return type '" + methodReturnType.getCanonicalName() + "' on method '" + theMethod.getName() + "' on type: " + theMethod.getDeclaringClass().getCanonicalName());
throw new ConfigurationException("Invalid return type '" + methodReturnType.getCanonicalName() + "' on method '" + theMethod.getName() + "' on type: "
+ theMethod.getDeclaringClass().getCanonicalName());
}
myResourceType = theReturnResourceType;
if (theReturnResourceType != null) {
ResourceDef resourceDefAnnotation = theReturnResourceType.getAnnotation(ResourceDef.class);
if (resourceDefAnnotation == null) {
@ -119,7 +121,12 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
switch (getReturnType()) {
case BUNDLE: {
Bundle bundle = parser.parseBundle(theResponseReader);
Bundle bundle;
if (myResourceType != null) {
bundle = parser.parseBundle(myResourceType, theResponseReader);
}else {
bundle = parser.parseBundle(theResponseReader);
}
switch (getMethodReturnType()) {
case BUNDLE:
return bundle;
@ -138,7 +145,12 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
break;
}
case RESOURCE: {
IResource resource = parser.parseResource(theResponseReader);
IResource resource;
if (myResourceType != null) {
resource = parser.parseResource(myResourceType, theResponseReader);
} else {
resource = parser.parseResource(theResponseReader);
}
List<String> lmHeaders = theHeaders.get(Constants.HEADER_LAST_MODIFIED_LOWERCASE);
if (lmHeaders != null && lmHeaders.size() > 0 && StringUtils.isNotBlank(lmHeaders.get(0))) {
@ -238,7 +250,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
return (IdDt) retValObj;
}
}
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + IdDt.class.getCanonicalName());
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
+ IdDt.class.getCanonicalName());
}
private InstantDt getInstantFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
@ -254,7 +267,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
return (InstantDt) retValObj;
}
}
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + InstantDt.class.getCanonicalName());
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected "
+ InstantDt.class.getCanonicalName());
}
private IParser getNewParser(EncodingUtil theResponseEncoding, boolean thePrettyPrint, NarrativeModeEnum theNarrativeMode) {
@ -271,8 +285,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
return parser.setPrettyPrint(thePrettyPrint).setSuppressNarratives(theNarrativeMode == NarrativeModeEnum.SUPPRESS);
}
private void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, List<IResource> theResult, EncodingUtil theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, boolean theRequestIsBrowser,
NarrativeModeEnum theNarrativeMode) throws IOException {
private void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, List<IResource> theResult, EncodingUtil theResponseEncoding, String theServerBase,
String theCompleteUrl, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode) throws IOException {
assert !theServerBase.endsWith("/");
theHttpResponse.setStatus(200);
@ -317,10 +331,10 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
b.append(resId);
/*
* If this is a history operation, we add the version of the
* resource to the self link to indicate the version
* If this is a history operation, we add the version of the resource to the self link to indicate the version
*/
if (getResourceOperationType() == RestfulOperationTypeEnum.HISTORY_INSTANCE || getResourceOperationType() == RestfulOperationTypeEnum.HISTORY_TYPE || getSystemOperationType() == RestfulOperationSystemEnum.HISTORY_SYSTEM) {
if (getResourceOperationType() == RestfulOperationTypeEnum.HISTORY_INSTANCE || getResourceOperationType() == RestfulOperationTypeEnum.HISTORY_TYPE
|| getSystemOperationType() == RestfulOperationSystemEnum.HISTORY_SYSTEM) {
IdDt versionId = getIdFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.VERSION_ID);
if (versionId != null) {
b.append('/');
@ -382,7 +396,8 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding {
}
}
private void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingUtil theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode) throws IOException {
private void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingUtil theResponseEncoding, boolean thePrettyPrint,
boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode) throws IOException {
theHttpResponse.setStatus(200);
if (theRequestIsBrowser && theServer.isUseBrowserFriendlyContentTypes()) {

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.method;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 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 java.io.IOException;
import java.io.Reader;
import java.util.List;

View File

@ -130,6 +130,20 @@ class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceP
return retVal;
}
@Override
public boolean matches(Request theRequest) {
if (super.matches(theRequest)) {
if (myVersionIdParameterIndex != null) {
if (theRequest.getVersion() == null) {
return false;
}
}
return true;
} else {
return false;
}
}
@Override
protected Set<RequestType> provideAllowableRequestTypes() {
return Collections.singleton(RequestType.PUT);

View File

@ -46,6 +46,7 @@ import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.ConformanceMethodBinding;
import ca.uhn.fhir.rest.method.Request;
import ca.uhn.fhir.rest.method.SearchMethodBinding;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@ -74,6 +75,8 @@ public class RestfulServer extends HttpServlet {
private boolean myUseBrowserFriendlyContentTypes;
private ResourceBinding myNullResourceBinding = new ResourceBinding();
private boolean myStarted;
/**
* Constructor
*/
@ -222,6 +225,7 @@ public class RestfulServer extends HttpServlet {
throw new ServletException("Failed to initialize FHIR Restful server", ex);
}
myStarted = true;
ourLog.info("A FHIR has been lit on this server");
}
@ -293,7 +297,7 @@ public class RestfulServer extends HttpServlet {
* {@link IllegalStateException} if called after that.
*/
public void setServerConformanceProvider(Object theServerConformanceProvider) {
if (myFhirContext != null) {
if (myStarted) {
throw new IllegalStateException("Server is already started");
}
myServerConformanceProvider = theServerConformanceProvider;
@ -525,6 +529,18 @@ public class RestfulServer extends HttpServlet {
versionId = new IdDt(nextString);
}
if (theRequestType==RequestType.PUT && versionId==null) {
String contentLocation = theRequest.getHeader("Content-Location");
if (contentLocation!=null) {
int idx = contentLocation.indexOf("/_history/");
if (idx != -1) {
String versionIdString = contentLocation.substring(idx + "/_history/".length());
versionId = new IdDt(versionIdString);
}
}
}
// TODO: look for more tokens for version, compartments, etc...
Request r = new Request();

View File

@ -38,6 +38,7 @@ public abstract class BaseServerResponseException extends RuntimeException {
registerExceptionType(MethodNotAllowedException.STATUS_CODE, MethodNotAllowedException.class);
registerExceptionType(ResourceNotFoundException.STATUS_CODE, ResourceNotFoundException.class);
registerExceptionType(ResourceVersionNotSpecifiedException.STATUS_CODE, ResourceVersionNotSpecifiedException.class);
registerExceptionType(ResourceVersionConflictException.STATUS_CODE, ResourceVersionConflictException.class);
registerExceptionType(UnprocessableEntityException.STATUS_CODE, UnprocessableEntityException.class);
}
@ -143,5 +144,6 @@ public abstract class BaseServerResponseException extends RuntimeException {
if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) {
throw new Error("Can not register " + theType + " to status code " + theStatusCode + " because " + ourStatusCodeToExceptionType.get(theStatusCode) + " already registers that code");
}
ourStatusCodeToExceptionType.put(theStatusCode, theType);
}
}

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.server.tester;
/*
* #%L
* HAPI FHIR Library
* %%
* Copyright (C) 2014 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 java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
@ -11,8 +31,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.thymeleaf.TemplateEngine;
@ -145,7 +165,7 @@ public class PublicTesterServlet extends HttpServlet {
ctx.setVariable("requestUrl", requestUrl);
ctx.setVariable("action", action);
ctx.setVariable("resultStatus", resultStatus);
ctx.setVariable("resultBody", StringEscapeUtils.escapeHtml(resultBody));
ctx.setVariable("resultBody", StringEscapeUtils.escapeHtml4(resultBody));
ctx.setVariable("resultSyntaxHighlighterClass", resultSyntaxHighlighterClass);
myTemplateEngine.process(PUBLIC_TESTER_RESULT_HTML, ctx, theResp.getWriter());

View File

@ -25,6 +25,10 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu.composite.AddressDt;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
@ -38,6 +42,7 @@ import ca.uhn.fhir.model.dstu.resource.Specimen;
import ca.uhn.fhir.model.dstu.resource.ValueSet;
import ca.uhn.fhir.model.dstu.resource.ValueSet.Define;
import ca.uhn.fhir.model.dstu.resource.ValueSet.DefineConcept;
import ca.uhn.fhir.model.dstu.valueset.AddressUseEnum;
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.StringDt;
@ -48,8 +53,7 @@ public class JsonParserTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserTest.class);
/**
* This sample has extra elements in <searchParam> that are not actually a
* part of the spec any more..
* This sample has extra elements in <searchParam> that are not actually a part of the spec any more..
*/
@Test
public void testParseFuroreMetadataWithExtraElements() throws IOException {
@ -61,6 +65,122 @@ public class JsonParserTest {
assertEquals("_id", res.getSearchParam().get(1).getName().getValue());
}
@Test
public void testEncodeExtensionWithResourceContent() throws IOException {
IParser parser = new FhirContext().newJsonParser();
Patient patient = new Patient();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.addUndeclaredExtension(false, "urn:foo", new ResourceReferenceDt(Organization.class, "123"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueResource\":{\"resource\":\"Organization/123\"}}]"));
Patient actual = parser.parseResource(Patient.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
List<ExtensionDt> ext = actual.getUndeclaredExtensionsByUrl("urn:foo");
assertEquals(1, ext.size());
ResourceReferenceDt ref = (ResourceReferenceDt) ext.get(0).getValue();
assertEquals("Organization/123", ref.getResourceUrl());
}
@Test
public void testEncodeDeclaredExtensionWithResourceContent() throws IOException {
IParser parser = new FhirContext().newJsonParser();
MyPatientWithOneDeclaredExtension patient = new MyPatientWithOneDeclaredExtension();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.setFoo(new ResourceReferenceDt(Organization.class, "123"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueResource\":{\"resource\":\"Organization/123\"}}]"));
MyPatientWithOneDeclaredExtension actual = parser.parseResource(MyPatientWithOneDeclaredExtension.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
ResourceReferenceDt ref = actual.getFoo();
assertEquals("Organization/123", ref.getResourceUrl());
}
@Test
public void testEncodeDeclaredExtensionWithAddressContent() throws IOException {
IParser parser = new FhirContext().newJsonParser();
MyPatientWithOneDeclaredAddressExtension patient = new MyPatientWithOneDeclaredAddressExtension();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.setFoo(new AddressDt().addLine("line1"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueAddress\":{\"line\":[\"line1\"]}}]"));
MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
AddressDt ref = actual.getFoo();
assertEquals("line1", ref.getLineFirstRep().getValue());
}
@Test
public void testEncodeUndeclaredExtensionWithAddressContent() throws IOException {
IParser parser = new FhirContext().newJsonParser();
Patient patient = new Patient();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.addUndeclaredExtension(false, "urn:foo", new AddressDt().addLine("line1"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueAddress\":{\"line\":[\"line1\"]}}]"));
MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
AddressDt ref = actual.getFoo();
assertEquals("line1", ref.getLineFirstRep().getValue());
}
@ResourceDef(name = "Patient")
public static class MyPatientWithOneDeclaredExtension extends Patient {
@Child(order = 0, name = "foo")
@Extension(url = "urn:foo", definedLocally = true, isModifier = false)
private ResourceReferenceDt myFoo;
public ResourceReferenceDt getFoo() {
return myFoo;
}
public void setFoo(ResourceReferenceDt theFoo) {
myFoo = theFoo;
}
}
@ResourceDef(name = "Patient")
public static class MyPatientWithOneDeclaredAddressExtension extends Patient {
@Child(order = 0, name = "foo")
@Extension(url = "urn:foo", definedLocally = true, isModifier = false)
private AddressDt myFoo;
public AddressDt getFoo() {
return myFoo;
}
public void setFoo(AddressDt theFoo) {
myFoo = theFoo;
}
}
@Test
public void testEncodeExt() throws Exception {
@ -150,9 +270,6 @@ public class JsonParserTest {
}
@Test
public void testSimpleResourceEncodeWithCustomType() throws IOException {
@ -239,7 +356,8 @@ public class JsonParserTest {
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle);
ourLog.info(encoded);
assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id", bundle.getLinkSelf().getValue());
assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id", bundle
.getLinkSelf().getValue());
assertEquals("urn:uuid:0b754ff9-03cf-4322-a119-15019af8a3", bundle.getBundleId().getValue());
BundleEntry entry = bundle.getEntries().get(0);

View File

@ -31,6 +31,7 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.composite.AddressDt;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
@ -51,6 +52,8 @@ import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.parser.JsonParserTest.MyPatientWithOneDeclaredAddressExtension;
import ca.uhn.fhir.parser.JsonParserTest.MyPatientWithOneDeclaredExtension;
public class XmlParserTest {
@ -69,7 +72,83 @@ public class XmlParserTest {
}
@Test
public void testEncodeExtensionWithResourceContent() throws IOException {
IParser parser = new FhirContext().newXmlParser();
Patient patient = new Patient();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.addUndeclaredExtension(false, "urn:foo", new ResourceReferenceDt(Organization.class, "123"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("<extension url=\"urn:foo\"><valueResource><reference value=\"Organization/123\"/></valueResource></extension>"));
Patient actual = parser.parseResource(Patient.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
List<ExtensionDt> ext = actual.getUndeclaredExtensionsByUrl("urn:foo");
assertEquals(1, ext.size());
ResourceReferenceDt ref = (ResourceReferenceDt) ext.get(0).getValue();
assertEquals("Organization/123", ref.getResourceUrl());
}
@Test
public void testEncodeDeclaredExtensionWithResourceContent() throws IOException {
IParser parser = new FhirContext().newXmlParser();
MyPatientWithOneDeclaredExtension patient = new MyPatientWithOneDeclaredExtension();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.setFoo(new ResourceReferenceDt(Organization.class, "123"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("<extension url=\"urn:foo\"><valueResource><reference value=\"Organization/123\"/></valueResource></extension>"));
MyPatientWithOneDeclaredExtension actual = parser.parseResource(MyPatientWithOneDeclaredExtension.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
ResourceReferenceDt ref = actual.getFoo();
assertEquals("Organization/123", ref.getResourceUrl());
}
@Test
public void testEncodeDeclaredExtensionWithAddressContent() throws IOException {
IParser parser = new FhirContext().newXmlParser();
MyPatientWithOneDeclaredAddressExtension patient = new MyPatientWithOneDeclaredAddressExtension();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.setFoo(new AddressDt().addLine("line1"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("<extension url=\"urn:foo\"><valueAddress><line value=\"line1\"/></valueAddress></extension>"));
MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
AddressDt ref = actual.getFoo();
assertEquals("line1", ref.getLineFirstRep().getValue());
}
@Test
public void testEncodeUndeclaredExtensionWithAddressContent() throws IOException {
IParser parser = new FhirContext().newXmlParser();
Patient patient = new Patient();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.addUndeclaredExtension(false, "urn:foo", new AddressDt().addLine("line1"));
String val = parser.encodeResourceToString(patient);
ourLog.info(val);
assertThat(val, StringContains.containsString("<extension url=\"urn:foo\"><valueAddress><line value=\"line1\"/></valueAddress></extension>"));
MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val);
assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum());
AddressDt ref = actual.getFoo();
assertEquals("line1", ref.getLineFirstRep().getValue());
}
@Test
public void testEncodeBundleResultCount() throws IOException {

View File

@ -36,6 +36,7 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.PathSpecification;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu.composite.CodingDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Conformance;
@ -46,7 +47,12 @@ 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.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.param.CodingListParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.QualifiedDateParam;
@ -131,7 +137,7 @@ public class ClientTest {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 400, "OK"));
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 400, "foobar"));
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("foobar"), Charset.forName("UTF-8")));
@ -481,6 +487,62 @@ public class ClientTest {
}
@Test
public void testSearchWithCustomType() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
ITestClientWithCustomType client = ctx.newRestfulClient(ITestClientWithCustomType.class, "http://foo");
CustomPatient response = client.getPatientByDob(new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString());
assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue());
}
public interface ITestClientWithCustomType extends IBasicClient {
@Search()
public CustomPatient getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) QualifiedDateParam theBirthDate);
}
@Test
public void testSearchWithCustomTypeList() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
ITestClientWithCustomTypeList client = ctx.newRestfulClient(ITestClientWithCustomTypeList.class, "http://foo");
List<CustomPatient> response = client.getPatientByDob(new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString());
assertEquals("PRP1660", response.get(0).getIdentifier().get(0).getValue().getValue());
}
public interface ITestClientWithCustomTypeList extends IBasicClient {
@Search()
public List<CustomPatient> getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) QualifiedDateParam theBirthDate);
}
@ResourceDef(name="Patient")
public static class CustomPatient extends Patient
{
// nothing
}
@Test
public void testSearchByToken() throws Exception {

View File

@ -0,0 +1,26 @@
package ca.uhn.fhir.rest.client;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.client.ClientTest.CustomPatient;
import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.param.QualifiedDateParam;
public class InvalidClientDefinitionTest {
@Test
public void testAnnotationTypeIsNotAssignableToMethodReturnType() {
// TODO: this should fail
new FhirContext().newRestfulClient(ITestClientWithCustomType.class, "http://example.com");
}
public interface ITestClientWithCustomType extends IBasicClient {
@Search(type=Patient.class)
public CustomPatient getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) QualifiedDateParam theBirthDate);
}
}

View File

@ -0,0 +1,52 @@
package ca.uhn.fhir.rest.server;
import java.io.IOException;
import javax.servlet.ServletException;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider;
public class DocumentationTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DocumentationTest.class);
@Test
public void testSearchParameterDocumentation() throws Exception {
RestfulServer rs = new RestfulServer();
rs.setProviders(new SearchProvider());
ServerConformanceProvider sc = new ServerConformanceProvider(rs);
rs.setServerConformanceProvider(sc);
rs.init(null);
Conformance conformance = sc.getServerConformance();
String conf = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
}
/**
* Created by dsotnikov on 2/25/2014.
*/
public static class SearchProvider {
@Search(type = Patient.class)
public Patient findPatient(@Description(shortDefinition = "The patient's identifier (MRN or other card number)") @RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
return null;
}
}
}

View File

@ -1,8 +1,6 @@
package ca.uhn.fhir.rest.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.io.StringReader;
import java.util.ArrayList;
@ -49,6 +47,7 @@ import ca.uhn.fhir.model.dstu.composite.CodingDt;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.DiagnosticOrder;
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu.resource.Patient;
@ -860,11 +859,10 @@ public class ResfulServerMethodTest {
}
@Test
public void testUpdateWrongResourceType() throws Exception {
// TODO: this method sends in the wrong resource type vs. the URL so it should
// give a useful error message
// give a useful error message (and then make this unit test actually run)
Patient patient = new Patient();
patient.addIdentifier().setValue("002");
@ -902,16 +900,17 @@ public class ResfulServerMethodTest {
patient.getIdentifier().setValue("001");
HttpPut httpPut = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
httpPut.addHeader("Content-Location", "/DiagnosticReport/001/_history/002");
httpPut.addHeader("Content-Location", "/DiagnosticReport/001/_history/004");
httpPut.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
HttpResponse status = ourClient.execute(httpPut);
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
// String responseContent = IOUtils.toString(status.getEntity().getContent());
// ourLog.info("Response was:\n{}", responseContent);
assertEquals(201, status.getStatusLine().getStatusCode());
assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002", status.getFirstHeader("Location").getValue());
assertEquals(204, status.getStatusLine().getStatusCode());
assertNull(status.getEntity());
assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/004", status.getFirstHeader("Location").getValue());
}
@ -977,11 +976,12 @@ public class ResfulServerMethodTest {
status = ourClient.execute(httpPost);
responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
// responseContent = IOUtils.toString(status.getEntity().getContent());
// ourLog.info("Response was:\n{}", responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("", responseContent);
assertEquals(204, status.getStatusLine().getStatusCode());
assertNull(status.getEntity());
// assertEquals("", responseContent);
}
@ -1043,6 +1043,14 @@ public class ResfulServerMethodTest {
return DiagnosticReport.class;
}
@SuppressWarnings("unused")
@Update()
public MethodOutcome updateDiagnosticReportWithNoResponse(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @ResourceParam DiagnosticReport thePatient) {
IdDt id = theId;
IdDt version = theVersionId;
return new MethodOutcome(id, version);
}
@SuppressWarnings("unused")
@Update()
public MethodOutcome updateDiagnosticReportWithVersionAndNoResponse(@IdParam IdDt theId, @ResourceParam DiagnosticReport thePatient) {
@ -1281,10 +1289,10 @@ public class ResfulServerMethodTest {
@SuppressWarnings("unused")
@Update()
public MethodOutcome updateDiagnosticReportWithVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @ResourceParam DiagnosticReport thePatient) {
public MethodOutcome updateDiagnosticReportWithVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @ResourceParam DiagnosticOrder thePatient) {
/*
* TODO: THIS METHOD IS NOT USED. It's the wrong type
* (DiagnosticReport), so it should cause an exception on startup.
* (DiagnosticOrder), so it should cause an exception on startup.
* Also we should detect if there are multiple resource params on an
* update/create/etc method
*/

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.rest.server;
import java.lang.annotation.Documented;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -16,8 +17,10 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
@ -75,7 +78,7 @@ public class TesterTest {
@Test
public void testTester() throws Exception {
// if (true) return;
if (true) return;
myRestfulServer.setProviders(new SearchProvider(), new GlobalHistoryProvider());
myServer.start();
@ -111,7 +114,10 @@ public class TesterTest {
}
@Search(type = Patient.class)
public Patient findPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) {
public Patient findPatient(
@Description(shortDefinition="The patient's identifier (MRN or other card number)")
@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier
) {
for (Patient next : getIdToPatient().values()) {
for (IdentifierDt nextId : next.getIdentifier()) {
if (nextId.matchesSystemAndValue(theIdentifier)) {