Fix #233 - elementQuantity gets incorrectly encoded as elementDuration

This commit is contained in:
jamesagnew 2015-09-29 19:41:31 -04:00
parent 04764ed07e
commit f9e4a3e1b5
12 changed files with 102 additions and 43 deletions

View File

@ -11,8 +11,13 @@
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name> <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments> <arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.m2e.core.maven2Builder.launch</value>
</dictionary>
</arguments> </arguments>
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>

View File

@ -16,13 +16,23 @@
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name> <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments> <arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.wst.validation.validationbuilder.launch</value>
</dictionary>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name> <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments> <arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.m2e.core.maven2Builder (1).launch</value>
</dictionary>
</arguments> </arguments>
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>

View File

@ -27,7 +27,7 @@ public interface IRuntimeDatatypeDefinition {
boolean isSpecialization(); boolean isSpecialization();
public BaseRuntimeElementDefinition<?> getProfileOf(); public Class<? extends IBaseDatatype> getProfileOf();
boolean isProfileOf(Class<? extends IBaseDatatype> theType); boolean isProfileOf(Class<? extends IBaseDatatype> theType);

View File

@ -30,6 +30,8 @@ import java.util.Set;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Child;
@ -41,6 +43,7 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini
private Map<String, BaseRuntimeElementDefinition<?>> myNameToChildDefinition; private Map<String, BaseRuntimeElementDefinition<?>> myNameToChildDefinition;
private Map<Class<? extends IBase>, String> myDatatypeToElementName; private Map<Class<? extends IBase>, String> myDatatypeToElementName;
private Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myDatatypeToElementDefinition; private Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myDatatypeToElementDefinition;
private String myReferenceSuffix;
public RuntimeChildChoiceDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, List<Class<? extends IBase>> theChoiceTypes) { public RuntimeChildChoiceDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, List<Class<? extends IBase>> theChoiceTypes) {
super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName); super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName);
@ -82,9 +85,15 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini
myDatatypeToElementName = new HashMap<Class<? extends IBase>, String>(); myDatatypeToElementName = new HashMap<Class<? extends IBase>, String>();
myDatatypeToElementDefinition = new HashMap<Class<? extends IBase>, BaseRuntimeElementDefinition<?>>(); myDatatypeToElementDefinition = new HashMap<Class<? extends IBase>, BaseRuntimeElementDefinition<?>>();
if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
myReferenceSuffix = "Resource";
} else {
myReferenceSuffix = "Reference";
}
for (Class<? extends IBase> next : myChoiceTypes) { for (Class<? extends IBase> next : myChoiceTypes) {
String elementName; String elementName = null;
BaseRuntimeElementDefinition<?> nextDef; BaseRuntimeElementDefinition<?> nextDef;
boolean nonPreferred = false; boolean nonPreferred = false;
if (IBaseResource.class.isAssignableFrom(next)) { if (IBaseResource.class.isAssignableFrom(next)) {
@ -109,32 +118,43 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini
* element fooString when encoded, because markdown is a profile of string. This is according to the * element fooString when encoded, because markdown is a profile of string. This is according to the
* FHIR spec * FHIR spec
*/ */
nextDefForChoice = nextDefDatatype.getProfileOf(); nextDefForChoice = null;
nonPreferred = true; nonPreferred = true;
Class<? extends IBaseDatatype> profileType = nextDefDatatype.getProfileOf();
BaseRuntimeElementDefinition<?> elementDef = theClassToElementDefinitions.get(profileType);
elementName = getElementName() + StringUtils.capitalize(elementDef.getName());
} }
} }
elementName = getElementName() + StringUtils.capitalize(nextDefForChoice.getName()); if (nextDefForChoice != null) {
} elementName = getElementName() + StringUtils.capitalize(nextDefForChoice.getName());
if (myNameToChildDefinition.containsKey(elementName) == false || !nonPreferred) {
myNameToChildDefinition.put(elementName, nextDef);
}
if (IBaseResource.class.isAssignableFrom(next)) {
Class<? extends IBase> refType = theContext.getVersion().getResourceReferenceType();
myDatatypeToElementDefinition.put(refType, nextDef);
String alternateElementName;
if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
alternateElementName = getElementName() + "Resource";
} else {
alternateElementName = getElementName() + "Reference";
} }
myDatatypeToElementName.put(refType, alternateElementName); }
// I don't see how elementName could be null here, but eclipse complains..
if (elementName != null) {
if (myNameToChildDefinition.containsKey(elementName) == false || !nonPreferred) {
myNameToChildDefinition.put(elementName, nextDef);
}
}
/*
* If this is a resource reference, the element name is "fooNameReference"
*/
if (IBaseResource.class.isAssignableFrom(next) || IBaseReference.class.isAssignableFrom(next)) {
next = theContext.getVersion().getResourceReferenceType();
elementName = getElementName() + myReferenceSuffix;
} }
myDatatypeToElementDefinition.put(next, nextDef); myDatatypeToElementDefinition.put(next, nextDef);
myDatatypeToElementName.put(next, elementName);
if (myDatatypeToElementName.containsKey(next)) {
String existing = myDatatypeToElementName.get(next);
if (!existing.equals(elementName)) {
throw new ConfigurationException("Already have element name " + existing + " for datatype " + next.getClass().getSimpleName() + " in " + getElementName() + ", cannot add " + elementName);
}
} else {
myDatatypeToElementName.put(next, elementName);
}
} }
myNameToChildDefinition = Collections.unmodifiableMap(myNameToChildDefinition); myNameToChildDefinition = Collections.unmodifiableMap(myNameToChildDefinition);
@ -145,7 +165,8 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini
@Override @Override
public String getChildNameByDatatype(Class<? extends IBase> theDatatype) { public String getChildNameByDatatype(Class<? extends IBase> theDatatype) {
return myDatatypeToElementName.get(theDatatype); String retVal = myDatatypeToElementName.get(theDatatype);
return retVal;
} }
@Override @Override

View File

@ -65,8 +65,8 @@ public class RuntimeCompositeDatatypeDefinition extends BaseRuntimeElementCompos
} }
@Override @Override
public BaseRuntimeElementDefinition<?> getProfileOf() { public Class<? extends IBaseDatatype> getProfileOf() {
return myProfileOf; return myProfileOfType;
} }
@Override @Override

View File

@ -58,8 +58,8 @@ public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefini
} }
@Override @Override
public BaseRuntimeElementDefinition<?> getProfileOf() { public Class<? extends IBaseDatatype> getProfileOf() {
return myProfileOf; return myProfileOfType;
} }
@Override @Override

View File

@ -17,13 +17,23 @@
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name> <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments> <arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.wst.validation.validationbuilder (1).launch</value>
</dictionary>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name> <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments> <arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.m2e.core.maven2Builder (2).launch</value>
</dictionary>
</arguments> </arguments>
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>

View File

@ -119,11 +119,11 @@ public class SubscriptionWebsocketHandler extends TextWebSocketHandler implement
} }
} }
private class SimpleBoundState implements IState { private class BoundStaticSubscipriptionState implements IState {
private WebSocketSession mySession; private WebSocketSession mySession;
public SimpleBoundState(WebSocketSession theSession) { public BoundStaticSubscipriptionState(WebSocketSession theSession) {
mySession = theSession; mySession = theSession;
} }
@ -157,12 +157,12 @@ public class SubscriptionWebsocketHandler extends TextWebSocketHandler implement
@Autowired @Autowired
private FhirContext myCtx; private FhirContext myCtx;
private class ResourceBoundState implements IState { private class BoundDynamicSubscriptionState implements IState {
private WebSocketSession mySession; private WebSocketSession mySession;
private EncodingEnum myEncoding; private EncodingEnum myEncoding;
public ResourceBoundState(WebSocketSession theSession, EncodingEnum theEncoding) { public BoundDynamicSubscriptionState(WebSocketSession theSession, EncodingEnum theEncoding) {
mySession = theSession; mySession = theSession;
myEncoding = theEncoding; myEncoding = theEncoding;
} }
@ -241,12 +241,12 @@ public class SubscriptionWebsocketHandler extends TextWebSocketHandler implement
subscription.setCriteria(theRemaining); subscription.setCriteria(theRemaining);
try { try {
String params = theRemaining.substring(theRemaining.indexOf('?')); String params = theRemaining.substring(theRemaining.indexOf('?')+1);
List<NameValuePair> paramValues = URLEncodedUtils.parse("http://example.com" + params, Constants.CHARSET_UTF8); List<NameValuePair> paramValues = URLEncodedUtils.parse(params, Constants.CHARSET_UTF8, '&');
EncodingEnum encoding = EncodingEnum.JSON; EncodingEnum encoding = EncodingEnum.JSON;
for (NameValuePair nameValuePair : paramValues) { for (NameValuePair nameValuePair : paramValues) {
if (Constants.PARAM_FORMAT.equals(nameValuePair)) { if (Constants.PARAM_FORMAT.equals(nameValuePair.getName())) {
EncodingEnum nextEncoding = EncodingEnum.forContentType(nameValuePair.getValue()); EncodingEnum nextEncoding = Constants.FORMAT_VAL_TO_ENCODING.get(nameValuePair.getValue());
if (nextEncoding != null) { if (nextEncoding != null) {
encoding = nextEncoding; encoding = nextEncoding;
} }
@ -257,7 +257,7 @@ public class SubscriptionWebsocketHandler extends TextWebSocketHandler implement
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id); mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement(); mySubscriptionId = subscription.getIdElement();
myState = new ResourceBoundState(theSession, encoding); myState = new BoundDynamicSubscriptionState(theSession, encoding);
return id; return id;
} catch (UnprocessableEntityException e) { } catch (UnprocessableEntityException e) {
@ -298,7 +298,7 @@ public class SubscriptionWebsocketHandler extends TextWebSocketHandler implement
Subscription subscription = mySubscriptionDao.read(id); Subscription subscription = mySubscriptionDao.read(id);
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id); mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement(); mySubscriptionId = subscription.getIdElement();
myState = new SimpleBoundState(theSession); myState = new BoundStaticSubscipriptionState(theSession);
} catch (ResourceNotFoundException e) { } catch (ResourceNotFoundException e) {
try { try {
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - Unknown subscription: " + id.getValue())); theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - Unknown subscription: " + id.getValue()));

View File

@ -1919,6 +1919,10 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
@Test() @Test()
public void testSortByComposite() { public void testSortByComposite() {
Observation o = new Observation();
o.getCode().setText("testSortByComposite");
myObservationDao.create(o);
SearchParameterMap pm = new SearchParameterMap(); SearchParameterMap pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_CODE_VALUE_CONCEPT)); pm.setSort(new SortSpec(Observation.SP_CODE_VALUE_CONCEPT));
try { try {

View File

@ -1293,6 +1293,9 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
@Test(expected = InvalidRequestException.class) @Test(expected = InvalidRequestException.class)
public void testSearchWithInvalidSort() throws Exception { public void testSearchWithInvalidSort() throws Exception {
Observation o = new Observation();
o.getCode().setText("testSearchWithInvalidSort");
myObservationDao.create(o);
//@formatter:off //@formatter:off
Bundle found = ourClient Bundle found = ourClient
.search() .search()

View File

@ -176,7 +176,7 @@ public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {
WebSocketClient client = new WebSocketClient(); WebSocketClient client = new WebSocketClient();
try { try {
client.start(); client.start();
URI echoUri = new URI("ws://localhost:" + ourPort + "/baseDstu2/websocket"); URI echoUri = new URI("ws://localhost:" + ourPort + "/websocket/dstu2");
client.connect(socket, echoUri, new ClientUpgradeRequest()); client.connect(socket, echoUri, new ClientUpgradeRequest());
ourLog.info("Connecting to : {}", echoUri); ourLog.info("Connecting to : {}", echoUri);
@ -241,7 +241,7 @@ public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {
WebSocketClient client = new WebSocketClient(); WebSocketClient client = new WebSocketClient();
try { try {
client.start(); client.start();
URI echoUri = new URI("ws://localhost:" + ourPort + "/baseDstu2/websocket"); URI echoUri = new URI("ws://localhost:" + ourPort + "/websocket/dstu2");
client.connect(socket, echoUri, new ClientUpgradeRequest()); client.connect(socket, echoUri, new ClientUpgradeRequest());
ourLog.info("Connecting to : {}", echoUri); ourLog.info("Connecting to : {}", echoUri);

View File

@ -95,6 +95,12 @@
JPA server Patient/[id]/$everything operation now supports JPA server Patient/[id]/$everything operation now supports
_lastUpdated filtering and _sort'ing of results. _lastUpdated filtering and _sort'ing of results.
</action> </action>
<action type="fix" issue="233">
Fix parser issue where profiled choice element datatypes (e.g. value[x] where one allowable
type is Duration, which is a profile of Quantity) get incorrectly encoded using the
profiled datatype name instead of the base datatype name as required by the FHIR
spec. Thanks to Nehashri Puttu Lokesh for reporting!
</action>
</release> </release>
<release version="1.2" date="2015-09-18"> <release version="1.2" date="2015-09-18">
<action type="add"> <action type="add">