Skip to content

Commit

Permalink
Fix #233 - elementQuantity gets incorrectly encoded as elementDuration
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesagnew committed Sep 29, 2015
1 parent 04764ed commit f9e4a3e
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 40 deletions.
7 changes: 6 additions & 1 deletion .project
Expand Up @@ -11,8 +11,13 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.m2e.core.maven2Builder.launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
Expand Down
14 changes: 12 additions & 2 deletions hapi-fhir-base/.project
Expand Up @@ -16,13 +16,23 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.wst.validation.validationbuilder.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.m2e.core.maven2Builder (1).launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
Expand Down
Expand Up @@ -27,7 +27,7 @@ public interface IRuntimeDatatypeDefinition {

boolean isSpecialization();

public BaseRuntimeElementDefinition<?> getProfileOf();
public Class<? extends IBaseDatatype> getProfileOf();

boolean isProfileOf(Class<? extends IBaseDatatype> theType);

Expand Down
Expand Up @@ -30,6 +30,8 @@

import org.apache.commons.lang3.StringUtils;
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 ca.uhn.fhir.model.api.annotation.Child;
Expand All @@ -41,6 +43,7 @@ public class RuntimeChildChoiceDefinition extends BaseRuntimeDeclaredChildDefini
private Map<String, BaseRuntimeElementDefinition<?>> myNameToChildDefinition;
private Map<Class<? extends IBase>, String> myDatatypeToElementName;
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) {
super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName);
Expand Down Expand Up @@ -82,9 +85,15 @@ void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseR
myDatatypeToElementName = new HashMap<Class<? extends IBase>, String>();
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) {

String elementName;
String elementName = null;
BaseRuntimeElementDefinition<?> nextDef;
boolean nonPreferred = false;
if (IBaseResource.class.isAssignableFrom(next)) {
Expand All @@ -109,32 +118,43 @@ void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseR
* element fooString when encoded, because markdown is a profile of string. This is according to the
* FHIR spec
*/
nextDefForChoice = nextDefDatatype.getProfileOf();
nextDefForChoice = null;
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);
// 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 (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);
/*
* 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);
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);
Expand All @@ -145,7 +165,8 @@ void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseR

@Override
public String getChildNameByDatatype(Class<? extends IBase> theDatatype) {
return myDatatypeToElementName.get(theDatatype);
String retVal = myDatatypeToElementName.get(theDatatype);
return retVal;
}

@Override
Expand Down
Expand Up @@ -65,8 +65,8 @@ public void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>
}

@Override
public BaseRuntimeElementDefinition<?> getProfileOf() {
return myProfileOf;
public Class<? extends IBaseDatatype> getProfileOf() {
return myProfileOfType;
}

@Override
Expand Down
Expand Up @@ -58,8 +58,8 @@ public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildTy
}

@Override
public BaseRuntimeElementDefinition<?> getProfileOf() {
return myProfileOf;
public Class<? extends IBaseDatatype> getProfileOf() {
return myProfileOfType;
}

@Override
Expand Down
14 changes: 12 additions & 2 deletions hapi-fhir-jpaserver-base/.project
Expand Up @@ -17,13 +17,23 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.wst.validation.validationbuilder (1).launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.m2e.core.maven2Builder (2).launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
Expand Down
Expand Up @@ -119,11 +119,11 @@ public void run() {
}
}

private class SimpleBoundState implements IState {
private class BoundStaticSubscipriptionState implements IState {

private WebSocketSession mySession;

public SimpleBoundState(WebSocketSession theSession) {
public BoundStaticSubscipriptionState(WebSocketSession theSession) {
mySession = theSession;
}

Expand Down Expand Up @@ -157,12 +157,12 @@ public void closing() {
@Autowired
private FhirContext myCtx;

private class ResourceBoundState implements IState {
private class BoundDynamicSubscriptionState implements IState {

private WebSocketSession mySession;
private EncodingEnum myEncoding;

public ResourceBoundState(WebSocketSession theSession, EncodingEnum theEncoding) {
public BoundDynamicSubscriptionState(WebSocketSession theSession, EncodingEnum theEncoding) {
mySession = theSession;
myEncoding = theEncoding;
}
Expand Down Expand Up @@ -241,12 +241,12 @@ private IIdType bingSearch(WebSocketSession theSession, String theRemaining) {
subscription.setCriteria(theRemaining);

try {
String params = theRemaining.substring(theRemaining.indexOf('?'));
List<NameValuePair> paramValues = URLEncodedUtils.parse("http://example.com" + params, Constants.CHARSET_UTF8);
String params = theRemaining.substring(theRemaining.indexOf('?')+1);
List<NameValuePair> paramValues = URLEncodedUtils.parse(params, Constants.CHARSET_UTF8, '&');
EncodingEnum encoding = EncodingEnum.JSON;
for (NameValuePair nameValuePair : paramValues) {
if (Constants.PARAM_FORMAT.equals(nameValuePair)) {
EncodingEnum nextEncoding = EncodingEnum.forContentType(nameValuePair.getValue());
if (Constants.PARAM_FORMAT.equals(nameValuePair.getName())) {
EncodingEnum nextEncoding = Constants.FORMAT_VAL_TO_ENCODING.get(nameValuePair.getValue());
if (nextEncoding != null) {
encoding = nextEncoding;
}
Expand All @@ -257,7 +257,7 @@ private IIdType bingSearch(WebSocketSession theSession, String theRemaining) {

mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement();
myState = new ResourceBoundState(theSession, encoding);
myState = new BoundDynamicSubscriptionState(theSession, encoding);

return id;
} catch (UnprocessableEntityException e) {
Expand Down Expand Up @@ -298,7 +298,7 @@ private IIdType bindSimple(WebSocketSession theSession, String theBindString) {
Subscription subscription = mySubscriptionDao.read(id);
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
mySubscriptionId = subscription.getIdElement();
myState = new SimpleBoundState(theSession);
myState = new BoundStaticSubscipriptionState(theSession);
} catch (ResourceNotFoundException e) {
try {
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - Unknown subscription: " + id.getValue()));
Expand Down
Expand Up @@ -1919,6 +1919,10 @@ public void testReverseIncludes() {

@Test()
public void testSortByComposite() {
Observation o = new Observation();
o.getCode().setText("testSortByComposite");
myObservationDao.create(o);

SearchParameterMap pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_CODE_VALUE_CONCEPT));
try {
Expand Down
Expand Up @@ -1293,6 +1293,9 @@ public void testSearchWithInclude() throws Exception {

@Test(expected = InvalidRequestException.class)
public void testSearchWithInvalidSort() throws Exception {
Observation o = new Observation();
o.getCode().setText("testSearchWithInvalidSort");
myObservationDao.create(o);
//@formatter:off
Bundle found = ourClient
.search()
Expand Down
Expand Up @@ -176,7 +176,7 @@ public void testSubscriptionDynamic() throws Exception {
WebSocketClient client = new WebSocketClient();
try {
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());
ourLog.info("Connecting to : {}", echoUri);

Expand Down Expand Up @@ -241,7 +241,7 @@ public void testSubscriptionDynamicXml() throws Exception {
WebSocketClient client = new WebSocketClient();
try {
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());
ourLog.info("Connecting to : {}", echoUri);

Expand Down
6 changes: 6 additions & 0 deletions src/changes/changes.xml
Expand Up @@ -95,6 +95,12 @@
JPA server Patient/[id]/$everything operation now supports
_lastUpdated filtering and _sort'ing of results.
</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 version="1.2" date="2015-09-18">
<action type="add">
Expand Down

0 comments on commit f9e4a3e

Please sign in to comment.